Super class 似乎错误地引用了 derived class 的属性

Super class appears to wrongly reference properties of derived class

在下面的 python 代码中(我使用的是 3.8),class B 的 object 来自 class A 调用方法 bar foo 通过 super() 函数访问 parent class 的成员。因此,我希望得到与直接在 A 上调用 barfoo 相同的结果。奇怪的是,返回的内容受 B 的 p 参数化的影响,这不应该发生,因为 A应该屏蔽它的 children,不是吗?!这是要重现的代码:

class A(object):
    @property
    def p(self):
        return 3

    def bar(self):
        return self.p

    def foo(self):
        return self.bar()

class B(A):
    @property
    def p(self):
        return 6

    def bar(self):
        return super().p

    def foo(self):
        return super().bar()



a, b = A(), B()

print(a.p) # prints 3, OK
print(b.p) # prints 6, OK

print(a.bar()) # prints 3, OK
print(b.bar()) # prints 3, OK, since where accessing super().p 

print(a.foo()) # prints 3, OK
print(b.foo()) # prints 6, NOT OK, because we are accessing super().bar() and expect 3

我在这里不知所措,所以如果有人可以阐明这种行为的基本原理并展示一种避免它的方法,这将是最有帮助的。非常感谢。

欢迎来到错综复杂的 super

super() 这里是 super(B, self) 的快捷方式。它 returns 将在 class MRO 中查找 B 之前出现的 class 的代理,因此 A 和 super().bar() 实际上会调用:

A.bar(self)

不更改原始 b 对象...

A.bar(self) 实际上是... b.p 并且会给出 6


如果您习惯了其他面向对象的语言,如 C++,那么一切都会发生,就好像 Python 中的所有方法都是虚拟的(Java 措辞中的非最终方法)

super().attr 表示在parent中查找attr属性。如果 attr 是一个方法,它会查找方法的代码(要执行的指令)。但这不会以任何方式修改传递的参数,它只是设置指令。

在Python中,self是幕后的争论。如果 c=C(),则 c.meth(...) 表示 C.meth(c, ...),即调用 class C 中定义的方法 meth 第一个参数 c(其他args跟随,如果有的话)。第一个参数成为方法实现中的 self 参数。名字self只是约定俗成,不是特殊关键字)

回到问题。这是一个没有属性的简化程序,它的行为相同:

class A:
    P = 3 

    def bar(self):
        return self.P

    def foo(self):
        return self.bar()

class B(A):
    P = 6 

    def bar(self):
        return super().P

    def foo(self):
        return super().bar()

b.foo() 调用 super().bar(),即父 class A 中的 bar()。该方法包含简单的 returns self.P 代码。但是 selfb,所以查找 returns 6。(在你原来的程序中 p 是 属性 即 returns 6)