super(Foo, self)和super(Foo, self.__class__)之间的区别是什么?

3

我对Python非常陌生,希望我没有错过太多必要的知识来理解这个问题,但是...

我有一个类,其中包含一些属性,我正在尝试覆盖其中一个属性的setter,类似于以下示例:

class Foo(object):
    def __init__(self):
        self._x = True

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

class Bar(Foo):
    @property
    def x(self):
        return super().x

    @x.setter
    def x(self, value):
        print('x set')

        super(Bar, self.__class__).x.fset(self, value)

bar = Bar()

# Prints 'x set' as expected:
bar.x = True

这很好用,但我真的不理解为什么这一行代码能够以它现在的方式运行...
super(Bar, self.__class__).x.fset(self, value)

...以及它与不起作用的这行代码有何不同:

super(Bar, self).x.fset(self, value)

如果您能提供任何指导,我们将不胜感激。

1个回答

2
为了简化问题,我们假设(就像你的例子中一样)super总是返回Foo中定义的东西的代理,也就是说,没有其他类涉及其中。
  1. 暂时忽略对super的调用,考虑bar.xBar.x之间的区别。前者会调用命名属性的getter方法;后者只是对属性本身的引用。

  2. 现在考虑一个非属性的属性。 super(Bar, self).method将是一个绑定方法的实例,这样super(Bar, self).method(x)将等同于Foo.method(self, x)super(Bar, self.__class__).method则是未绑定的方法,即简单地Foo.method

  3. 现在将步骤1和步骤2结合起来。我们知道bar.x将导致在Bar中定义的getter被调用,我们也知道super(Bar, self)通过self作为代理,是指向Foo的。因此,super(Bar, self).x必须调用在Foo中定义而不是在Bar中定义的getter。

    我们还知道Bar.x只是对property对象的引用,不会调用其getter方法;并且我们知道super(Bar, self.__class__)作为代理是独立于任何特定对象的Foo。因此,我们可以得出结论:super(Bar, self.__class__).x,对于Bar的实例self,是对在Foo中定义的property对象的引用。


这非常有道理。感谢您提供如此清晰的回答! - Ocelot20

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接