Réflexion de super classe Python
-
09-06-2019 - |
Question
Si j'ai du code Python
class A():
pass
class B():
pass
class C(A, B):
pass
et j'ai cours C
, existe-t-il un moyen de parcourir ses super classes (A
et B
) ?Quelque chose comme un pseudocode :
>>> magicGetSuperClasses(C)
(<type 'A'>, <type 'B'>)
Une solution semble être inspecter le module et getclasstree
fonction.
def magicGetSuperClasses(cls):
return [o[0] for o in inspect.getclasstree([cls]) if type(o[0]) == type]
mais est-ce une manière « pythonienne » d'atteindre l'objectif ?
La solution
C.__bases__
est un tableau de super classes, vous pouvez donc implémenter votre fonction hypothétique comme ceci :
def magicGetSuperClasses(cls):
return cls.__bases__
Mais j'imagine qu'il serait plus facile de simplement faire référence cls.__bases__
directement dans la plupart des cas.
Autres conseils
@John:Votre extrait ne fonctionne pas : vous renvoyez le classe des classes de base (également appelées métaclasses).Tu veux vraiment juste 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
De plus, si vous utilisez Python 2.4+, vous pouvez utiliser expressions génératrices au lieu de créer une liste (via []), puis de la transformer en tuple (via tuple
).Par exemple:
def get_base_metaclasses(cls):
"""Returns the metaclass of all the base classes of cls."""
return tuple(base.__class__ for base in clz.__bases__)
C'est un exemple quelque peu déroutant, mais les genexps sont généralement faciles et sympas.:)
Le module d'inspection était un bon début, utilisez le obtenirmro fonction:
Renvoie un tuple des classes de base de la classe cls, y compris cls, dans l'ordre de résolution des méthodes.Aucune classe n'apparaît plus d'une fois dans ce tuple....
>>> 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>)
Le premier élément du tuple renvoyé est C
, vous pouvez simplement l'ignorer.
si vous avez besoin de savoir dans quel ordre super() appellerait les classes que vous pouvez utiliser C.__mro__
et je n'ai pas besoin inspect
donc.