Python での @property デコレーターの注意が必要な使用法 (コード例)

不言
リリース: 2018-11-23 16:45:37
転載
1785 人が閲覧しました

この記事では、Python での @property デコレーターの技術的な使用法 (コード例) を紹介します。これは一定の参考価値があります。必要な友人は参照できます。お役に立てば幸いです。

@プロパティ デコレータはメソッドをプロパティに変換して呼び出すことができます。Python の黒魔術 @プロパティ デコレータの使用スキル分析を見てみましょう

@ 属性は何に使用されますか?表面的には、メソッドは属性としてアクセスされているように見えます。

上記のコード

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 を追加すると、プロパティとして c.area に直接アクセスできます。

ここで疑問が生じます。c.area が呼び出されるたびに、計算が 1 回行われます。CPU の無駄です。どうすれば 1 回だけ計算できるでしょうか?これは怠惰の性質です。

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」は 1 回しか出力されないため、@Lazy のメカニズムをよく理解しておく必要があります。

ここでは、遅延クラスには、記述子であることを示す __get__ メソッドがあります。c.area が初めて実行されるとき、順序の問題により、最初に Ç.__dict__ で検索されます。見つからない場合は、クラス空間に移動して見つけてください。クラス サークル内には area() メソッドがあるため、__get__ によってインターセプトされます。

__get__ では、インスタンスのregion() メソッドを呼び出して結果を計算し、同じ名前の属性をインスタンスに動的に追加して結果をそれに割り当てます。つまり、それを Ç に追加します。 __ 辞書__。

c.area を再度実行するときは、まず Ç.__ 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: Unable toプロパティを設定するよう求められます

フラグメント 2: 正しい操作

Python2 ドキュメントを参照してください。@property は読み取り専用属性を提供します。上記のコードは、対応する @voltage.setter を提供しません。フラグメント 2 のコードが実行エラーを表示するのは当然です。python2 ドキュメントには次の情報があります:

BIF:

property([fget[,fset[, fdel[,doc]]])

新しいスタイル クラス (Object から派生したクラス) の属性プロパティを返します。

Python2 では、組み込み型オブジェクトがデフォルトの基本クラスではないことが判明しました。クラスを定義するときに明確な説明がない場合 (コード スニペット 2)、定義した Parrot (コード スニペット 2) ) は Object を継承しません

オブジェクト クラスは、必要な @property 関数を提供するだけです。ドキュメントには次の情報があります:

新しいスタイルのレッスン

任意のクラスこれは 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;>
ログイン後にコピー

返された から、次のことがわかります。 は必要なオブジェクト タイプです (Python 3.0 はオブジェクト クラスをデフォルトの基本クラスとして使用するため、すべてが を返します)

考慮するために移行期間中の Python バージョンのコードの互換性について質問です。クラス ファイルを定義するときは、良い習慣としてオブジェクトを明示的に定義する必要があると思います。

最終的なコードは次のようになります:

ああ、

以上がPython での @property デコレーターの注意が必要な使用法 (コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:segmentfault.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート