1

Pythonでクラスがあるとしましょう:

class Foo(object):
    a = 1
    b = 2

「b」ではなく「a」にアクセスするときに、いくつかの追加処理を行いたいと考えています。たとえば、私がやりたいことは、属性の値をインクリメントすることだとしましょう。

> f = Foo()
> f.a # Should output 2
> f.a # Should output 3
> f.a # Should output 4
> f.b # Should output 2, since I want the extra behavior just on 'a'

__getattr__ や __getattribute__ を経由する方法があるように感じますが、私にはそれがわかりませんでした。

余分なものは何でもかまいませんが、必ずしも属性に関連している必要はありません (print 'Hello world' など)。

ありがとう。

4

2 に答える 2

8

探しているのは、デコレータとしてうまく使用できるプロパティです。

class Foo(object):
    _a = 2

    @property
    def a(self):
        Foo._a += 1
        return Foo._a - 1

    b = 2

にアクセスしようとするたびに関数が呼び出されfoo_instance.a、返された値が属性の値として使用されます。属性が設定されたときに新しい値で呼び出されるセッターも定義できます。

これは、インスタンスからのみアクセスするクラス属性の奇妙な設定が必要であると想定しています。(_aそして、bここではクラスに属しています-つまり、質問のように、すべてのインスタンスで共有される変数は1つだけです)。ただし、プロパティは常にインスタンス所有です。最も可能性の高いケースは、実際に必要な場合です。

class Foo(object):
    def __init__(self):
        self._a = 2
        self.b = 2

    @property
    def a(self):
        self._a += 1
        return self._a - 1

それらはインスタンス属性です。

于 2012-11-13T20:47:51.503 に答える
3

@propertyクラス変数に相当するものが本当に必要な場合は、記述子を自分で作成する必要があります。

通常のインスタンス変数を作成する方法については、Lattyware の回答を参照し、それらの 1つ@property.

しかし、これを行う方法は次のとおりです。

class IncrementOnGetDescriptor(object):
    def __init__(self, initval=None):
        self.val = initval
    def __get__(self, obj, objtype):
        self.val += 1
        return self.val - 1
    def __set__(self, obj, val):
        self.val = val

class Foo(object):
    a = IncrementOnGetDescriptor(2)
    b = 2

これでテストできます:

>>> f = Foo()
>>> f.a
2
>>> Foo.a
3
>>>> f.a
4

これを@classpropertyデコレータに変換することは、読者の課題として残されています。

PS、これはまだ通常のクラス変数とまったく同じではありません。設定Foo.a = 10は、魔法の自動インクリメント値を通常の に置き換えますが、10設定は、インスタンス変数を に格納する代わりにfoo.a = 10、自動インクリメントでクラスを更新します。(通常は自動インクリメントのマジック変数を読み取り専用にする必要があるため、私はもともとraise メソッドを持っていましたが、対処しなければならないすべての問題を示すために、より複雑なバージョンを表示することにしました。)10f__set__AttributeError

于 2012-11-13T21:08:47.103 に答える