2013-07-04 72 views
1

我有一類具有這樣的特性:二傳手屬性的

class Foo(object): 
    def __init__(self): 
     self._bar = 'bar' 

    @property 
    def bar(self): 
     return self._bar 

    @bar.setter 
    def bar(self, value): 
     self._bar = value 

我實例化類,在字典中使用它,並賦予了新的價值屬性是這樣的:

f = Foo() 
d = {'x': f.bar} 
d['x'] = 'baz' 
print d['x'] # prints baz, as expected 
print f.bar # prints bar, not as expected 

爲什麼當我以這種方式使用它時,屬性的setter沒有被調用?

編輯:這visualization已經做了很多的事情更清楚:如果我理解正確的,什麼是存儲在字典不是對象Foo與屬性bar,但吸氣的返回值。對?

回答

3

當您做d = {'x': f.bar}時,您將字典的'x'值設置爲當前值f.bar ---創建字典時的值。每次您讀取字典值時(或每次設置字典值時都會設置它),它不會創建一個「鏈接」或參考,它會讀取f.bar。對象屬性值和字典值之間沒有關聯。 (這基本上就是你在編輯中所說的內容:在字典中存儲的是的值f.bar;該值不能「知道」它是通過讀取f.bar獲得的,所以它與任何將來的更改分離f.bar。)

沒有改變你使用對象/字典的方式來創建這樣的鏈接沒有真正的方法。也就是說,沒有辦法創建一個簡單的字典,所以d['x'] = 2實際上是f.bar = 2。你可以創建一個自定義的代理對象類來實現這一點,並使用它來代替字典。或者你可以讓字典持有的屬性名稱,並使用getattr/setattr讀/設定值:

d = {'x': 'bar'} 
getattr(f, d['x']) # gives the value of f.bar 
setattr(f, d['x'], 2) # sets f.bar = 2 

這不是從你的問題清楚你的更大的目標是使用此代碼是什麼,所以很難說什麼是合適的解決方案。

+0

我想解決的問題是:我有一個需要修改屬性的對象列表。我把它們全部放在字典中,以便輕鬆訪問它們。我現在使用了一個簡單的if/else結構,它不那麼簡潔,但是可以工作:-) – BioGeek

1

當同一個鍵被使用兩次時,字典覆蓋它們的值。

>>> test_dict = {'a': 1, 'b': 2, 'c': 3} 
>>> test_dict['a'] 
1 
>>> test_dict['a'] = 5 
>>> test_dict 
{'a': 5, 'c': 3, 'b': 2} 

在你的代碼

f = Foo() 
d = {'x': f.bar} # map 'x' to f.bar - and your getter property is invoked 
d['x'] = 'baz' # remap 'x' to baz 
print d['x'] # prints baz, as expected 
print f.bar # prints bar, again getter is invoked here 

編輯:

如果我理解正確的,什麼是存儲在字典不是對象美孚與屬性欄,但返回值的返回值。對?

是的,吸氣劑可用於執行某些操作。例如,假設你需要第一個字母大寫的欄,你可以修改你的數據並把它返回給getter。

@property 
def bar(self): 
    return self._bar.capitalize() 

類似的setter可以用於健全性測試。說你不需要串稱爲「愚蠢的」存儲在您的數據 - 你可以不喜歡

@bar.setter 
def bar(self, value): 
    if value == 'stupid': 
     raise ValueError("Stupid not allowed!") 
    self._bar = value 

基本上,你需要記住的是,當值被設置,setter被調用什麼,當檢索到該值時,調用getter。在你的代碼中,setter從不被調用。

+0

感謝您對getter和setter的更多解釋。 – BioGeek