子类中重写属性setter的特性

时间:2012-02-14 19:12:27

标签: python properties override

所以我有这个:

class Parent(object):

    def __init__(self, val):
        print 'enter Base init'
        self._set_x(val)
        print 'leave Base init'

    def _get_x(self):
        return self._x

    def _set_x(self, val):
        print 'enter Base _set_x'
        self._x = val
        print 'leave Base _set_x'

    x = property(_get_x, _set_x)

class Child(Parent):

    def _set_x(self, val):
        print 'enter Child _set_x'
        y = val * 2
        super(Child, self)._set_x(y)
        print 'leave Child _set_x'

child = Child(5)
num = child.x
child.x = 5
print num == child.x

当我运行它时,我明白了:

enter Base init
enter Child _set_x
enter Base _set_x
leave Base _set_x
leave Child _set_x
leave Base init
enter Base _set_x
leave Base _set_x
False

我一直在读书,人们都说最重要的不应该奏效,但我的问题是为什么这里看似不一致?从init调用时,子类'setter被调用,但是当你稍后对已经初始化的对象进行操作时,它会调用base的setter。有人可以解释这里发生了什么吗?

4 个答案:

答案 0 :(得分:5)

因为你不一致地称它 - 一次直接称呼,一次通过一个属性。将self._set_x(x)中的Parent.__init__更改为self.x = x,您将看到永远不会调用Child._set_x。要覆盖子类中的setter,可以使用property.setter作为装饰器:

class Child(Parent):
    @Parent.x.setter
    def x(self, arg):
        super()._set_x(arg)

或者向属性添加一个间接级别:

class Parent(object):
    # ...
    x = property(
        lambda self:    self._get_x(),
        lambda self, x: self._set_x(x)
    )

覆盖不能直接起作用,因为属性存储具体的方法对象(Parent._get_xParent._set_x),并且不会再次查找它们,即使对象的类型恰好发生了变化 - 无论如何运行的代码都是相同的。间接强制在动态类型self中查找,允许覆盖。

答案 1 :(得分:3)

没有矛盾。 __init__方法通过属性查找显式调用self._set_xself在此处引用Child对象,由于Child定义_set_xChild类位于对象的Method Resolution Order(MRO)中),它的_set_x版本是被调用的版本。

但是x属性是在Parent内定义的。尚未涉及儿童,因此传递给_set_x的{​​{1}}和_get_x版本是property中定义的版本。现在,当访问Parent的{​​{1}}属性时,Python首先在x类中查找Child。但它找不到它,因为x没有定义它。然后它进入MRO的下一课:Child。它在那里找到Child,并按照Parent中的定义使用它。

答案 2 :(得分:2)

x = property(_get_x, _set_x)

此处x成为具有getter Parent._get_x和setter Parent._set_x的属性。

如果您将行x = property(Parent._get_x, _set_x)添加到Child类,则会重新定义该属性并按预期工作。

答案 3 :(得分:0)

将方法视为对象。 Parent类上的属性x已绑定到父类的_get_x / _set_x方法对象。但是在你的Child类中,你正在调用该类'自己的_set_x方法对象。