ホームページ  >  記事  >  バックエンド開発  >  Pythonデコレータのプロパティの使い方を詳しく解説

Pythonデコレータのプロパティの使い方を詳しく解説

巴扎黑
巴扎黑オリジナル
2017-08-18 17:11:532267ブラウズ

@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 &#39;classobj&#39;>
class A(object): 
  pass 
>>type(A) 
<type &#39;type&#39;>

返された 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 サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。