31 votes

Réflexion sur la super classe Python

Si j'ai un code Python

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

et j'ai de la classe C existe-t-il un moyen d'itérer à travers ses super classes ( A y B ) ? Quelque chose comme un pseudo-code :

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

Une solution semble être inspecter le module y 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 ?

36voto

John Points 5478

C.__bases__ est un tableau des super classes, vous pourriez donc implémenter votre fonction hypothétique comme suit :

def magicGetSuperClasses(cls):
  return cls.__bases__

Mais j'imagine qu'il serait plus facile de simplement référencer cls.__bases__ directement dans la plupart des cas.

11voto

cdleary Points 18869

@John : Votre extrait ne fonctionne pas -- vous retournez le fichier classe des classes de base (qui sont également appelées métaclasses). Vous voulez 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 de générateur au lieu de créer une liste (via []), puis de la transformer 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__)

C'est un exemple un peu confus, mais les genexps sont généralement faciles et cool :)

4voto

Torsten Marek Points 27554

Le module inspect était un bon début, utilisez le module getmro fonction :

Retourne un tuple de classes de base de la classe cls, incluant 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 retourné est C vous pouvez l'ignorer.

2voto

sinzi Points 87

Si vous avez besoin de connaître l'ordre dans lequel super() appelle les classes, vous pouvez utiliser C.__mro__ et n'ont pas besoin inspect donc.

0voto

Emma Points 2122

J'ai essayé cette fonction de la réponse de cdleary, et j'ai obtenu une erreur

def get_base_metaclasses(cls):
    """Returns the metaclass of all the base classes of cls."""
    return tuple(base.__class__ for base in cls.__bases__)

Voici ma solution récursive :

class A:
    @classmethod
    def get_superclasses(cls):
        """Returns all superclasses of cls."""
        b = list(cls.__bases__)
        for base in b:
            b = b + base.get_superclasses()
        return b
class B(A): pass
class C(B): pass

c = C()
# This works both for an instance and for a class
print c.get_superclasses()
print C.get_superclasses()

renvoie à

[<class __main__.B at 0xb7ca156c>, <class __main__.A at 0xb7ca144c>]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X