<__main__.Property object at 0x000002041BD051C0><__main__.A object at 0x000002041BD05250><class'__main__.A'>10set~~~~<__main__.Property object at 0x000002041BD051C0><__main__.A object at 0x000002041BD05250>100<__main__.Property object at 0x000002041BD051C0><__main__.A object at 0x000002041BD05250><class'__main__.A'>100
2、类静态方法描述器实现
# 一个描述器类只为一个类服务# 自定义实现 staticmethodclassStaticMethod:"""This is a StaticMethod class."""def__init__(self, fn):
self.fn = fn
def__get__(self, instance, owner):return self.fn
# smtd = StaticMethod(smtd) # smtd 是类属性,是描述器类的一个实例classA:""""Class A."""@StaticMethoddefsmtd(x, y):# smtd = StaticMethod(smtd) """Smtd in class A."""return(x, y)
a = A()print(a.smtd(4,5))print(a.smtd.__doc__, a.smtd.__name__)
import inspect
classTypeCheck:# 数据描述器def__init__(self, typ):
self.type= typ
def__get__(self, instance, owner):if instance:return instance.__dict__[self.name]else:return self
def__set_name__(self, owner, name):# 动态注入,不会触发这个魔术方法print(name, owner)# 实例初始化的时候,才会触发这个方法
self.name = name
def__set__(self, instance, value):if instance:ifisinstance(value, self.type):
instance.__dict__[self.name]= value
else:raise TypeError(self.name)defdatainject(cls):# 为类动态注入属性
sig = inspect.signature(cls)
params = sig.parameters
for name, param in params.items():print(name, param.name, param.kind, param.default, param.annotation)if param.annotation != inspect._empty:setattr(cls, name, TypeCheck(param.annotation))# 注入属性return cls
@datainjectclassPerson:# name = TypeCheck(str)# age = TypeCheck(int)def__init__(self, name:str, age:int):
self.name = name
self.age = age
tom = Person('tom',20)print(tom.name)print(tom.age)print(Person.name)# 动态注入时,__set_name__不会被触发
name name POSITIONAL_OR_KEYWORD <class'inspect._empty'><class'str'>
age age POSITIONAL_OR_KEYWORD <class'inspect._empty'><class'int'>
AttributeError:'TypeCheck'object has no attribute 'name'
4.2 Version 2
import inspect
classTypeCheck:# 数据描述器def__init__(self, name, typ):
self.type= typ
self.name =name
def__get__(self, instance, owner):if instance:return instance.__dict__[self.name]else:return self
def__set__(self, instance, value):if instance:ifisinstance(value, self.type):
instance.__dict__[self.name]= value
else:raise TypeError(self.name)defdatainject(cls):# 为类动态注入属性
sig = inspect.signature(cls)
params = sig.parameters
for name, param in params.items():print(name, param.name, param.kind, param.default, param.annotation)if param.annotation != inspect._empty:setattr(cls, name, TypeCheck(name, param.annotation))# 注入属性return cls
@datainjectclassPerson:# name = TypeCheck(str)# age = TypeCheck(int)def__init__(self, name:str, age:int):
self.name = name
self.age = age
tom = Person('tom',20)print(tom.name)print(tom.age)print(Person.name)
name name POSITIONAL_OR_KEYWORD <class'inspect._empty'><class'str'>
age age POSITIONAL_OR_KEYWORD <class'inspect._empty'><class'int'>
tom
20<__main__.TypeCheck object at 0x000002041BCF9A60>
4.3 Version 3
import inspect
from functools import wraps, update_wrapper
classTypeCheck:# 数据描述器def__init__(self, name, typ):
self.type= typ
self.name =name
def__get__(self, instance, owner):if instance:return instance.__dict__[self.name]else:return self
def__set__(self, instance, value):if instance:ifisinstance(value, self.type):
instance.__dict__[self.name]= value
else:raise TypeError(self.name)classDataInject:def__init__(self, cls):
self.cls = cls
sig = inspect.signature(cls)
params = sig.parameters
for name, param in params.items():# print(name, param.name, param.kind, param.default, param.annotation)if param.annotation != inspect._empty:setattr(cls, name, TypeCheck(name, param.annotation))# 注入属性# print(cls.__dict__)def__call__(self,*args,**kwargs):return self.cls(*args,**kwargs)@DataInjectclassPerson:# name = TypeCheck(str)# age = TypeCheck(int) def__init__(self, name:str, age:int):
self.name = name
self.age = age
tom = Person('tom',20)print(tom.name)print(tom.age)print(Person.__dict__)