@property デコレーターはメソッドをプロパティに変換して呼び出すことができます。Python の黒魔術である @property デコレーターの使用法を見てみましょう。
@property の用途は、表面的には何ですか?メソッドは属性の形式でアクセスされます
上記のコードは最も明確です。
class Circle(object): def __init__(self, radius): self.radius = radius @property def area(self): return 3.14 * self.radius ** 2 c = Circle(4) print c.radius print c.area
@property を追加した後、プロパティ Access.
として直接 c.area を定義できることがわかります。ここで問題が発生します。c.area が呼び出されるたびに計算されますが、これは CPU の無駄です。これは遅延プロパティです。
class lazy(object): def __init__(self, func): self.func = func def __get__(self, instance, cls): val = self.func(instance) setattr(instance, self.func.__name__, val) return val class Circle(object): def __init__(self, radius): self.radius = radius @lazy def area(self): print 'evalute' return 3.14 * self.radius ** 2 c = Circle(4) print c.radius print c.area print c.area print c.area
evalute' は一度だけ出力するので、@lazy のメカニズムをよく理解する必要があります。
ここで、lazy クラスには、順序の問題により、c.area が初めて実行されるとき、それが記述子であることを示します。 、まず c.__dict__ に移動します。見つからない場合は、クラス空間に移動して見つけます。Circle クラスには area() メソッドがあるため、__get__ によってインターセプトされます。
__get__ では、インスタンスの area() メソッドを使用して結果を計算し、同じ名前の属性をインスタンスに動的に追加して結果を割り当てます。つまり、c.__dict__ に追加します。
再度 c.area を実行すると、まず c.__dict__ にアクセスして見つけます。この時点ではすでに存在しているため、その必要はありません。 area() メソッドと __get__ を経由します。
注意
次のコード シナリオに注意してください。
コード スニペット 1:
class Parrot(object): def __init__(self): self._voltage = 100000 @property def voltage(self): """Get the current voltage.""" return self._voltage if __name__ == "__main__": # instance p = Parrot() # similarly invoke "getter" via @property print p.voltage # update, similarly invoke "setter" p.voltage = 12
コード スニペット 2:
class Parrot: def __init__(self): self._voltage = 100000 @property def voltage(self): """Get the current voltage.""" return self._voltage if __name__ == "__main__": # instance p = Parrot() # similarly invoke "getter" via @property print p.voltage # update, similarly invoke "setter" p.voltage = 12
コード 1 と 2 の違いは、
class Parrot(object):
python2 で個別にテストを実行する
フラグメント 1: 予想されるエラー メッセージ AttributeError : 属性を設定できないというメッセージが表示されます
フラグメント 2: 正しく実行します
python2 ドキュメントを参照してください。 @property は、対応する @voltage.setter を提供しません。フラグメント 2 のコードが実行エラーを引き起こす理由は、python2 ドキュメントで次の情報を見つけることができます:
BIF:
property([fget[ , fset[, fdel[, doc]]])
新しいスタイルのクラス (オブジェクトから派生したクラス) のプロパティ属性を返します。
Python2 では、クラスを定義するときに、組み込み型オブジェクトがデフォルトの基本クラスではないことがわかります。明確な説明 (コード スニペット 2)、私たちが定義する Parrot (コード スニペット 2) はオブジェクトを継承しません
オブジェクト クラスは、必要な @property 関数を提供するだけです。次の情報をドキュメント内で確認できます。 -style クラス
object から継承する任意のクラス。これには list や dict などのすべての組み込み型が含まれます。__slots__、記述子、プロパティ、__getattribute__() などの Python の新しい多機能機能を使用できるのは、新しいスタイルのクラスだけです。同時に、次のメソッドを通じて検証することもできます
class A: pass >>type(A) <type 'classobj'>
class A(object): pass >>type(A) <type 'type'>
返された 0de78ee0d3b407c99059b714f3837c5b から、f5ae6bbdf402bfea04a71faa8c02de77 であることがわかります。必要なオブジェクト タイプ (Python 3.0 はオブジェクト クラスをデフォルトの基本クラスとして使用するため、f5ae6bbdf402bfea04a71faa8c02de77 を返します)
Python バージョンの移行期間中の互換性の問題を考慮するため、コードを書くときは、クラスを定義する必要があると思います ファイルを書くときは、オブジェクトを明示的に定義するのが良い習慣です
最終的なコードは次のようになります:
class Parrot(object): def __init__(self): self._voltage = 100000 @property def voltage(self): """Get the current voltage.""" return self._voltage @voltage.setter def voltage(self, new_value): self._voltage = new_value if __name__ == "__main__": # instance p = Parrot() # similarly invoke "getter" via @property print p.voltage # update, similarly invoke "setter" p.voltage = 12
なお、
@propertyは2.6と3.0で追加され、2.5でも追加されていますこの機能がありません。以上がPythonデコレータのプロパティの使い方を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。