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

Python 是否可以重写子类中属性的getter?,python,inheritance,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 是否可以在子示例中将getter重写为value?您的问题之前

例如:

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

是否可以在子示例中将getter重写为value?

您的问题之前已经得到了回答:

http://stackoverflow.com/questions/3393534/python-property-and-method-override-issue-why-subclass-property-still-calls-the

本质上,您不必直接使用
属性
,而是必须延迟调用getter,以便它能够访问在子类中定义的getter,而不是在您首次定义属性时在超类中定义的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

不可能在子类中重写属性的getter。属性是一个存在于类中的对象,它包含对给定函数的引用——如果以后重新定义这些函数的名称,它将根本不会影响属性

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

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

或者,只需定义一个新属性,就可以在子类中重新定义整个属性。但是,您将无法方便地访问parentclass中定义的函数或属性,而且在多重继承面前做正确的事情是很困难的。

您可以这样做

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"
但是,只有当
示例
是一个新样式的类(
类示例(对象):
)而不是一个旧样式的类(
类示例:
)时,这才起作用,就像在示例代码中一样



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

我修复了您的代码示例,使其成为有效的Python。啊,这就是我想要的。我不知道这个新/旧的课堂风格,我还在学习。谢谢还有什么地方可以让我了解更多关于使用
@
?setter只在新型类(直接或间接从
对象继承的类)中工作。此解决方案的问题是它无法正确处理多继承情况,如果其他类在inheritace层次结构中介于
DoubleExample
Example
之间。@ghasyx:为了帮助您进行搜索,使用
@
的名称为“Decorator”。它们的工作方式非常简单:将
@Example.value.getter
放在方法之前就像将
value=Example.value.getter(value)
放在方法之后一样。恐怕我不知道有什么好的资源可以学习它们。关于新/旧样式的类:我认为旧样式的类只是为了向后兼容,您应该在编写的代码中始终使用新样式的类。@Thomas:您能提供一个这样做不起作用的示例吗?我对它在多重继承下的行为感到不舒服,但无法想出一个简单的失败案例。从
Example
继承并重写属性的
SideExample
,以及从
DoubleExample
SideExample
继承的
DoubleSideExample
(按该顺序)这不涉及属性。
DoubleSideExample
类的大部分行为都会被
SideExample
修改,但是属性会完全忽略
SideExample
类。看起来您在示例中遗漏了内部属性名称前的下划线。\uu initldn您的基类中不也定义了占位符_v_getter方法吗?我是在一个基类中这样做的,在这个基类中,重写属性getter是类的主要用途之一。用户可以将self.dloc=NPArray设置为固定值,或者self.calc_loc=self.foo覆盖属性getter方法对象只是使用somenode.loc来请求值。我没有错过
\uuuuu init\uuuuu
中的下划线。
\uuuu init\uuuuuu
方法只是分配给属性,这意味着调用了实际属性的setter。是的,通常您也希望基类提供最小的
\u getter
。我不记得为什么我没有这样做这里是这样。对!所有的方法在初始化时都已经存在,所以self.v调用self.\v\u setter,甚至在init中也是如此。我觉得这有点奇怪吗?我的直接想法是,您引用的是一个未初始化的变量\u v…我不知道您为什么认为这会很棘手。
\u init\uu
方法是在c的实例中调用的类被创建,这是在类本身被创建之后的必然结果。