2009-11-20 2 views
9

Voici une session python.La métaclasse n'est pas appelée dans les sous-classes

>>> class Z(type): 
    def __new__(cls, name, bases, attrs): 
     print cls 
     print name 
     return type(name, bases, attrs) 
...  
>>> class Y(object): 
    __metaclass__ = Z 
...  
<class '__main__.Z'> 
Y 
>>> class X(Y): 
...  pass 
... 
>>> class W(Y): 
...  __metaclass__ = Z 
...  
<class '__main__.Z'> 
W 
>>> 

Après la classe XI attendent définis Z._new__ à appeler pour lui, et pour imprimer la deuxième ligne, ce qui ne se produit pas, (comme métaclasse sont hérités?)

Répondre

12

Le problème est que l'argument cls (qui est l'objet métaclasse) n'est pas transmis lorsque vous appelez type, par conséquent l'objet de classe Y créé et retourné ne contient aucune référence à la métaclasse Z.

Si vous remplacez la dernière ligne __new__ avec

return super(Z, cls).__new__(cls, name, bases, attrs) 

il fonctionne. Notez que même si cls est utilisé dans super, nous devons encore fournir cls comme argument, puisque super renvoie ici une méthode non liée (voir here pour plus d'informations).

Comme alternative à l'utilisation de super on peut utiliser:

return type.__new__(cls, name, bases, attrs) 

L'important est que nous donnons cls (notre objet métaclasse Z) au classmethod __new__. La forme plus courte type(name, bases, attrs) remplit type lui-même pour l'argument cls, ce qui est bien sûr erroné. Cette erreur est similaire à l'appel d'une méthode d'instance avec le mauvais argument self.

Je préfère utiliser super, car c'est un meilleur style.

+2

Ah, d'accord, ça marche. Mais ne devrait pas retourner super (Z, cls) .__ new__' être équivalent à 'type .__ classe __. New' whis est équivalent à' type .__ new__' qui devrait être identique à la création d'une nouvelle classe via 'type'? – agiliq

+2

En fait, ce n'est pas la même chose, j'aborde maintenant cela dans ma réponse. Super appelle la méthode 'type .__ new__', mais nous pouvons alors utiliser l'argument' cls' correct, ce qui n'est pas possible si nous appelons 'type' directement. – nikow

Questions connexes