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='ジョン'
設定:ジョン
取得:ジョン
'ジョン'>> 名前
の削除注: 記述子はクラス レベルでのみインスタンス化できます。__init__() やその他のメソッドで記述子オブジェクトを作成してインスタンスごとに記述子を作成することはできません。
記述子を持つクラスによって使用されるプロパティ名は、インスタンスに格納されているプロパティ名よりも優先されます。記述子がインスタンスに値を格納するには、記述子自体が使用する名前とは異なる名前を選択する必要があります。
上記の例と同様、PERSON クラスの初期化 __init__ 関数がインスタンスの属性を設定するときに名前を使用することはできません。
データ記述子と非データ記述子:
クラスバインディング: 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) に注目してください。