2015-06-23 20 views
0

我正在使用Python描述符在主机对象上创建复杂的接口。不明确的描述符调用者参考评估

我不明白的问题,当我运行的代码,例如这样我会直觉地想到:

我希望在这种情况下destination.acc.get()返回“香蕉”,不是'芒果'。

然而,意向(复制从“源”到“目标” _Val)如果代码被重构像这样工作的:

val = source.acc.get() 
destination.acc.set(val) 
print destination.acc.get() 
# Result: banana 

什么是是,打破了“客户”参考穿过得到如果描述符被用于单行而不是单独的行?有没有一种方法可以获得我直觉上期待的行为?

非常感谢提前。

K

回答

0

您的实施ALMOST工作。它的问题出现在destination.acc.set(source.acc.get())。什么情况是,它首先查找destination.acc,将设置_ownerdestination,但它可以调用set()之前,它必须解决的参数,source.acc.get(),这最终会设置acc_ownersource

由于destination.accsource.acc是同一个对象(描述符存放的类,而不是实例),你是它的_owner设置为source后调用它set()。这意味着你正在设置source._val,而不是destination._val

,让你会直觉地想到行为的方式是摆脱或你的get()set()__get__()__set__()取代他们,让您的描述符,可用于其原因是使用的描述符。

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 

然后,你可以重写你的客户端代码

source = TestClass() 
destination = TestClass() 

source.acc = 'banana' 
destination.acc = 'mango' 

destination.acc = source.acc 
print destination.acc 

描述的重点是去除明确的getter和setter与看起来像简单的属性使用隐式调用者。如果你仍然想在Accessor上使用你的getter和setter,那么不要把它作为描述符。做到这一点,而不是:

class Accessor(object): 
    def get(self): 
     if hasattr(self, '_val'): 
      return self._val 
     else: 
      return None 
    def set(self, val): 
     self._val = val 

然后重写TestClass看起来更像是这样的:

class TestClass(object): 
    def __init__(self): 
     self.acc = Accessor() 

之后,你原来的客户端代码会工作。

+0

谢谢。我正在使用Autodesk Maya中的PyMEL接口,我必须使用这种特定模式有两个原因:a)我知道基于__init __的方法,但是在__init__上实例化“接口”对象的执行速度要慢得多至少在Maya解释器中使用描述符。 b).get()/ .set()语法是一个PyMEL约定,我想坚持下去。我意识到它是非描述符的。 –

+0

PyMEL系统中的现有类是否使用这样的描述符?还是他们使用“基于init”的方法?我发现很难相信,如果他们使用描述符,他们会维持这个惯例。 –

+0

我有一些工作。我只需要到适当的键盘输入:)。这将是几个小时,因为我现在正准备上班。 –

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