ホームページ  >  記事  >  バックエンド開発  >  Python 黒魔術 @propertydecorator の使用スキルの分析

Python 黒魔術 @propertydecorator の使用スキルの分析

高洛峰
高洛峰オリジナル
2017-01-23 14:50:321188ブラウズ

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

ここで問題が発生します (どの掘削機テクノロジーが優れているかということではありません)。 c.area が呼び出されるたびに、計算が 1 回行われます。 CPU の無駄、一度だけ計算する方法は? @lazy のメカニズムの説明。
ここで、lazy クラスには、それが記述子であることを示す __get__ メソッドがあり、順序の問題により、最初に c.__dict__ が検索されます。見つからない場合は、クラス空間に移動して検索します。Circle クラスには area() メソッドがあるため、__get__ でインスタンスの area() メソッドを呼び出して動的に結果を計算します。同じ名前の属性をインスタンスに追加し、結果をそれに割り当てます。つまり、c.__dict__ に追加されます。

c.area を再度実行するときは、この時点ではすでに存在しているため、最初に c.__dict__ に移動します。したがって、area() メソッドと __get__ は経由しません。 Python2.6 コード

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


コード 1 と 2 の違いは

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

python2.6 では、テストを個別に実行します
フラグメント 1: 予想されるエラー メッセージ AttributeError: can't set Attribute が表示されますプロンプトが表示されます

フラグメント 2: 正しく実行します


python2.6 ドキュメントを参照してください。@property は、対応する @voltage.setter を提供しません。これは当然のことです。 Python2.6 ドキュメントでは、次の情報を見つけることができます:

BIF:

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

new のプロパティ属性を返す-style クラス (オブジェクトから派生するクラス)

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


そして、オブジェクト クラスは必要な @property 関数を提供するだけです。次の情報が見つかりました:

新しいスタイル クラス

継承する任意のクラス。これには、list や dict などのすべての組み込み型が含まれます。__slots__、記述子、プロパティ、__getattribute__() などの Python の新しい多機能機能を使用できるのは、新しいスタイルのクラスのみです。

同時に、検証することもできます。

Python 2.6 コード

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



Python 2.6 コード

class Parrot(object):

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

Python版のコードでは、クラスファイルを定義する際に、オブジェクトを明示的に定義するのが良い習慣だと思います

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

class A:
  pass
 
>>type(A)
<type &#39;classobj&#39;>


さらに、 @property を追加しました2.6と3.0、2.5にはこの機能はありません。

Python のブラック マジック @プロパティ デコレータのヒントや関連記事をさらに詳しく知りたい場合は、PHP 中国語 Web サイトに注目してください。

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