2017-08-26 61 views
5

我期望以下代码打印,但它打印012012.为什么?我希望这些调用能够访问相同的变量,因为它们是从同一个类继承的,但它们显然是不同的变量。python类的方法和继承

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

它不影响意外的行为,你我看到了,但我想指出,你不需要在任何一个子类中使用'super'。你可以直接调用'self.incr()'。当你想跳过不同版本的函数时(通常是因为你已经在当前类中重写),你只需要使用'super'。 – Blckknght

+0

你应该切换到Python 3.6。 https://pythonclock.org/ – wwii

回答

5

他们是从同一个类继承,而是通过超级传递给classmethodcls是当前类,其中方法是从调用。 super可以访问该方法的基类版本,但该呼叫的cls是拨打电话的类别。

这是做的微妙区别之一:

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

和:

def func(self): 
    a.incr() 

您可以在这两种情况下,打印出当前clsincr方法证实了这一点:

你永远不应该假设所有的super都是做一个绑定到父类的方法调用。它做了更多。

请记住,当执行第一个增强赋值+=时,将从基类读取初始值var(因为此时它不存在于子类的字典中)。然而,更新的值被写入子类。来自第二个子类的调用super重复读取a的初始var值的相同行为。

+0

你可能希望明确表示'cls'不同时'cls.var + = 1'行的行为奇怪。第一次运行时,它*读取var的继承值(在本例中为'0',但如果调用了't.incr()',可能会有其他值),但它*写*到特定的'cls'而不是基类。所有后续调用都使用该子类的值,而无需查看基类。 – Blckknght

+0

@Blckknght我会添加一个简短的说明。 –

0

分类b和分类c分别从分类a继承,并且var每次都设置为0。

一种方法有c类来获得的var相同价值a类为类b没有,类c可以从b类继承,像这样:

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

如果第一次调用't2.func()'在所有的't1.func()'调用之后,那么这只会给出预期的结果。如果你把它们混在一起,你就不会得到你所期望的结果。说“var'每次都设置为0”这很容易让人误解。只有一个“var”,当它是零时(“a”中的那个)。在第一次“incr”调用之后,无论什么类都得到一个新的'var'属性,值为'1'。 – Blckknght