我需要一种工作方法来获取从 Python 中的基类继承的所有类。
新式类(即从 子类化object,这是 Python 3 中的默认设置)有一个__subclasses__返回子类的方法:
object
__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列为它们的基础:
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'. 用于importlib加载类的模块,然后检索相应的属性:
'pkg.module.Foo'
'Foo'
importlib
import importlib modname, _, clsname = name.rpartition('.') mod = importlib.import_module(modname) cls = getattr(mod, clsname)
无论您如何找到该类,cls.__subclasses__()都会返回其子类的列表。
cls.__subclasses__()