【问题标题】:Iterate over subclasses of a given class in a given module迭代给定模块中给定类的子类
【发布时间】:2008-09-04 18:05:23
【问题描述】:

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

【问题讨论】:

    标签: python oop


    【解决方案1】:

    尽管 Quamrana 的建议效果很好,但我还是想提出一些可能的改进建议,使其更符合 Python 风格。他们依赖于使用标准库中的检查模块。

    1. 您可以使用 inspect.getmembers() 避免 getattr 调用
    2. 使用inspect.isclass() 可以避免try/catch

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

    def find_subclasses(module, clazz):
        return [
            cls
                for name, cls in inspect.getmembers(module)
                    if inspect.isclass(cls) and issubclass(cls, clazz)
        ]
    

    【讨论】:

    • 效果很好,但我的回复也返回了基类(我用 clazz 发送的那个),知道吗?
    • Fredrik,原来 issubclass(Foo, Foo) 是真的。不过很容易修复。在列表理解中添加“而不是 cls 是 clazz”
    • -1:代码不起作用。正确的是:cls for name, cls in inspect.getmembers(module)
    【解决方案2】:

    这是一种方法:

    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
    

    【讨论】:

    • 我的解决方案不会返回不是“cls”直接后代的类。 quamrana 下面的解决方案将找到在其祖先中某处具有“cls”的任何类。
    【解决方案3】:

    我可以建议 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
    

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

    【讨论】:

      【解决方案4】:

      给定模块 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'>)]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-16
        • 1970-01-01
        • 2011-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多