pto*_*ato 13 python properties descriptor magic-methods
我正在尝试创建一个Python属性,其中就地添加由不同的方法处理,而不是检索值,添加另一个值并重新分配.因此,对于x对象上的属性o,
o.x += 5
Run Code Online (Sandbox Code Playgroud)
应该不同于
o.x = o.x + 5
Run Code Online (Sandbox Code Playgroud)
最终的价值o.x应该是相同的,以免混淆人们的期望,但我想让就地增加更有效率.(实际上,操作比简单添加需要更多的时间.)
我的第一个想法是在课堂上定义
x = property(etc. etc.)
x.__iadd__ = my_iadd
Run Code Online (Sandbox Code Playgroud)
但这引发了一个AttributeError,大概是因为property工具__slots__?
我的下一次尝试使用描述符对象:
class IAddProp(object):
def __init__(self):
self._val = 5
def __get__(self, obj, type=None):
return self._val
def __set__(self, obj, value):
self._val = value
def __iadd__(self, value):
print '__iadd__!'
self._val += value
return self
class TestObj(object):
x = IAddProp()
#x.__iadd__ = IAddProp.__iadd__ # doesn't help
>>> o = TestObj()
>>> print o.x
5
>>> o.x = 10
>>> print o.x
10
>>> o.x += 5 # '__iadd__!' not printed
>>> print o.x
15
Run Code Online (Sandbox Code Playgroud)
如您所见,__iadd__不会调用特殊方法.我无法理解为什么会这样,虽然我猜测对象__getattr__是以某种方式绕过它.
我怎样才能做到这一点?我没有得到描述符的意思吗?我需要一个元类吗?
__iadd__只会查找返回的值__get__.你需要使__get__(或属性getter)返回一个对象(或代理对象)__iadd__.
@property
def x(self):
proxy = IProxy(self._x)
proxy.parent = self
return proxy
class IProxy(int, object):
def __iadd__(self, val):
self.parent.iadd_x(val)
return self.parent.x
Run Code Online (Sandbox Code Playgroud)
+=线路中的操作员
o.x += 5
Run Code Online (Sandbox Code Playgroud)
被翻译成
o.x = o.x.__iadd__(5)
Run Code Online (Sandbox Code Playgroud)
右侧的属性查找转换为
o.x = IAddProp.__get__(TestObj2.x, o, TestObj2).__iadd__(5)
Run Code Online (Sandbox Code Playgroud)
可以看到,__iadd__()是在属性查找的返回值上调用的,所以需要__iadd__()在返回的对象上实现。