Descriptor描述器 & 类初始化参数检查

  

  • 实现StaticMethod,完成staticmethod装饰器功能
  • 实现ClassMethod,完成classmethod装饰器功能

class StaticMethod:
    def __init__(self,fn):
        print('StaticMethod Init')
        self.fn=fn

    def __get__(self,instance,owner):
        print('StaticMethod.__get__',self,instance,owner)
        return self # 返回self.fn 或者使用__call__变成可调用对象

    def __call__(self,*args,**kwargs): 
        return self.fn(*args,**kwargs)

from functools import partial

class ClassMethod:
    def __init__(self,fn):
        print('ClassMethod Init')
        self.fn=fn

    def __get__(self,instance,owner):
        print('ClassMethod.__get__',self,instance,owner)
        def f(*args,**kwargs):
            ret=self.fn(owner,*args,**kwargs)
            return ret
        return partial(self.fn,owner) 


class B:
    @StaticMethod
    def ore(*args,**kwargs): # ore=StaticMethod(ore)
        print('ore',args,kwargs)

    @ClassMethod
    def rag(cls,*args,**kwargs): # rag=ClassMethod(rag)
        print(cls,args,kwargs)

print(B.ore)
B.ore(23423)
print('$'*80)
print(B.rag)
print(B.rag(234234))

 

class ClassMethod:
    def __init__(self, fn):
        self.fn = fn

    def __get__(self, instance, owner):
        return lambda *args, **kwargs: self.fn(owner, *args, **kwargs)

 

class StaticMethod:
    def __init__(self,fn):
        self._fn=fn

    def __get__(self,instance,owner):
        return self._fn

class B:
    @StaticMethod
    def ore(): # ore=StaticMethod(ore)
        print('static method')
B.ore()
B().ore()
from functools import partial
class ClassMethod:
    def __init__(self,fn):
        self._fn=fn

    def __get__(self,instance,owner):
        return partial(self._fn,owner)

class B:
    @ClassMethod
    def ore(cls):
        print(cls.__name__)
        
print(B.__dict__)
print(B.ore())

 

类初始化参数检查

1:函数版

class Rag:
    def __init__(self,name:str,age:int):
        if not self.checkparameters(((name,str),(age,int))):
            raise TypeError('Type Error!')
        self._name=name
        self._age=age

    def checkparameters(self,params):
        for data,type in params:
            if not isinstance(data,type):
                return False
        return True

b=Rag('uiop',44)

2:类装饰器V1

class CheckParams:
    def __init__(self,attr,annotation):
        self.attr=attr
        self.annotation=annotation

    def __get__(self,instance,owner):
        if instance is not None: #非类访问
            return instance.__dict__[self.attr]
        return self

    def __set__(self,instance,value):
        if not isinstance(value,self.annotation):
            raise TypeError(r'{} should be type {}'.format(value,self.annotation))
        instance.__dict__[self.attr]=value

class Rag:
    name=CheckParams('name',str) # 硬编码
    age=CheckParams('age',int)
    def __init__(self,name:str,age:int):
        self.name=name
        self.age=age

p=Rag(22,22)

 

class CheckParams:
    def __init__(self,attr,type):
        self.attr=attr
        self.type=type
        pass
    def __get__(self,instance,owner):
        pass
    def __set__(self,instance,value):
        if not isinstance(value,self.type):
            raise ValueError(r'{}'.format(value))
        else:
            instance.__dict__[self.attr]=value
        pass

class Ore:
    name=CheckParams('name',str)
    age=CheckParams('age',int)

    def __init__(self,name:str,age:any):
        self.name=name
        self.age=age

o=Ore('uiop',88)
print(o.__dict__)

import inspect
b=inspect.signature(Ore)
print(type(b),b)
print(b.parameters)
print(type(b.parameters['age']))
for k,v in b.parameters.items():
    print(k,v.annotation)

3:类装饰器V2

class CheckParams:
    def __init__(self,attr,annotation):
        self.attr=attr
        self.annotation=annotation

    def __get__(self,instance,owner):
        return instance.__dict__[self.attr]

    def __set__(self,instance,value):
        if not isinstance(value,self.annotation):
            raise TypeError(r'{} should be type {}!'.format(value,self.annotation))
        else:
            instance.__dict__[self.attr]=value

import inspect
class TypeAssert:
    def __init__(self,cls):
        self.cls=cls
        # setattr in self.cls
        # OrderedDict([('name', <Parameter "name: str">), ('age', <Parameter "age">)])
        params=inspect.signature(self.cls).parameters
        for attr,param in params.items():
            if param.annotation != param.empty: # annotation is not empty
                setattr(self.cls,attr,CheckParams(attr,param.annotation))

    def __call__(self,*args,**kwargs):
        return self.cls(*args,**kwargs)

@TypeAssert
class Person:
    def __init__(self,name:str,age:int):
        self.name=name
        self.age=age

p1=Person('uiop','77')
print(Person)
print(Person.__dict__['cls'].__dict__)
print(p1.__dict__)
print(p1.name)

 

 

4:函数装饰器

class CheckParams:
    def __init__(self,attr,annotation):
        self.attr=attr
        self.annotation=annotation

    def __get__(self,instance,owner):
        if instance is not None:
            return instance.__dict__[self.attr]
        return self

    def __set__(self,instance,value):
        if not isinstance(value,self.annotation):
            raise TypeError(r'{} should be type {}'.format(value,self.annotation))
        instance.__dict__[self.attr]=value

import inspect
def typeassert(cls):
    params=inspect.signature(cls).parameters
    for attr,param in params.items():
        if param.annotation != param.empty:
            setattr(cls,attr,CheckParams(attr,param.annotation))
    return cls

@typeassert # 添加描述器
class Ore:
    def __init__(self,name:str,age:int):
        self.name=name
        self.age=age

    def __repr__(self):
        return 'name:{} age:{}'.format(self.name,self.age)

p=Ore('22',33)
print(Ore.__dict__) # 观察Ore属性的变化
print(p)

 

posted @ 2020-10-07 22:54  ascertain  阅读(142)  评论(0编辑  收藏  举报