Как узнать все производные классы родителя?
Предположим, что у вас есть базовый класс A, и этот класс переопределяется B и C.
Предположим также, что существует метод класса A.derived()
, который говорит вам, какие классы переопределяют A, поэтому возвращает [B, C], и если вы позже имеете class D(A): pass
или class D(B): pass
, теперь A.derived()
возвращает [B, C, D].
Как бы вы реализовали метод A.derived()
? У меня такое ощущение, что это невозможно, если вы не используете метаклассы. Вы можете пересечь дерево наследования только с дочернего на родительский с помощью стандартного механизма. Чтобы иметь ссылку в другом направлении, вы должны держать ее "вручную", а это означает отмену традиционной механики декларации классов.
Ответы
Ответ 1
Если вы определяете свои классы как класс нового стиля (подкласс 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
не распознается как подкласс A до тех пор, пока не будет выполнена функция f
. Но в любом случае это одинаково для классов python, поскольку я полагаю, что вы уже знаете.
Ответ 2
Учитывая обсуждение подклассов, реализация может выглядеть так:
class A(object):
@classmethod
def derived(cls):
return [c.__name__ for c in cls.__subclasses__()]
edit: вы также можете посмотреть на этот ответ на несколько другой вопрос.
Ответ 3
Вот еще одна реализация, которая будет рекурсивно распечатывать все подклассы с отступом.
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)