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的实例中调用的类被创建,这是在类本身被创建之后的必然结果。