Python 3 ではコードは機能しますが、Python 2 ではメソッドがルックアップされるときにいくつかのラッピングが行われます。
クラスとインスタンス
クラス レベル:counter
関数を使用して (直接、または変更可能な既定値を使用して) 格納すると、インスタンスの数に関係なく、関数は 1 つしか存在しないため、効果的にクラス レベルの属性になります (それらはすべて同じ関数オブジェクトを共有します)。 )。
インスタンス レベル:counter
インスタンス レベルの属性を作成するには、 で関数を作成し、 (通常のメソッドのように動作するように)__init__
でラップfunctools.partial
し、インスタンスに格納する必要があります。これで、インスタンスごとに 1 つの関数オブジェクトができました。
クラスレベル
static に似た変数に対して受け入れられている方法は、変更可能なデフォルト引数を使用することです。
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
。counter
の一部であることを強調することの重要性を再評価することを強くお勧めします。bar
それが本当に重要な場合bar
は、インスタンスが のインスタンスの一部になる独自のクラスを作成することを強くお勧めしますfoo
。それほど重要でない場合は、通常の方法で行います。
class foo(object):
def __init__(self):
self.bar_counter = 0
def bar(self):
self.bar_counter += 1
return self.bar_counter