ホームページ  >  記事  >  データベース  >  Python 記述子記述子(1)

Python 記述子記述子(1)

黄舟
黄舟オリジナル
2016-12-23 17:37:181172ブラウズ

Python 記述子は、管理プロパティを作成する方法です。属性がクエリされるたびに、アクションが発生します。このアクションのデフォルトは、取得、設定、または削除です。ただし、アプリケーションにはさらに多くの要件があり、より複雑なアクションを設計する必要がある場合があります。最善の解決策は、目的のアクションを実行する関数を作成し、プロパティにアクセスしたときにその関数が実行されるように指定することです。この機能を持つオブジェクト

を記述子と呼びます。記述子は、Python メソッド、バインド メソッド、スーパー、PRoperty、静的メソッド、およびクラスメソッドの実装の基礎です。

1. 記述子プロトコル

記述子は、属性値を表すオブジェクトであり、1 つ以上の __get__、__set__、__delete__ メソッドを実装することで、記述子を属性アクセス メカニズムにリンクでき、これらをカスタマイズすることもできます。 。

__get__(self,instance,own): 属性にアクセスし、属性の値を返すために使用されます。 Instance は記述子を使用するインスタンス オブジェクトであり、own はインスタンスが属するクラスです。クラスを通じてプロパティにアクセスする場合、インスタンスは None です。

__set__(self,instance,value): 属性値を設定します。

__delete__(self,instance): 属性値を削除します。

2. 記述子の実装方法

class Descriptor(object):

def __get__(self, instance, owner):

print 'getting:%s'%self._name
return self._name
def __set__(self,インスタンス、名前):
Print' 設定:%s'%name
self._name = name
def __delete __ (self, インスタンス):
Print 'deleting:%s'%seld._name
SS 人 (オブジェクト):
name = Descriptor()


非常に単純な記述子オブジェクトが生成されます。これで、Person オブジェクトの属性名の読み取り、設定、削除ができるようになります。 ;> p.name='ジョン'
設定:ジョン

>>> p.name

取得:ジョン

'ジョン'

>> 名前
の削除注: 記述子はクラス レベルでのみインスタンス化できます。__init__() やその他のメソッドで記述子オブジェクトを作成してインスタンスごとに記述子を作成することはできません。

記述子を持つクラスによって使用されるプロパティ名は、インスタンスに格納されているプロパティ名よりも優先されます。記述子がインスタンスに値を格納するには、記述子自体が使用する名前とは異なる名前を選択する必要があります。

上記の例と同様、PERSON クラスの初期化 __init__ 関数がインスタンスの属性を設定するときに名前を使用することはできません。

データ記述子と非データ記述子:

__get__ と __set__ が実装されている場合、それはデータ記述子であり、__get__ のみが実装されている場合、それは非データ記述子です。異なる効果は、上記の p のように、インスタンスを通じて属性に値を割り当てるときに、データ記述子が常にインスタンス

の属性実装を置き換え、非データ記述子にはセットが存在しないことです。 name = 'hello' ではありません。__set__ メソッドが再度呼び出され、インスタンス属性 p.name が直接 'hello' に設定されます。

もちろん、__set__ で AttributeError を発生させるだけの場合でも、データではない記述子を取得することになります。

記述子呼び出しメカニズム:

オブジェクトの属性 a.attr をクエリするとき、Python が attr が記述子オブジェクトであることを検出した場合、属性の読み取り方法はオブジェクト a によって異なります:

直接呼び出し: 最も単純な呼び出しは次のとおりです。直接使用します コードは記述子メソッド attr.__get__(a) を呼び出します

インスタンス バインディング: a がインスタンス オブジェクトの場合、メソッドを呼び出します: type(a).__dict__['attr'].__get__(a,type( a))

クラスバインディング: A がクラスオブジェクトの場合、メソッドを呼び出します: A.__dict__['attr'].__get__(None,A)

スーパーバインディング: a がスーパーインスタンスの場合、super(B ,obj).m () obj.__class__.__mro__ をクエリして B の基本クラス A を見つけ、A.__dict__['m'].__get__(obj,obj.__class__)

3 を実行します。

class TypedProperty(object):
def __init__(self,name,attr_type,default=None):
self.name='_'+name
self.type=attr_type
self.default=default if default else attr_type()
def __get__(self,instance,own):
return getattr(instance,self.name,self.default)
def __set__(self,instance,value):
isinstance(value,self.type):
raise TypeError,'%s である必要があります'%self.type
setattr(instance,self.name,value)
def __delete__(self,instance):
raise AttributeError('属性を削除できません')
class Foo(object):
name=TypedProperty('name',str)
num=TypedProperty('num',int,37)

上記の記述子は、name 属性が str type に設定されていない場合、または属性の型をチェックできます。 num が int 型ではない場合、エラーが報告されます:

>>> f.name=21
TypeError: Must be

属性の削除は禁止されています:

> >> del f.name
AttributeError: 属性

f.name を削除できません 非表示の呼び出し type(f).__dict__['name'].__get__(f,Foo) Foo.name.__get__( f,Foo)。

上記の記述子は実際には setattr(f,_name,value) を通じて f._name に保存され、num は f._num に保存されます。これが下線の理由でもあります。 descriptor 名前 name はインスタンス属性 name と競合し、記述子属性 f.name はインスタンス属性 f.name を上書きします。

上記は Python 記述子 descriptor (1) の内容です。さらに関連する内容については、PHP 中国語 Web サイト (www.php.cn) に注目してください。


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