10

クラスの 1 つのインスタンス メソッドに属性を追加したいと考えています。この質問で与えられた答えを試しましたが、この答えは機能に対してのみ機能します-私が知る限り。

例として、次のようなことができるようにしたいと思います。

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

しかし、foo().bar() を呼び出すと、次のようになります。

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

これを行う目的は、'counter' 変数が bar() メソッドに対してローカルであることを印象づけようとすることと、さらに別の属性でクラスの名前空間が乱雑にならないようにすることです。これを行う方法はありますか?これを行うためのよりpythonicな方法はありますか?

4

5 に答える 5

8

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)

概要

ご覧のとおり、 のインスタンス レベルに移行すると、可読性が大幅に低下しましたcountercounterの一部であることを強調することの重要性を再評価することを強くお勧めします。barそれが本当に重要な場合barは、インスタンスが のインスタンスの一部になる独自のクラスを作成することを強くお勧めしますfoo。それほど重要でない場合は、通常の方法で行います。

class foo(object):
    def __init__(self):
        self.bar_counter = 0
    def bar(self):
        self.bar_counter += 1
        return self.bar_counter
于 2012-03-01T20:52:56.627 に答える
2

古い投稿を掘り下げて申し訳ありませんが、検索で出くわし、実際に解決策を持っている人を見つけました.

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

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

于 2012-12-26T17:57:10.493 に答える
0

すべてのインスタンスでカウンターを永続的にしたい場合は、次のようにしますが、これはまだ Pythonic ではありません。

class foo(object):
    def bar(self):
        self.bar.im_func.counter += 1
        return self.bar.im_func.counter
    bar.counter = 0
于 2012-03-01T20:35:30.250 に答える
0

__init__データ メンバーを初期化するメソッドが必要です。

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

データ値を関数に直接アタッチすることは明らかに非 Pythonic です。

于 2012-03-01T20:19:43.673 に答える