我正在使用Python描述符在主机对象上创建复杂的接口。
当我运行这样的代码时,我不会直截了当地得到这样的行为:
class Accessor(object):
def __get__(self,inst,instype):
self._owner = inst
return self
def set(self,value):
self._owner._val = value
def get(self):
if hasattr(self._owner,'_val'):
return self._owner._val
else: return None
class TestClass(object):
acc = Accessor()
source = TestClass()
destination = TestClass()
source.acc.set('banana')
destination.acc.set('mango')
destination.acc.set(source.acc.get())
print destination.acc.get()
# Result: mango
在这种情况下,我希望destination.acc.get()返回' banana'而不是'芒果'。
但是,如果代码被重构,则意图(将_val从' source'复制到' destination')起作用:
val = source.acc.get()
destination.acc.set(val)
print destination.acc.get()
# Result: banana
是什么打击了客户'如果描述符在一行中使用而不是分成不同的行,则引用通过 get 传递?有没有办法得到我直觉所期望的行为?
非常感谢提前。
ķ
答案 0 :(得分:0)
您的实施ALMOST有效。它的问题出现在destination.acc.set(source.acc.get())
。会发生的事情是它首先查找destination.acc
,将_owner
设置为destination
,但在它可以调用set()
之前,它必须解析参数{{1最终将source.acc.get()
' s acc
设置为_owner
。
由于source
和destination.acc
是同一个对象(描述符存储在类中,而不是实例上),因此您在{{1}之后调用source.acc
}}设置为set()
。这意味着您需要设置_owner
,而不是source
。
获得您直觉所期望的行为的方法是摆脱您的source._val
和destination._val
并将其替换为get()
和set()
,以便您的描述符可以用于使用描述符的原因。
__get__()
然后您可以将客户端代码重写为
__set__()
描述符的要点是使用看起来像简单属性使用的隐式getter和setter调用来删除。如果你仍想在class Accessor(object):
def __get__(self, instance, owner): # you should use the conventional parameter names
if instance is None:
return self
else:
return instance._val
def __set__(self, instance, value):
instance._val = value
上使用你的getter和setter,那么就不要让它成为描述符。这样做:
source = TestClass()
destination = TestClass()
source.acc = 'banana'
destination.acc = 'mango'
destination.acc = source.acc
print destination.acc
然后重写Accessor
看起来更像这样:
class Accessor(object):
def get(self):
if hasattr(self, '_val'):
return self._val
else:
return None
def set(self, val):
self._val = val
之后,您的原始客户端代码将起作用。
答案 1 :(得分:0)
我已经说过为什么它不适用于我的其他帖子。所以,这是一种在保留get()
和set()
方法的同时使用描述符的方法。
class Accessor(object):
def __get__(self, instance, owner):
if instance is None:
return self
elif not hasattr(instance, '_val'):
setattr(instance, '_val', Acc())
return getattr(instance, '_val')
class Acc(object):
def get(self):
if hasattr(self, '_val'):
return self._val
else:
return None
def set(self, val):
self._val = val
class TestClass(object):
acc = Accessor()
诀窍是将get()
和set()
方法移动到返回的新类,而不是从描述符返回self
。