Python 29記述子
目次
ディスクリプタ定義
記述子の種類と優先度
記述子の適用
記述子+クラスアクセラレータ(Personクラスにクラスプロパティを追加)
記述子による@propertyのカスタマイズ
property補充
ディスクリプタ定義
記述子は一種で、私たちは実現しました.get__()、__set__()と_delete__()のいずれかのメソッドのクラスを記述子と呼ぶ.
記述子の役割はクラスのプロパティをエージェントするために使用されます.記述子は使用されるクラスの構造関数で定義できません.クラスのプロパティとして定義するしかありません.クラスにのみ属し、インスタンスには属しません.インスタンスとクラスの辞書を参照して確認できます.
記述子はほとんどのPythonクラスの特性の中で最下層のデータ構造を実現する実現手段であり,我々がよく使用する@classmethod,@staticmethd,@property,さらには_slots__などのプロパティは記述子によって実現されます.これは多くの高度なライブラリとフレームワークの重要なツールの一つであり、装飾器やメタクラスの大規模なフレームワークに使用される非常に重要なコンポーネントです.
記述子および参照記述子クラスのコードの例を次に示します.
class Descriptors:
def __init__(self, key, value_type):
self.key = key
self.value_type = value_type
def __get__(self, instance, owner):
print("===> Descriptors get")
return instance.__dict__[self.key]
def __set__(self, instance, value):
print("===> Descriptors set")
if not isinstance(value, self.value_type):
raise TypeError(" %s %s" % (self.key, self.value_type))
instance.__dict__[self.key] = value
def __delete__(self, instance):
print("===> Descriptors delete")
instance.__dict__.pop(self.key)
class Person:
name = Descriptors("name", str)
age = Descriptors("age", int)
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("xu", 15)
print(person.__dict__)
person.name
person.name = "xu-1"
print(person.__dict__)
# :
# ===> Descriptors set
# ===> Descriptors set
# {'name': 'xu', 'age': 15}
# ===> Descriptors get
# ===> Descriptors set
# {'name': 'xu-1', 'age': 15}
ここで、Descriptorsクラスは記述子であり、Personは記述子を使用するクラスである.
クラスの_dict__属性はクラスの組み込み属性であり、クラスの静的関数、クラス関数、一般関数、グローバル変数、およびいくつかの組み込み属性はクラスに配置されています.dict__で行ないます.
記述子の変数を出力すると、記述子の__が呼び出されます.get__メソッドでは、記述子変数を設定すると、記述子の__が呼び出されます.set__方法.
記述子の種類と優先度
記述子は、データ記述子と非データ記述子に分けられる.
少なくとも内蔵されています_set__()と_get__()メソッドの記述子をデータ記述子と呼ぶ.除_を実現しましたset__()以外の方法の記述子を非データ記述子と呼ぶ.
記述子の優先度の高低順:クラス属性>データ記述子>インスタンス属性>非データ記述子>見つからない属性トリガ_getattr__().
上記の「記述子定義」章の例では、インスタンスpersonの属性優先度がデータ記述子Descriptorsより低いため、値の付与または取得中に記述子のメソッドが呼び出されます.
class Descriptors:
def __get__(self, instance, owner):
print("===> Descriptors get")
def __set__(self, instance, value):
print("===> Descriptors set")
def __delete__(self, instance):
print("===> Descriptors delete")
class University:
name = Descriptors()
def __init__(self, name):
self.name = name
クラスプロパティ>データ記述子(Class Properties>Data Descriptor)
# >
# , XX-XX
print(University.__dict__) # {..., 'name': <__main__.descriptors object="" at="">,}
University.name = "XX-XX"
print(University.__dict__) # {..., 'name': 'XX-XX',}
データ記述子>インスタンス属性(Data Descriptor>Instance Attributes)
# >
# , name , , 'name': <__main__.descriptors object="" at="">
# Descriptors __set__; un.name __get__
print(University.__dict__)
un = University("xx-xx")
un.name
# :
# {..., 'name': <__main__.descriptors object="" at="">,}
# ===> Descriptors set
# ===> Descriptors get
次に、テストインスタンス属性、非データ記述子、_getattr__ コードの使用
class Descriptors:
def __get__(self, instance, owner):
print("===>2 Descriptors get")
class University:
name = Descriptors()
def __init__(self, name):
self.name = name
def __getattr__(self, item):
print("---> item = {}".format(item))
インスタンスプロパティ>非データ記述子(Instance Properties>Non Data Descriptor)
# >
# , name, un2.name , name
un2 = University("xu2")
print(un2.name) # xu Descriptors __get__
print(un2.__dict__) # {'name': 'xu2'}
un2.name = "xu-2"
print(un2.__dict__) # {'name': 'xu-2'}
非データ記述子>見つからない属性トリガ_getattr__
# > __getattr__
# name1 __getattr__
un3 = University("xu3")
print(un3.name1) # ---> item = name1
(上記参照:https://blog.csdn.net/chenzhanhai/article/details/84350403 )
記述子の適用
記述子を使用してデータ型を検証する
class Typed:
def __init__(self, key, type):
self.key = key
self.type = type
def __get__(self, instance, owner):
print("---> get ")
# print("instance = {}, owner = {}".format(instance, owner))
return instance.__dict__[self.key]
def __set__(self, instance, value):
print("---> set ")
# print("instance = {}, value = {}".format(instance, value))
if not isinstance(value, self.type):
# print(" name : type = {}".format(type(value)))
# return
raise TypeError(" {} {}, {}".format(self.key, self.type, type(value)))
instance.__dict__[self.key] = value
def __delete__(self, instance):
print("---> delete ")
# print("instance = {}".format(instance))
instance.__dict__.pop(self.key)
class Person:
name = Typed("name", str)
age = Typed("age", int)
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary
p1 = Person("xu", 99, 100.0)
print(p1.__dict__)
p1.name = "XU1"
print(p1.__dict__)
del p1.name
print(p1.__dict__)
# :
# ---> set
# ---> set
# {'name': 'xu', 'age': 99, 'salary': 100.0}
# ---> set
# {'name': 'XU1', 'age': 99, 'salary': 100.0}
# ---> delete
# {'age': 99, 'salary': 100.0}
記述子+クラスアクセラレータ(Personクラスにクラスプロパティを追加)
類の装飾器、道理は関数の装飾器と同じです
def Typed(**kwargs):
def deco(obj):
for k, v in kwargs.items():
setattr(obj, k, v)
return obj
return deco
@Typed(x=1, y=2) # 1、Typed(x=1, y=2) ==> deco 2、@deco ==> Foo = deco(Foo)
class Foo:
pass
#
print(Foo.__dict__) # {......, 'x': 1, 'y': 2}
print(Foo.x)
記述子とクラスアクセラレータを使用してPersonクラスにクラスプロパティを追加する
"""
+
"""
class Typed:
def __init__(self, key, type):
self.key = key
self.type = type
def __get__(self, instance, owner):
print("---> get ")
# print("instance = {}, owner = {}".format(instance, owner))
return instance.__dict__[self.key]
def __set__(self, instance, value):
print("---> set ")
# print("instance = {}, value = {}".format(instance, value))
if not isinstance(value, self.type):
# print(" name : type = {}".format(type(value)))
# return
raise TypeError(" {} {}, {}".format(self.key, self.type, type(value)))
instance.__dict__[self.key] = value
def __delete__(self, instance):
print("---> delete ")
# print("instance = {}".format(instance))
instance.__dict__.pop(self.key)
def deco(**kwargs):
def wrapper(obj):
for k, v in kwargs.items():
setattr(obj, k, Typed(k, v))
return obj
return wrapper
@deco(name=str, age=int)
class Person:
# name = Typed("name", str)
# age = Typed("age", int)
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary
p1 = Person("xu", 99, 100.0)
print(Person.__dict__)
print(p1.__dict__)
p1.name = "XU1"
print(p1.__dict__)
del p1.name
print(p1.__dict__)
# :
# ---> set
# ---> set
# {..., 'name': <__main__.typed object="" at="">, 'age': <__main__.typed object="" at="">}
# {'name': 'xu', 'age': 99, 'salary': 100.0}
# ---> set
# {'name': 'XU1', 'age': 99, 'salary': 100.0}
# ---> delete
# {'age': 99, 'salary': 100.0}
記述子による@propertyのカスタマイズ
class Lazyproperty:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
print("===> Lazypropertt.__get__ : instance = {}, owner = {}".format(instance, owner))
if instance is None:
return self
res = self.func(instance)
setattr(instance, self.func.__name__, res)
return self.func(instance)
# def __set__(self, instance, value):
# pass
class Room:
def __init__(self, name, width, height):
self.name = name
self.width = width
self.height = height
# @property # area=property(area)
@Lazyproperty # # area=Lazyproperty(area)
def area(self):
return self.width * self.height
# @property
# r = Room(" ", 2, 3)
# print(Room.__dict__) # {..., 'area': ,}
# print(r.area) # 6
# r2 = Room(" 2", 2, 3)
# print(r2.__dict__) # {'name': ' 2', 'width': 2, 'height': 3}
# print(r2.area)
# print(Room.area) # <__main__.lazyproperty object="" at="">
r3 = Room(" 3", 2, 3)
print(r3.area)
print(r3.area)
# ( ):
# ===> Lazypropertt.__get__ : instance = <__main__.room object="" at="">, owner =
# 6
# 6
property補充
class Foo:
@property
def A(self):
print("===> get A")
@A.setter
def A(self, val):
print("===> set A, val = {}".format(val))
@A.deleter
def A(self):
print("===> del A")
f = Foo()
f.A # ===> get A
f.A = "a" # ===> set A, val = a
del f.A # ===> del A
class Foo:
def get_A(self):
print("===> get_A")
def set_A(self, val):
print("===> set_A, val = {}".format(val))
def del_A(self):
print("===> del_A")
A = property(get_A, set_A, del_A)
f = Foo()
f.A # ===> get_A
f.A = "a" # ===> set_A, val = a
del f.A # ===> del_A