2015-06-23 96 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