子类中重写属性setter的特性

Sil*_*Ray 2 python overriding properties

所以我有这个:

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
Run Code Online (Sandbox Code Playgroud)

当我运行它时,我得到了这个:

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
Run Code Online (Sandbox Code Playgroud)

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

Cat*_*lus 5

因为你不一致地称它 - 一次直接,一次通过一个属性.改变self._set_x(x)Parent.__init__self.x = x,你会看到Child._set_x永远不会被调用.要覆盖子类中的setter,可以使用property.setteras decorator:

class Child(Parent):
    @Parent.x.setter
    def x(self, arg):
        super()._set_x(arg)
Run Code Online (Sandbox Code Playgroud)

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

class Parent(object):
    # ...
    x = property(
        lambda self:    self._get_x(),
        lambda self, x: self._set_x(x)
    )
Run Code Online (Sandbox Code Playgroud)

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