2012-03-01 82 views
8

我想在我的一個類中爲實例方法添加屬性。我試過this question給出的答案,但這個答案只適用於函數 - 據我所知。將屬性添加到Python中的實例方法

舉個例子,我希望能夠做這樣的事情:

class foo(object): 
    ... 
    def bar(self): 
     self.bar.counter += 1 
     return self.bar.counter 
    bar.counter = 1 
    ... 

,但是,當我調用foo()巴()我得到:

AttributeError: 'instancemethod' object has no attribute 'counter' 

我的目標這樣做的目的是試圖說明'counter'變量是bar()方法的局部變量,也是爲了避免使用另一個屬性混淆我的類名稱空間。有沒有辦法做到這一點?是否有更多pythonic這樣做?

+0

應該'counter'是一流的水平(所有實例共享當前計),或實例級別(每個實例會從1開始)? – 2012-03-01 21:50:34

+0

'計數器'應該是實例級別 – sbell 2012-03-01 21:54:30

+0

此相關的問題可能(或可能不會)有所幫助:http://stackoverflow.com/questions/7034063/adding-attributes-the-instancemethods-in-python – 2012-03-01 22:11:10

回答

8

在Python 3中,你的代碼可以工作,但是在Python 2中,當查找方法時會發生一些包裝。

類VS實例

  • 類級別:存儲counter用函數(直接,或通過使用一個可變的默認值)有效地使得一個類級別屬性,因爲這裏只有永遠該函數的一個,不管你有多少個實例(它們都共享相同的函數對象)。

  • 實例級別:使counter實例級別屬性必須在__init__創建功能,然後用functools.partial包起來(因此它的行爲像一個正常的方法),然後將其存儲在實例 - 現在你每個實例都有一個函數對象。

職業等級

一個靜態類變量上通行的做法是使用可變默認參數:如果你希望它是更漂亮,你可以定義自己的可變

class foo(object): 
    ... 
    def bar(self, _counter=[0]): 
     _counter[0] += 1 
     return _counter[0] 

集裝箱:

class MutableDefault(object): 
    def __init__(self, start=0): 
     self.value = start 
    def __iadd__(self, other): 
     self.value += other 
     return self 
    def value(self): 
     return self.value 

和改變,像這樣的代碼:

class foo(object): 
    def bar(self, _counter=MutableDefault()): 
     _counter += 1 
     return _counter.value 

實例級別

from functools import partial 

class foo(object): 
    def __init__(self): 
     def bar(self, _counter=MutableDefault(1)): # create new 'bar' each time 
      value = _counter.value 
      _counter += 1 
      return value 
     self.bar = partial(bar, self) 

摘要

正如你所看到的,可讀性移動到實例級別counter當把一個嚴重的打擊。我強烈建議你重新強調一下counterbar的一部分的重要性,並且如果它真的很重要,可能使bar是其自己的類,其實例成爲foo的實例的一部分。如果不是真的很重要,這樣做的正常方式:

class foo(object): 
    def __init__(self): 
     self.bar_counter = 0 
    def bar(self): 
     self.bar_counter += 1 
     return self.bar_counter 
+0

請注意,'MutableDefault'不是接近完整實現的地方 - 這是讀者的練習。 :) – 2012-03-01 20:57:23

+0

默認參數只評估一次,所以它是類級別的。 OP在對該問題的評論中澄清說它應該是實例級的。 – 2012-03-01 22:09:57

+0

@ Series8217:是的,這就是爲什麼我問這個問題 - 更新答案以顯示如何在實例級別執行此操作。 – 2012-03-01 23:25:17

0

您需要一個__init__方法來初始化數據成員:

class foo(object): 
    def __init__(self): 
     self.counter = 0 
    def bar(self): 
     self.counter += 1 
     return self.counter 

直接附加的數據值的功能是斷然非Python化。

+0

我很欣賞這一點,但我的目標是將計數器變量綁定到條形方法(出於我在我的問題中提到的原因)。我修改你的答案: 類Foo(對象): 高清__init __(個體經營): self.bar.counter = 0 高清條(個體經營): self.bar.counter + = 1 回報self.bar .counter 但現在我在__init__調用中得到相同的AttributeError – sbell 2012-03-01 20:25:53

+0

不像請求的OP那樣將'counter'綁定到'bar'。 – 2012-03-01 20:45:34

+0

@EthanFurman:OP要求採取「更pythonic」的方式來做到這一點。直接將數據附加到函數與Pythonic相反。 – 2012-03-01 20:46:59

0

如果您希望計數器在所有實例中保持不變,您可以執行以下操作,但這仍然不是Pythonic。

class foo(object): 
    def bar(self): 
     self.bar.im_func.counter += 1 
     return self.bar.im_func.counter 
    bar.counter = 0 
相關問題