Reflexión de superclase de Python
-
09-06-2019 - |
Pregunta
Si tengo código Python
class A():
pass
class B():
pass
class C(A, B):
pass
y tengo clase C
, ¿hay alguna manera de iterar a través de su superclase (A
y B
)?Algo así como pseudocódigo:
>>> magicGetSuperClasses(C)
(<type 'A'>, <type 'B'>)
Una solución parece ser inspeccionar el módulo y getclasstree
función.
def magicGetSuperClasses(cls):
return [o[0] for o in inspect.getclasstree([cls]) if type(o[0]) == type]
¿Pero es esta una forma "pitoniana" de lograr el objetivo?
Solución
C.__bases__
es una matriz de superclases, por lo que podrías implementar tu función hipotética de esta manera:
def magicGetSuperClasses(cls):
return cls.__bases__
Pero imagino que sería más fácil simplemente hacer referencia cls.__bases__
directamente en la mayoría de los casos.
Otros consejos
@John:Su fragmento no funciona: está devolviendo el clase de las clases base (que también se conocen como metaclases).Realmente solo quieres cls.__bases__
:
class A: pass
class B: pass
class C(A, B): pass
c = C() # Instance
assert C.__bases__ == (A, B) # Works
assert c.__class__.__bases__ == (A, B) # Works
def magicGetSuperClasses(clz):
return tuple([base.__class__ for base in clz.__bases__])
assert magicGetSuperClasses(C) == (A, B) # Fails
Además, si estás usando Python 2.4+ puedes usar expresiones generadoras en lugar de crear una lista (a través de []), y luego convertirla en una tupla (a través de tuple
).Por ejemplo:
def get_base_metaclasses(cls):
"""Returns the metaclass of all the base classes of cls."""
return tuple(base.__class__ for base in clz.__bases__)
Este es un ejemplo un tanto confuso, pero las genexps son generalmente fáciles y interesantes.:)
El módulo de inspección fue un buen comienzo, use el getmro función:
Devuelve una tupla de las clases base de la clase cls, incluida cls, en el orden de resolución del método.Ninguna clase aparece más de una vez en esta tupla....
>>> class A: pass
>>> class B: pass
>>> class C(A, B): pass
>>> import inspect
>>> inspect.getmro(C)[1:]
(<class __main__.A at 0x8c59f2c>, <class __main__.B at 0x8c59f5c>)
El primer elemento de la tupla devuelta es C
, puedes simplemente ignorarlo.
si necesita saber para ordenar en qué super() llamaría a las clases que puede usar C.__mro__
y no necesito inspect
por lo tanto.