2008-08-25 19 views
30

Si je code PythonPython réflexion super classe

class A(): 
    pass 
class B(): 
    pass 
class C(A, B): 
    pass 

et je classe C, est-il un moyen d'itérer à travers elle est super Classée (A et B)? Quelque chose comme pseudocode:

>>> magicGetSuperClasses(C) 
(<type 'A'>, <type 'B'>) 

Une solution semble être inspect 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 façon "pythonienne" d'atteindre l'objectif?

+2

L'adjectif correct est "Pythonic". – asmeurer

+0

Voir aussi [Vérifier si A est une super-classe de B en Python] (/ q/1938755/1157100). –

Répondre

36

C.__bases__ est un tableau des super-classes, pour que vous puissiez mettre en œuvre votre fonction hypothétique comme ceci:

def magicGetSuperClasses(cls): 
    return cls.__bases__ 

Mais je suppose qu'il serait plus facile de faire référence à juste cls.__bases__ directement dans la plupart des cas.

+0

Je +1 si cela était corrigé par le point cdleary ci-dessous. –

11

@John: Votre extrait ne fonctionne pas - vous renvoyez la classe des classes de base (également appelées métaclasses). Vous voulez vraiment que 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 generator expressions au lieu de créer une liste (via []), puis en le transformant en un 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__) 

Ceci est un exemple assez confus, mais genexps sont généralement faciles et cool. :)

+0

Ce message ne semble plus pertinent (John a corrigé sa réponse). Si j'étais vous, je supprimerais ce post. –

4

Le inspectez module a été un bon début, utilisez la fonction getmro:

Return a tuple of class cls’s base classes, including cls, in method resolution order. No class appears more than once in this 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 retourné est C, vous pouvez simplement l'ignorer.

2

si vous avez besoin de savoir à l'ordre dans lequel super() appellera les classes, vous pouvez utiliser C.__mro__ et n'avez donc pas besoin de inspect.

+0

Cela n'a pas fonctionné pour moi. Dans mon exemple, j'ai 'class C (B): pass', et' C .__ mro__' donne 'AttributeError: la classe C n'a pas d'attribut '__mro __'', alors que 'inspect.getmro (C)' renvoie '(__main__ .C, __main __. B) '. J'utilise Python 2.7.6. – m01