是否可以重写子类中属性的getter?

时间:2011-05-30 21:14:26

标签: python inheritance

例如:

class Example:
    def __init__(self):
        self.v = 0

    @property
    def value(self):
        return self.v
    @value.setter
    def value(self, v):
        self.v = v

class SubExample(Example):
    pass

是否可以在SubExample中仅将getter重写为值?

3 个答案:

答案 0 :(得分:4)

你可以这样做

class DoubleExample(Example):
    @Example.value.getter
    def value(self):
        return self.v * 2

o = Example()
o.value = 1
print o.value # prints "1"

p = DoubleExample()
p.value = 1
print p.value # prints "2"

但是,这仅在Example是新样式类(class Example(object):)而不是旧样式类(class Example:)时才有效,就像在示例代码中一样。 / p>


警告: Thomas在评论中指出,如果您使用多重继承(class Foo(Bar, Baz)),此方法可能无法按预期运行。

答案 1 :(得分:3)

无法在子类中覆盖属性的getter,no。该属性是一个存在于类中的对象,它包含对您提供的函数的引用 - 如果稍后重新定义这些函数的名称,它将根本不会影响该属性。

可以做的是让你的属性调用的函数执行间接调用,如下所示:

class Example(object):
    def __init__(self):
        self.v = 0

    @property
    def v(self):
       return self._v_getter()
    @v.setter
    def v(self, value):
       return self._v_setter(value)

    def _v_setter(self, value):
        self._v = value

class SubExample(Example):
    def _v_getter(self):
        return 5

>>> se = SubExample()
>>> se.v
5
>>> se._v
0
>>> se.v = 10
>>> se.v
5
>>> se._v
10

或者,您可以通过简单地定义新属性来重新定义子类中的整个属性。但是,您无法方便地访问父类中定义的函数或属性,并且面对多重继承时做正确的事情很困难。

答案 2 :(得分:0)

您的问题之前已得到解答:

http://code.activestate.com/recipes/408713-late-binding-properties-allowing-subclasses-to-ove/ http://stackoverflow.com/questions/3393534/python-property-and-method-override-issue-why-subclass-property-still-calls-the

本质上,不必直接使用property,而是必须推迟调用getter,以便它在第一次定义属性时访问子类中定义的而不是超类中定义的那个。这可以通过lambda

来实现
class Test(object):
    def __init__(self):
        self.v = 0
    def _value(self):
        return self.v
    def _value_setter(self, v):
        self.v = v
    value = property(lambda self: self._value(), lambda self, v: self._value_setter(v))

class Test2(Test):
    def _value(self):
        return self.v + 1

a = Test()
a.value = 2
print a.value  # 2

b = Test2()
b.value = 2
print b.value  # 4