2012-03-01 9 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な方法がありますか?あなたは、データメンバを初期化する方法__init__必要

+0

'クラスレベル(すべてのインスタンスが現在のカウントを共有する)、またはインスタンスレベル(各インスタンスは1から始まります)ことcounter'べきでしょうか? –

+0

'counter'はインスタンスレベルでなければなりません – sbell

+0

この関連する質問は役に立つかもしれません(またはそうでないかもしれません):http://stackoverflow.com/questions/7034063/adding-attributes-the-instancemethods-in-python –

答えて

8

Python 3ではコードは機能しますが、Python 2ではメソッドがルックアップされるときにいくつかのラッピングが行われます。インスタンス

  • クラスクラスレベル:機能とcounterを保存する(直接、または変更可能なデフォルト使用して)しか機能の一つがあるので効果的にクラスレベルの属性になりを、どれくらいのインスタンスを所有していても(すべて同じ関数オブジェクトを共有しています)

  • インスタンスレベル:counterインスタンス・レベルは、あなたが(それは、通常の方法のように振る舞う)functools.partialでそれをラップし、その後、__init__で関数を作成し、そのインスタンスに保管しなければならない属性を作るために - 今すべてのインスタンスに1つの関数オブジェクトがあります。

クラスレベル

静的のような変数の慣例は、変更可能なデフォルトの引数を使用することです:

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'は完全な実装に近いところにはありません。これは読者のための練習として残されています。 :) –

+0

デフォルトの引数は一度しか評価されないので、クラスレベルです。 OPは、それがインスタンスレベルでなければならないという質問へのコメントで明らかになった。 –

+0

@ Series8217:それで、私は質問しました。答えは、インスタンスレベルでそれを行う方法を示すために更新されました。 –

0

:機能に直接データ値を取り付け

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

は明らかに非Python的です。

+0

私はこれを感謝しますが、私の目標は、(私の質問で述べた理由で)barメソッドにカウンタ変数を結びつけることです。私はあなたの答えを修正する: クラスのfoo(オブジェクト): デフ__init __(自己): self.bar.counter = 0 デフバー(自己): self.bar.counter + = 1 戻りself.bar .counter しかし、私は__init__呼び出しで同じAttributeErrorを受け取るようになりました。 – sbell

+0

要求されたOPのように 'counter'を' bar'に結びつけません。 –

+0

@EthanFurman:OPは、これを行うために "もっとpythonic"な方法を求めました。関数に直接データを添付することはPythonicの反対です。 –

0

すべてのインスタンスでカウンタを永続化したい場合は、次の操作を実行できますが、これはまだPythonicではありません。

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

申し訳ありませんが、古いポストを掘るが、私は私の検索でそれに出くわしたし、実際にソリューションを持つ人を見つけたために:それは本当に重要ではありません場合は、それを通常の方法を実行します。

ここには、あなたが抱えている問題と、あなたが望むことをするデコレータを作成する方法について説明するブログ記事があります。必要な機能を得るだけでなく、Pythonがこのように動作する理由を説明してくれます。

http://metapython.blogspot.com/2010/11/python-instance-methods-how-are-they.html

関連する問題