Python黒魔法@property装飾器の使用テクニック解析
4669 ワード
@propertyは何の役に立ちますか?表面的には、一つの方法を属性でアクセスすることである.上のコード、コードが一番はっきりしています.
areaはメソッドとして定義形式であるが,@propertyを加えると,直接c.areaとして属性としてアクセスできることがわかる.今問題が来て、(掘削機の技術のどの家が強いのではありません)、c.areaを呼び出すたびに、一度計算して、cpuを浪費して、どのようにして一度だけ計算することができますか?これがlazy propertyです.
「evalute」は一度しか出力されていないことがわかります.私の前のいくつかのブログを見たら、@lazyのメカニズムはよく理解できるはずです.ここでlazyクラスには_get__方法、説明はディスクリプタで、初めてc.areaを実行するとき、順序の問題で、先にc._dict__の中で探して、探し当てていないで、類の空間に行って探して、類のCircleの中で、area()方法があって、そこで_get__阻止するで_get__では、インスタンスのarea()メソッドを呼び出して結果を算出し、インスタンスに同じ名前のプロパティを動的に追加して結果を割り当てます.すなわち、c._dict__中去c.areaを再度実行する場合は、先にc._dict__探して、この時すでにあったため、area()の方法と__を通りませんget__はい.
注意:次のコードシーンに注意してください.
コードクリップ1:Python 2.6コード
コードクリップ2:Python 2.6コード
コード1、2の違いは
python 2.6で、テストフラグメント1を別々に実行します.予想されるエラーメッセージが表示されます.AttributeError:can't set attributeフラグメント2:正しく実行されます.
参照python 2.6ドキュメント,@propertyはready-only propertyを提供し,以上のコードは対応する@voltageを提供しない.setter、クリップ2のコードはpython 2でエラーを実行するように要求されます.6ドキュメントでは、次の情報を参照できます.
BIF: property([fget[, fset[, fdel[, doc]]]]) Return a property attribute for new-style classes (classes that derive from object). python 2にいたのか.6では、組み込み型objectはデフォルトのベースクラスではありません.クラスを定義するときに、明確な説明がなければ(コードクリップ2)、私たちが定義したParrot(コードクリップ2)はobjectを継承しません.
objectクラスは、ドキュメントで次の情報を調べるために必要な@property機能を提供しています.
new-style class Any class which inherits from object. This includes all built-in types like list and dict. Only new-style classes can use Python's newer, versatile features like __slots__, descriptors, properties, and __getattribute__().
Python 2.6コードも以下の方法で検証できます
Python 2.6コード
返されるのは、私たちが必要とするobjectタイプであることがわかります(python 3.0はobjectクラスをデフォルトのベースクラスとしているので、すべて返されます).
コードのpythonバージョンの移行期間の互換性の問題を考慮するために、classファイルを定義すべき時、objectを明示的に定義すべきで、良い習慣だと思います.
最後のコードは次のとおりです.
また,@propertyは2.6,3.0に追加され,2.5にはこの機能はない.
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
areaはメソッドとして定義形式であるが,@propertyを加えると,直接c.areaとして属性としてアクセスできることがわかる.今問題が来て、(掘削機の技術のどの家が強いのではありません)、c.areaを呼び出すたびに、一度計算して、cpuを浪費して、どのようにして一度だけ計算することができますか?これがlazy propertyです.
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クラスには_get__方法、説明はディスクリプタで、初めてc.areaを実行するとき、順序の問題で、先にc._dict__の中で探して、探し当てていないで、類の空間に行って探して、類のCircleの中で、area()方法があって、そこで_get__阻止するで_get__では、インスタンスのarea()メソッドを呼び出して結果を算出し、インスタンスに同じ名前のプロパティを動的に追加して結果を割り当てます.すなわち、c._dict__中去c.areaを再度実行する場合は、先にc._dict__探して、この時すでにあったため、area()の方法と__を通りませんget__はい.
注意:次のコードシーンに注意してください.
コードクリップ1:Python 2.6コード
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: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
コード1、2の違いは
class Parrot(object):
python 2.6で、テストフラグメント1を別々に実行します.予想されるエラーメッセージが表示されます.AttributeError:can't set attributeフラグメント2:正しく実行されます.
参照python 2.6ドキュメント,@propertyはready-only propertyを提供し,以上のコードは対応する@voltageを提供しない.setter、クリップ2のコードはpython 2でエラーを実行するように要求されます.6ドキュメントでは、次の情報を参照できます.
BIF: property([fget[, fset[, fdel[, doc]]]]) Return a property attribute for new-style classes (classes that derive from object). python 2にいたのか.6では、組み込み型objectはデフォルトのベースクラスではありません.クラスを定義するときに、明確な説明がなければ(コードクリップ2)、私たちが定義したParrot(コードクリップ2)はobjectを継承しません.
objectクラスは、ドキュメントで次の情報を調べるために必要な@property機能を提供しています.
new-style class Any class which inherits from object. This includes all built-in types like list and dict. Only new-style classes can use Python's newer, versatile features like __slots__, descriptors, properties, and __getattribute__().
Python 2.6コードも以下の方法で検証できます
class A:
pass
>>type(A)
Python 2.6コード
class A(object):
pass
>>type(A)
返されるのは、私たちが必要とするobjectタイプであることがわかります(python 3.0はobjectクラスをデフォルトのベースクラスとしているので、すべて返されます).
コードのpythonバージョンの移行期間の互換性の問題を考慮するために、classファイルを定義すべき時、objectを明示的に定義すべきで、良い習慣だと思います.
最後のコードは次のとおりです.
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にはこの機能はない.