Reflexão da superclasse Python
-
09-06-2019 - |
Pergunta
Se eu tiver código Python
class A():
pass
class B():
pass
class C(A, B):
pass
e eu tenho aula C
, existe uma maneira de iterar através de sua superclasse (A
e B
)?Algo como pseudocódigo:
>>> magicGetSuperClasses(C)
(<type 'A'>, <type 'B'>)
Uma solução parece ser inspecionar módulo e getclasstree
função.
def magicGetSuperClasses(cls):
return [o[0] for o in inspect.getclasstree([cls]) if type(o[0]) == type]
mas esta é uma maneira "Pythoniana" de atingir o objetivo?
Solução
C.__bases__
é um array de superclasses, então você poderia implementar sua função hipotética assim:
def magicGetSuperClasses(cls):
return cls.__bases__
Mas imagino que seria mais fácil apenas fazer referência cls.__bases__
diretamente na maioria dos casos.
Outras dicas
@John:Seu snippet não funciona. Você está retornando o aula das classes base (que também são conhecidas como metaclasses).Você realmente só quer 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
Além disso, se você estiver usando Python 2.4+, você pode usar expressões geradoras em vez de criar uma lista (via []) e depois transformá-la em uma tupla (via tuple
).Por exemplo:
def get_base_metaclasses(cls):
"""Returns the metaclass of all the base classes of cls."""
return tuple(base.__class__ for base in clz.__bases__)
Esse é um exemplo um tanto confuso, mas genexps geralmente são fáceis e legais.:)
O módulo de inspeção foi um bom começo, use o getmro função:
Retorna uma tupla das classes base da classe cls, incluindo cls, na ordem de resolução do método.Nenhuma classe aparece mais de uma vez nesta 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>)
O primeiro elemento da tupla retornada é C
, você pode simplesmente desconsiderá-lo.
se você precisar saber em qual ordem super() chamaria as classes que você pode usar C.__mro__
e não precisa inspect
portanto.