描述符调用者参考评估不清楚

时间:2015-06-23 17:44:16

标签: python descriptor

我正在使用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 传递?有没有办法得到我直觉所期望的行为?

非常感谢提前。

ķ

2 个答案:

答案 0 :(得分:0)

您的实施ALMOST有效。它的问题出现在destination.acc.set(source.acc.get())。会发生的事情是它首先查找destination.acc,将_owner设置为destination,但在它可以调用set()之前,它必须解析参数{{1最终将source.acc.get()' s acc设置为_owner

由于sourcedestination.acc是同一个对象(描述符存储在类中,而不是实例上),因此您在{{1}之后调用source.acc }}设置为set()。这意味着您需要设置_owner,而不是source

获得您直觉所期望的行为的方法是摆脱您的source._valdestination._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