【问题标题】:python class methods and inheritancepython类方法和继承
【发布时间】:2018-02-04 12:03:09
【问题描述】:

我希望下面的代码会打印 012345,但它会打印 012012。为什么?我希望对 incr 的调用访问相同的变量,因为它们是从同一个类继承的,但它们显然是不同的变量。

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()

【问题讨论】:

  • 它不会影响您看到的意外行为,但我想指出您不需要在任何子类中使用super。您可以直接致电self.incr()。当你想跳过不同版本的函数时,你只需要使用super(通常是因为你已经在当前类中被覆盖了)。
  • 你应该切换到 Python 3.6。 pythonclock.org

标签: python class methods multiple-inheritance


【解决方案1】:

有一种方法可以生成序列 012345。您必须确保在 incr 方法中增加类 avar,即使在子类中调用它也是如此。 要实现这一点,请增加a.var += 1,而不是cls.var += 1

正如其他答案所指出的,var 也继承给bc。 通过使用cls.var += 1,两个子类都增加了它们自己的var,而不是avar

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

class b(a):
    def f(self):
        super().incr()

class c(a):
    def f(self):
        super().incr()

cb = b()
cc = c()
cb.incr()
cb.incr()
cb.incr()
cc.incr()
cc.incr()
cc.incr()

cb.incr()
cc.incr()

生产:

0
1
2
3
4
5
6
7

【讨论】:

    【解决方案2】:

    它们继承自同一个类,但通过 super 传递给 classmethodcls 是调用该方法的当前类。 super 访问方法的基类版本,但调用的 cls 是进行 super 调用的类。

    这是做事之间细微的区别之一:

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

    和:

    def func(self):
        a.incr()
    

    在这两种情况下,您都可以通过在 incr 方法中打印当前的 cls 来确认这一点:

    def incr(cls):
        print cls
        ...
    

    您永远不应该假设super 所做的只是将方法调用绑定到父类。它的作用更多。

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

    【讨论】:

    • 您可能想明确指出,当cls 不同时,cls.var+=1 行的行为异常。第一次运行时,它读取 var 的继承值(在示例中为0,但如果已调用t.incr() 则可能是其他值),但它写入到特定的cls 而不是基类。所有后续调用都使用子类的值,而不会看到基类。
    • @Blckknght 我会添加一个简短的说明。
    【解决方案3】:

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

    一种让c 类在a 中获得与b 类相同的var 值的方法,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()` 
    

    【讨论】:

    • 只有在对t2.func() 的第一次调用出现在所有t1.func() 调用之后才会给出预期结果。如果你把它们混在一起,你就不会得到你期望的结果。说“var 每次都设置为 0”是非常具有误导性的。当它为零时只有一个vara 中的那个)。在第一个 incr 调用之后,无论在哪个类上创建一个新的 var 属性,其值为 1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多