2010-02-08 47 views
16

Supongamos que tiene una clase base A, y esta clase se vuelve a implementar por B y C. Supongamos que también hay un método de clase A.derived() que le indica qué clases se vuelven a aplicar A, por lo tanto devuelve [B, C] y si posteriormente tener class D(A): pass o class D(B): pass, ahora A.derived() devuelve [B, C, D].¿Cómo saber todas las clases derivadas de un padre?

¿Cómo implementaría el método A.derived()? Tengo la sensación de que no es posible a menos que use metaclases. Puede atravesar el árbol de herencia solo de hijo a padre con el mecanismo estándar. Para tener el enlace en la otra dirección, debes mantenerlo "a mano", y esto significa anular la mecánica de declaración de clase tradicional.

+0

¿Por qué? ¿Por qué no puedes leer la fuente para determinar esto? –

+0

@ S.Lott: estoy jugando con el búho. no preguntes –

Respuesta

15

Si define sus clases como una clase de nuevo estilo (subclase de object), esto es posible ya que las subclases se guardan en __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 

No sé exactamente cuándo se introdujo esto o si hay alguna consideración especial. Sin embargo, sí funcionan bien para declarar una subclase en una función:

>>> 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 

Sin embargo, es necesario tener en cuenta que hasta que las definiciones de clases han sido ejecutar el intérprete no sabe nada de ellos. En el ejemplo anterior, C no se reconoce como una subclase de A hasta que se ejecute la función f. Pero de todos modos, esto es lo mismo para las clases de python de todos modos, ya que supongo que ya lo sabes.

+0

oh ... eso está bien, no lo sabía. :) –

+2

El método '__subclasses__' es un detalle de implementación no documentado, por lo que puede eliminarse en versiones futuras de Python. Tampoco se implementa en otras versiones de Python como Jython e IronPython. Use con cuidado. –

+6

Raspe lo que dije en mi comentario anterior - Acabo de verificar y se ha agregado a los documentos para 3.x, y está implementado en Jython 2.5, así que supongo que ahora es oficial y llegará para quedarse. No tengo instalado IronPython, por lo que no puedo comentar si todavía está implementado. –

3

Teniendo en cuenta la discusión sobre subclases continuación, una implementación podría tener este aspecto:

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

edición: es posible que también desee ver en este answer a una pregunta ligeramente diferente.

2

Aquí hay otra implementación que imprimirá recursivamente todas las subclases, con indentación.

 
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) 
+0

Hay errores de indentación en for-loop –

+0

@kigurai, ¡gracias por detectar eso! El problema era una pestaña enmascarada como 4 espacios. Lo he arreglado ahora –

Cuestiones relacionadas