如何知道某个父类的所有派生类?

23 投票
3 回答
6034 浏览
提问于 2025-04-15 19:00

假设你有一个基础类A,这个类被B和C重新实现了。还有一个类方法A.derived(),它可以告诉你哪些类在重新实现A,所以它会返回[B, C]。如果你后来又定义了class D(A): pass或者class D(B): pass,那么现在A.derived()会返回[B, C, D]。

那么,你该怎么实现这个方法A.derived()呢?我觉得这可能不太容易,除非你使用元类。因为用标准的方法,你只能从子类向父类遍历继承树。如果想要反向链接,也就是从父类找到子类,你就得手动维护这个关系,这就意味着你需要改变传统的类声明方式。

3 个回答

2

这里有另一个实现方法,它会递归地打印出所有的子类,并且会加上缩进。

def findsubclass(baseclass, indent=0):
    if indent == 0:
        print "Subclasses of %s are:" % baseclass.__name__
    indent = indent + 1
    for c in baseclass.__subclasses__():
        print "-"*indent*4 + ">" + c.__name__
        findsubclass(c, indent)
3

根据关于子类的讨论,下面的实现可能是这样的:

class A(object):
    @classmethod
    def derived(cls):
        return [c.__name__ for c in cls.__subclasses__()]

补充说明: 你可能还想看看这个 回答,它是针对一个稍微不同的问题。

23

如果你把你的类定义为新式类(也就是继承自 object 的类),那么就可以做到这一点,因为子类会被保存在 __subclasses__ 里。

class A(object):
 def hello(self):
  print "Hello A"

class B(A):
 def hello(self):
   print "Hello B"

>>> for cls in A.__subclasses__():
...  print cls.__name__
...
B

我不太清楚这个功能具体是什么时候引入的,或者有没有什么特别的注意事项。不过,在一个函数里声明一个子类是完全没问题的:

>>> def f(x):
...  class C(A):
...   def hello(self):
...    print "Hello C"
...  c = C()
...  c.hello()
...  print x
...  for cls in A.__subclasses__():
...   print cls.__name__
...
>>> f(4)
Hello C
4
B
C

不过,你需要注意的是,在类的定义被执行之前,解释器是不会知道这些类的。在上面的例子中,C 直到函数 f 被执行后,才会被识别为 A 的子类。但这对于 Python 的类来说,每次都是这样,我想你应该已经知道了。

撰写回答