通過類模擬一個classmthod
首先搞明白clssmethod原理,直接修改類的dict
框架如下:
class Class_Method: def __init__(self,fn): self.fn = fn def __get__(self, instance, owner): print(self,instance,owner) return self.fn class A: @Class_Method def bar(cls): print(cls.__name__) f = A.bar print(f) f()
發現報錯:
Traceback (most recent call last): <__main__.Class_Method object at 0x0000000000DE8390> None <class ‘__main__.A‘> File "E:/python_project/learing/20171106/class_test.py", line 32, in <module> <function A.bar at 0x00000000010F0488> f() TypeError: bar() missing 1 required positional argument: ‘cls‘
get可以獲取到,return的是bar函數
考慮A在哪裏可以獲取到,回到get方法中,獲取owner屬性,直接return owner
也就是說直接返回A
def __get__(self, instance, owner): print(self,instance,owner) return self.fn(owner)
測試:
f()
Traceback (most recent call last): File "E:/python_project/learing/20171106/class_test.py", line 33, in <module> f() TypeError: ‘NoneType‘ object is not callable
是一個函數調用,但是沒有return任何東西
1.首先return self.fn(owner) 直接指向A類,A類可以獲取
2.但是函數返回值是None,因為是def bar中沒有return其他,默認是None
解決:
固定返回參數
partial
return self.fn 和 class也就是A 返回為一個新的函數
class Class_Method: def __init__(self,fn): print(‘init,self.fn : ‘, fn) self.fn = fn def __get__(self, instance,cls): print(self,instance,cls) # return self.fn(owner) return partial(self.fn,cls) class A: @Class_Method def bar(cls): print(‘bar:‘,cls.__name__) f = A.bar print(f) f()
返回如下:
init,self.fn : <function A.bar at 0x00000000010C1488> <__main__.Class_Method object at 0x00000000008592E8> None <class ‘__main__.A‘> functools.partial(<function A.bar at 0x00000000010C1488>, <class ‘__main__.A‘>) bar: A
因為返回的必須是函數,所以最好使用partial 返回一個新函數
再進行調用,發現模擬使用方法是差不多的,但是模仿終歸模仿
對實例的數據進行校驗
涉及:inspect 參數檢查
使用描述器進行參數檢查
當實例化的時候必須傳遞參數進去,必須實例化
class Typed: def __init__(self): pass def __get__(self, instance, owner): print(‘get :‘,self, instance, owner ) def __set__(self, instance, value): print(‘set : ‘,self, instance, value) class Person: name = Typed() age = Typed() def __init__(self,name:str,age:int): self.name = name self.age = age
調用返回如下:
set : <__main__.Typed object at 0x0000000000DD8470> <__main__.Person object at 0x0000000000DB6470> tom set : <__main__.Typed object at 0x0000000000DB6400> <__main__.Person object at 0x0000000000DB6470> 1
返回了兩個實例的value
判斷類型:
首先需要聲明並傳遞一個類型,
class Typed: def __init__(self,type): self.type = type def __get__(self, instance, owner): print(‘get :‘,self, instance, owner ) def __set__(self, instance, value): print(‘set : ‘,self, instance, value) class Person: name = Typed(str) age = Typed(int) def __init__(self,name:str,age:int): self.name = name self.age = age p = Person(‘tom‘,1)
獲取了value,接下來自己的類型也明確了,首先傳遞進來是被set攔截,那麽需要在set中做判斷
因為設置值的時候才觸發set
改進:
通過inspect 進行參數檢查
inspect.signature(Person) 檢查參數
print(inspect.signature(Person)) (name:str, age:int)
返回的是初始化方法,參數註解
通過parameters 返回的是一個
print(inspect.signature(Person).parameters) OrderedDict([(‘name‘, <Parameter "name:str">), (‘age‘, <Parameter "age:int">)])
返回的是一個有序字典
使用annotation將其轉為class類型
params = inspect.signature(Person).parameters for name,param in params.items(): print(name,param.annotation)
返回如下:
name <class ‘str‘> age <class ‘int‘>
通過類裝飾器判斷數據類型
新建一個類,做為裝飾器判斷
class TypeAssert: def __init__(self,cls): self.cls = cls def __call__(self,name,age): params = inspect.signature(self.cls).parameters for name,param in params.items(): print(name,param.annotation) class Person: name = Typed(str) age = Typed(int) def __init__(self,name:str,age:int): self.name = name self.age = age
將這兩句話去掉,不在類中調用Typed的類,將其在TypeAssert中進行調用並判斷
通過setattr 創建類的屬性,直接寫入到字典
name,age
class TypeAssert: def __init__(self,cls): self.cls = cls def __call__(self,name,age): params = inspect.signature(self.cls).parameters for name,param in params.items(): print(name,param.annotation) if param.annotation != param.empty: #判斷值是否有註解,將不等於空則加入類屬性 setattr(self.cls,name,Typed(param.annotation))
這樣再添加屬性則被__set__攔截並修改
完整如下:
class Typed: def __init__(self,type): self.type = type def __get__(self, instance, owner): print(‘get :‘,self, instance, owner ) def __set__(self, instance, value): print(‘set : ‘,self, instance, value) if not isinstance(value,self.type): raise ValueError(value) class TypeAssert: def __init__(self,cls): self.cls = cls def __call__(self,name,age): params = inspect.signature(self.cls).parameters print(params) for name,param in params.items(): print(name,param.annotation) if param.annotation != param.empty: setattr(self.cls,name,Typed(param.annotation)) @TypeAssert class Person: name = Typed(str) age = Typed(int) def __init__(self,name:str,age:int): self.name = name self.age = age p = Person(‘tom‘,11) print(Person.__dict__) print(type(p))
本文出自 “心情依舊” 博客,請務必保留此出處http://yijiu.blog.51cto.com/433846/1984201
通過類模擬一個classmthod