Jes*_*ick 41 python inheritance overriding properties
所以,我试图找出最好的(最优雅,代码最少)的方法来允许在python中覆盖属性的特定函数(例如,只是getter,只是setter等).我喜欢以下做属性的方法,因为它们的所有方法都被封装在相同的缩进代码块中(更容易看到处理一个属性的函数停止在哪里以及处理函数的函数下一步开始):
@apply
def foo():
"""A foobar"""
def fget(self):
return self._foo
def fset(self, val):
self._foo = val
return property(**locals())
Run Code Online (Sandbox Code Playgroud)
但是,如果我想从以这种方式定义属性的类继承,然后,比如重写foo
setter函数,那么它似乎很棘手.我做了一些搜索和大多数我已经找到了答案已经确定在基类(如独立的功能getFoo
和setFoo
),明确从他们(例如,创建一个属性定义foo = property(lambda x: x.getFoo(), lambda x, y: x.setFoo(y), lambda x: x.delFoo())
),然后覆盖getFoo
,setFoo
以及delFoo
根据需要.
我不喜欢这个解决方案,因为这意味着我必须为每个属性定义lambas,然后写出每个函数调用(在我刚刚完成之前property(**locals())
).我也没有得到我原来的封装.
理想情况下,我希望能够做到的是这样的事情:
class A(object):
def __init__(self):
self.foo = 8
@apply
def foo():
"""A foobar"""
def fget(self):
return self._foo
def fset(self, val):
self._foo = val
return property(**locals())
class ATimesTwo(A):
@some_decorator
def foo():
def fset(self, val):
self._foo = val * 2
return something
Run Code Online (Sandbox Code Playgroud)
然后输出看起来像:
>>> a = A()
>>> a.foo
8
>>> b = ATimesTwo()
>>> b.foo
16
Run Code Online (Sandbox Code Playgroud)
基本上,ATimesTwo
继承getter函数A
但覆盖setter函数.有没有人知道这样做的方式(以类似于上面例子的方式)?some_decorator
看起来会是什么函数,foo
函数应该返回什么?
std*_*err 51
装饰器上的Python 文档property
提出了以下习语:
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
Run Code Online (Sandbox Code Playgroud)
然后子类可以覆盖单个setter/getter,如下所示:
class C2(C):
@C.x.getter
def x(self):
return self._x * -1
Run Code Online (Sandbox Code Playgroud)
这有点吵,因为覆盖多种方法似乎需要你做以下事情:
class C3(C):
@C.x.getter
def x(self):
return self._x * -1
# C3 now has an x property with a modified getter
# so modify its setter rather than C.x's setter.
@x.setter
def x(self, value):
self._x = value * 2
Run Code Online (Sandbox Code Playgroud)
当然,当你重写getter,setter和deleter时,你可以重新定义C3的属性.
agf*_*agf 46
我相信你以前听过这个,但自从Python 2.3以来apply
已经被弃用了八年.不要使用它.你的使用locals()
也与Python的Zen相反 - 显式优于隐式.如果你真的喜欢增加的缩进,那么就没有必要创建一个一次性对象了
if True:
@property
def foo(self):
return self._foo
@foo.setter
def foo(self, val):
self._foo = val
Run Code Online (Sandbox Code Playgroud)
哪个不滥用locals
,使用apply
,需要创建一个额外的对象,或者之后需要一行,foo = foo()
使得更难以看到块的结尾.它适用于您的老式使用方式property
- 只需foo = property(fget, fset)
照常进行.
如果要覆盖任意子类中的属性,可以使用这样的配方.
如果子类知道属性的定义位置,那么只需:
class ATimesTwo(A):
@A.foo.setter
def foo(self, val):
self._foo = val * 2
Run Code Online (Sandbox Code Playgroud)
jus*_*usx 12
stderr 的答案满足大多数用例。
我想为您想要扩展getter
,setter
和/或 的情况添加一个解决方案deleter
。有两种方法可以做到这一点:
property
第一种方法是通过子类化内置函数property
并添加装饰器,这些装饰器是getter
,setter
和/或deleter
扩展当前 get、set 和 delete 回调的版本
支持将方法附加到集合函数的属性示例:
class ExtendableProperty(property):
def append_setter(self, fset):
# Create a wrapper around the new fset that also calls the current fset
_old_fset = self.fset
def _appended_setter(obj, value):
_old_fset(obj, value)
fset(obj, value)
# Use that wrapper as setter instead of only the new fset
return self.setter(_appended_setter)
Run Code Online (Sandbox Code Playgroud)
用法与普通属性相同,只是现在可以向属性设置器添加方法:
class A(object):
@ExtendableProperty
def prop(self):
return self._prop
@prop.setter
def prop(self, v):
self._prop = v
class B(A):
@A.prop.append_setter
def prop(self, v):
print('Set', v)
Run Code Online (Sandbox Code Playgroud)
>>> a = A()
>>> a.prop = 1
>>> a.prop
1
>>> b = B()
>>> b.prop = 1
Set 1
>>> b.prop
1
Run Code Online (Sandbox Code Playgroud)
使用普通属性,覆盖 getter、setter 或 deleter,然后在父类的属性中添加对fget
、fset
或 的调用。fdel
属性类型示例如示例 1 所示:
class A(object):
@property
def prop(self):
return self._prop
@prop.setter
def prop(self, v):
self._prop = v
class B(A):
@A.prop.setter
def prop(self, v):
A.prop.fset(self, v) # This is the call to the original set method
print('Set {}'.format(v))
Run Code Online (Sandbox Code Playgroud)
我认为第一个选项看起来更好,因为不需要调用超级属性的 fset