17

在 Python 中,给定一个模块 X 和一个类 Y,我如何迭代或生成模块 X 中存在的所有 Y 子类的列表?

4

4 回答 4

21

尽管 Quamrana 的建议效果很好,但我想建议一些可能的改进,使其更加 Pythonic。他们依赖于使用标准库中的检查模块。

  1. 您可以通过使用避免 getattr 调用inspect.getmembers()
  2. 可以通过使用来避免 try/catchinspect.isclass()

有了这些,如果你愿意,你可以将整个事情简化为一个列表理解:

def find_subclasses(module, clazz):
    return [
        cls
            for name, cls in inspect.getmembers(module)
                if inspect.isclass(cls) and issubclass(cls, clazz)
    ]
于 2009-01-03T01:56:21.720 回答
12

这是一种方法:

import inspect

def get_subclasses(mod, cls):
    """Yield the classes in module ``mod`` that inherit from ``cls``"""
    for name, obj in inspect.getmembers(mod):
        if hasattr(obj, "__bases__") and cls in obj.__bases__:
            yield obj
于 2008-09-04T18:20:21.087 回答
4

我可以建议 Chris AtLee 和 zacherates 的答案都不符合要求吗?我认为对 zacerates 答案的这种修改更好:

def find_subclasses(module, clazz):
    for name in dir(module):
        o = getattr(module, name)
        try:
            if (o != clazz) and issubclass(o, clazz):
                yield name, o
        except TypeError: pass

我不同意给定答案的原因是第一个不会产生作为给定类的遥远子类的类,而第二个包含给定类。

于 2008-09-05T22:54:42.557 回答
1

给定模块 foo.py

class foo(object): pass
class bar(foo): pass
class baz(foo): pass

class grar(Exception): pass

def find_subclasses(module, clazz):
    for name in dir(module):
        o = getattr(module, name)

        try: 
             if issubclass(o, clazz):
             yield name, o
        except TypeError: pass

>>> import foo
>>> list(foo.find_subclasses(foo, foo.foo))
[('bar', <class 'foo.bar'>), ('baz', <class 'foo.baz'>), ('foo', <class 'foo.foo'>)]
>>> list(foo.find_subclasses(foo, object))
[('bar', <class 'foo.bar'>), ('baz', <class 'foo.baz'>), ('foo', <class 'foo.foo'>), ('grar', <class 'foo.grar'>)]
>>> list(foo.find_subclasses(foo, Exception))
[('grar', <class 'foo.grar'>)]
于 2008-09-04T18:29:59.847 回答