新式类(即从object
,这是 Python 3 中的默认设置)__subclasses__
返回子类的方法:
class Foo(object): pass
class Bar(Foo): pass
class Baz(Foo): pass
class Bing(Bar): pass
以下是子类的名称:
print([cls.__name__ for cls in Foo.__subclasses__()])
# ['Bar', 'Baz']
以下是子类本身:
print(Foo.__subclasses__())
# [<class '__main__.Bar'>, <class '__main__.Baz'>]
确认子类确实列出Foo
作为他们的基础:
for cls in Foo.__subclasses__():
print(cls.__base__)
# <class '__main__.Foo'>
# <class '__main__.Foo'>
请注意,如果您想要子子类,则必须递归:
def all_subclasses(cls):
return set(cls.__subclasses__()).union(
[s for c in cls.__subclasses__() for s in all_subclasses(c)])
print(all_subclasses(Foo))
# {<class '__main__.Bar'>, <class '__main__.Baz'>, <class '__main__.Bing'>}
请注意,如果子类的类定义尚未执行 - 例如,如果子类的模块尚未导入 - 则该子类尚不存在,并且__subclasses__
不会找到它。
你提到“给它的名字”。由于 Python 类是第一类对象,因此您不需要使用带有类名的字符串来代替类或类似的内容。您可以直接使用该类,而且您可能应该这样做。
如果您确实有一个表示类名称的字符串,并且想要查找该类的子类,则有两个步骤:根据给定的名称查找该类,然后使用__subclasses__
如上。
如何从名称找到类取决于您期望在哪里找到它。如果您希望在与尝试查找该类的代码相同的模块中找到它,那么
cls = globals()[name]
会完成这项工作,或者在不太可能的情况下,你希望在当地人中找到它,
cls = locals()[name]
如果该类可以位于任何模块中,那么您的名称字符串应包含完全限定的名称 - 类似'pkg.module.Foo'
而不是仅仅'Foo'
. Use importlib
加载类的模块,然后检索相应的属性:
import importlib
modname, _, clsname = name.rpartition('.')
mod = importlib.import_module(modname)
cls = getattr(mod, clsname)
不管你发现什么班级,cls.__subclasses__()
然后将返回其子类的列表。