2017-08-26 3 views
5

Je m'attendrais à ce que le code suivant imprimemais il imprime 012012. Pourquoi? Je m'attendrais à ce que les appels augmentent pour accéder aux mêmes variables puisqu'ils sont hérités de la même classe mais ils sont clairement des variables différentes.Méthodes de classe python et héritage

class a(object): 
    var = 0 
    @classmethod 
    def incr(cls): 
     print cls.var 
     cls.var+=1 

class b(a): 
    def func(self): 
     super(b,self).incr() 

class c(a): 
    def func(self): 
     super(c,self).incr() 


t = a() 
t1 = b() 
t2 = c() 
t1.func() 
t1.func() 
t1.func() 
t2.func() 
t2.func() 
t2.func() 
+1

Il n'a pas d'effet le comportement inattendu vous Je vois, mais je veux noter que vous n'avez pas besoin d'utiliser «super» ici dans l'une ou l'autre de vos sous-classes. Vous pouvez simplement appeler 'self.incr()' à la place. Vous n'avez besoin d'utiliser 'super' que lorsque vous voulez passer une version différente de la fonction (généralement parce que vous avez écrasé la classe actuelle). – Blckknght

+0

Vous devriez passer à Python 3.6. https://pythonclock.org/ – wwii

Répondre

5

Ils sont hérités de la même classe, mais le cls passé à la classmethod via super est la classe actuelle où la méthode a été appelée. super accède à la version de la classe de base de la méthode, mais cls pour l'appel est la classe où l'appel super a été effectué.

Ceci est l'un des subtiles différences entre faire:

def func(self): 
    super(c, self).incr() # same as a.__dict__['incr'].__get__(self, type(self))() 

et:

def func(self): 
    a.incr() 

Vous pouvez confirmer en imprimant la cls actuelle dans votre méthode incr dans les deux cas:

Vous ne devez jamais supposer que tout super fait est un appel de méthode lié à la classe parente. Cela fait beaucoup plus. Gardez à l'esprit que lorsque la première affectation augmentée += est exécutée, la valeur initiale var est lue dans la classe de base (puisqu'à ce stade, elle n'existe pas dans la dict des sous-classes). La valeur mise à jour est cependant écrite dans la sous-classe. L'appel super de la seconde sous-classe répète le même comportement de lecture de la valeur initiale var de a.

+0

Vous pouvez être explicite sur le fait que c'est la ligne 'cls.var + = 1' qui se comporte bizarrement lorsque' cls' est différent. La première fois qu'elle est exécutée, elle * lit * la valeur héritée de 'var' (qui est' 0' dans l'exemple, mais aurait pu être une autre valeur si 't.incr()' avait été appelée), mais elle * écrit * sur le 'cls' spécifique plutôt que sur la classe de base. Tous les appels suivants utilisent la valeur de la sous-classe sans jamais voir la classe de base. – Blckknght

+0

@Blckknght Je vais ajouter une petite note à ce sujet. –

0

Les deux classes b et la classe c Hériter de la classe a séparément, et var est réglé sur 0 à chaque fois.

Une façon d'avoir la classe c pour obtenir la même valeur de var en classe a comme classe b ne classe c peut hériter de la classe b comme ceci:

class a(object): 
    var = 0 
    @classmethod 
    def incr(cls): 
     print cls.var 
     cls.var+=1 

class b(a): 
    def func(self): 
     super(b,self).incr() 

class c(b): 
    def func(self): 
     super(c,self).incr() 


t = a() 
t1 = b() 
t2 = c() 
t1.func() 
t1.func() 
t1.func() 
t2.func() 
t2.func() 
t2.func()` 
+1

Cela donne seulement le résultat attendu si le premier appel à 't2.func()' vient après tous les appels 't1.func()'. Si vous les mélangez, vous n'obtiendrez pas le résultat attendu. Et il est très trompeur de dire que "' var' est mis à 0 à chaque fois ". Il n'y a qu'un 'var' quand c'est zéro (celui de' a').C'est après le premier appel 'incr' que la classe sur laquelle il a été créé obtient un nouvel attribut' var' avec la valeur '1'. – Blckknght