148

@propertyPythonでの使い方に興味があります。私はPythonのドキュメントを読みましたが、私の意見では、そこにある例は単なるおもちゃのコードです:

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

_xプロパティデコレータで塗りつぶされたものをラップすることで得られる利点がわかりません。次のように実装しないのはなぜですか:

class C(object):
    def __init__(self):
        self.x = None

プロパティ機能は、場合によっては役立つかもしれないと思います。でもいつ?誰かが私にいくつかの実例を教えてもらえますか?

4

10 に答える 10

94

他の例としては、設定された属性の検証/フィルタリング(強制的に範囲内または許容可能にする)や、複雑または急速に変化する用語の遅延評価があります。

属性の背後に隠された複雑な計算:

class PDB_Calculator(object):
    ...
    @property
    def protein_folding_angle(self):
        # number crunching, remote server calls, etc
        # all results in an angle set in 'some_angle'
        # It could also reference a cache, remote or otherwise,
        # that holds the latest value for this angle
        return some_angle

>>> f = PDB_Calculator()
>>> angle = f.protein_folding_angle
>>> angle
44.33276

検証:

class Pedometer(object)
    ...
    @property
    def stride_length(self):
        return self._stride_length

    @stride_length.setter
    def stride_length(self, value):
        if value > 10:
            raise ValueError("This pedometer is based on the human stride - a stride length above 10m is not supported")
        else:
            self._stride_length = value
于 2011-06-10T09:06:20.380 に答える
81

簡単なユースケースの1つは、読み取り専用のインスタンス属性を設定することです。Pythonで変数名を1つのアンダースコアでリードすると_x、通常はプライベート(内部使用)を意味しますが、インスタンス属性を読み取り、書き込みを行わないようにしたい場合があります。これに使用できるようpropertyにします。

>>> class C(object):

        def __init__(self, x):
            self._x = x

        @property
        def x(self):
            return self._x

>>> c = C(1)
>>> c.x
1
>>> c.x = 2
AttributeError        Traceback (most recent call last)

AttributeError: can't set attribute
于 2011-06-10T08:55:58.647 に答える
22

非常に実用的な使い方については、この記事をご覧ください。要するに、Python で明示的な getter/setter メソッドを通常どのように捨てることができるかを説明しています。ある段階でそれらが必要になった場合propertyは、シームレスな実装に使用できるからです。

于 2011-06-10T08:58:22.467 に答える
16

私がこれを使用したことの1つは、データベースに格納されている、検索が遅いが変更されない値をキャッシュすることです。これは、属性が計算またはオンデマンドでのみ実行したいその他の長い操作(データベースチェック、ネットワーク通信など)を必要とする状況に一般化されます。

class Model(object):

  def get_a(self):
    if not hasattr(self, "_a"):
      self._a = self.db.lookup("a")
    return self._a

  a = property(get_a)

これは、特定のページビューにこの種の特定の属性が1つだけ必要なWebアプリでしたが、基になるオブジェクト自体にそのような属性がいくつかある可能性があります。構築時にすべてを初期化するのは無駄であり、プロパティを使用すると柔軟に対応できます。属性は怠惰であり、そうではありません。

于 2011-06-10T09:05:32.663 に答える
7

プロパティは、特定のフィールドを操作してミドルウェアの計算を行う方法をより詳細に制御できる、フィールドの単なる抽象化です。頭に浮かぶいくつかの使用法は、検証と事前の初期化とアクセス制限です

@property
def x(self):
    """I'm the 'x' property."""
    if self._x is None:
        self._x = Foo()

    return self._x
于 2011-06-10T08:59:05.760 に答える
6

setter と getter を使用するプロパティのもう 1 つの優れた機能は、属性に対して OP= 演算子 (+=、-=、*= など) を引き続き使用できる一方で、検証、アクセス制御、キャッシュなどを引き続き保持できることです。セッターとゲッターが提供します。

たとえばPerson、 settersetage(newage)と getterを使用してクラスを作成したgetage()場合、年齢をインクリメントするには、次のように記述する必要があります。

bob = Person('Robert', 25)
bob.setage(bob.getage() + 1)

しかしage、プロパティを作成した場合は、よりクリーンに書くことができます:

bob.age += 1
于 2016-06-27T00:01:07.503 に答える
5

あなたの質問に対する簡単な答えは、あなたの例ではメリットがないということです。おそらく、プロパティを含まないフォームを使用する必要があります。

プロパティが存在する理由は、コードが将来変更され、データをさらに処理する必要が突然発生した場合です。値のキャッシュ、アクセスの保護、外部リソースのクエリなど、クラスを簡単に変更してゲッターを追加できます。インターフェイスを変更せずにデータのセッターを使用できるため、そのデータがアクセスされるコード内のあらゆる場所を見つけて、それも変更する必要はありません。

于 2014-07-15T13:39:05.217 に答える
4

多くの人が最初は気付かないことは、プロパティの独自のサブクラスを作成できるということです。これは、読み取り専用のオブジェクト属性または読み取りと書き込みはできるが削除できない属性を公開するのに非常に役立つことがわかりました。また、オブジェクト フィールドへの変更の追跡などの機能をラップする優れた方法でもあります。

class reader(property):
    def __init__(self, varname):
        _reader = lambda obj: getattr(obj, varname)
        super(reader, self).__init__(_reader)

class accessor(property):
    def __init__(self, varname, set_validation=None):
        _reader = lambda obj: getattr(obj, varname)
        def _writer(obj, value):
            if set_validation is not None:
               if set_validation(value):
                  setattr(obj, varname, value)
        super(accessor, self).__init__(_reader, _writer)

#example
class MyClass(object):
   def __init__(self):
     self._attr = None

   attr = reader('_attr')
于 2014-01-10T19:49:52.047 に答える