小编典典

如何找到给定名称的类的所有子类?

all

我需要一种工作方法来获取从 Python 中的基类继承的所有类。


阅读 83

收藏
2022-04-29

共1个答案

小编典典

新式类(即从 子类化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'.
用于importlib加载类的模块,然后检索相应的属性:

import importlib
modname, _, clsname = name.rpartition('.')
mod = importlib.import_module(modname)
cls = getattr(mod, clsname)

无论您如何找到该类,cls.__subclasses__()都会返回其子类的列表。

2022-04-29