描述符:
描述符本质是一个新式类,在这个新式类中,至少出现了__get__()
、__set__()
或者__delete__()
方法中的一个,也被称为描述符协议。
-
__get__()
:obj.name
调用一个属性的时候触发 -
__set__()
:obj.name = "bill"
为一个属性赋值的时候触发 -
__delete__()
:del obj.name
采用del
删除属性的时候,触发
描述符分为两种:
- 数据描述符 至少实现了
__get__()
和__set__()
- 非数据描述符 没有实现
__set__()
注意:对象本身调用不会触发描述符协议,当该新式类为别的类的属性,通过别的类来调用该新式类时候才会触发“
class Foo:
def __set__(self, instance, value):
# 可以通过__dict__属性字典设置,在设置前可以增加判断等操作
print("hahaha")
class Tmp:
#Foo()是数据描述符 代理了foo对象的属性调用相关方法
foo = Foo()
result = Tmp()
result.foo = "asdf"
函数装饰器复习
前有函数装饰器:
def foo(func):
print("装饰器")
return func;
@foo # 这一步就等于func1 = foo(func1)
def func1():
print("func1")
func1()
类装饰器使用
终极代码:类装饰器 + 描述符
class TypedC:
def __init__(self, key, classType):
self.key = key
self.classType = classType
def __get__(self, instance, owner):
return instance.__dict__[self.key]
def __set__(self, instance, value):
if not isinstance(value, self.classType):
raise TypeError("传入的数据类型有问题")
instance.__dict__[self.key] = value
def out_deco(**kwargs):
def in_deco(obj):
for key, value in kwargs.items():
setattr(obj, key, TypedC(key,value))
return obj
return deco
@out_deco(name=str, age=int)
class New:
def __init__(self, name, age):
self.name = name
self.age = age
print(New("alex",100).__dict__)
解释:
@out_deco(name=str, age=int)
先忽略@,即执行右半边方法: out_deco(name=str, age=int) -> out_deco({字典})
得到:
@in_deco(New) 相当于 New = in_deco(New)
然后执行in_deco(New)内部循环:
setattr(obj, key, TypedC(key,value)) 相当于 New.key = TypedC("name", str)
自定义装饰器
使用类装饰器 模拟系统@property
的实现
class Deco_class:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
return self.func(instance)
class Foo:
def __init__(self):
pass
@Deco_class
def showAnim(self):
print("show anim 运行")
obj = Foo()
obj.showAnim
改进版:储存函数执行结果,下次不用重复计算执行
class Deco_class:
def __init__(self, func):
self.func = func
# 因为没有重写__set__方法,所以是非数据描述符,优先级比实例属性低
def __get__(self, instance, owner):
res = self.func(instance)
# 储存结果到实例对象中后 下次调用 由于优先级的问题 会优先从实例对象中查找showAnim方法,而不是调用非数据描述符
setattr(instance, self.func.__name__, res)
return res
class Foo:
def __init__(self):
pass
@Deco_class
def showAnim(self):
print("show anim 运行")
obj = Foo()
obj.showAnim
补充:
使用@property
装饰器修饰的方法,不可以赋值,需要:
class Foo:
@property
def showAnim(self):
print("show anim 运行")
@showAnim.setter
def showAnim(self, name):
print("show anim 运行", name)
obj = Foo()
obj.showAnim
obj.showAnim = "bill"
另一种写法:
class Foo:
def get_a(self):
print("get method")
def set_a(self, val):
print("set method")
def del_a(self):
print("del method")
aaa = property(get_a, set_a, del_a)
obj = Foo()
obj.aaa = "bill"
网友评论