import datetime import time from functools import wraps #wraps可以把原函數對象的指定屬性復制給包裝函數對象 # start = datetime.datetime.now() # delta = (datetime.datetime.now() -start).total_seconds() def add(x,y): time.sleep(2) return x + y #裝飾器 def logger(fn): def wrapper(*args): z = fn(*args) return z return wrapper #裝飾器 def logged(func): @wraps(func)#原函數就是f,使用@wraps可以把f的屬性復制給func對象 def logging(*args, **kwargs): print(1, func.__name__) return func(*args, **kwargs) #這里不但可以返回一個像我上面寫的z= fn(*args,**kwargs),即z,也可以直接返回一個函數 return logging @logged def f(x): """This is a test model""" return 'ok' print(f.__name__) #f print(f.__doc__) #This is a test model def deltatime(fn): @wraps(fn) def wrapper(*args, **kwargs): start = datetime.datetime.now() ret = fn(*args, **kwargs) #測試,這里如果直接使用return返回對象的話,下面的語句塊就不會執行了 delta = (datetime.datetime.now() - start).total_seconds() print('The demo execute time is {}'.format(delta)) #按照自己的思路想把delta,print和wrapper函數對齊,但是報錯 return ret return wrapper @deltatime # add = deltatime(add) def add(x, y): time.sleep(2) return x + y print(add(3,5))
import time import datetime from functools import wraps class TimeIt: def __init__(self, fn): self.fn = fn # self.__doc__ = fn.__doc__ #直接修改,就可以使用被裝飾函數的屬性,動態增減,添加一個,可以看到一個,如果就動態增加doc的話,name的話看不到 wraps(fn)(self) # def __enter__(self): # self.start = datetime.datetime.now() # return self # def __exit__(self, exc_type, exc_val, exc_tb): # self.delta = (datetime.datetime.now() - self.start).total_seconds() # print('This demo\'s time is {} '.format(self.delta)) # pass def __call__(self, *args, **kwargs): self.start = datetime.datetime.now() ret = self.fn(*args, **kwargs) self.delta = (datetime.datetime.now() - self.start) print('This second demo\'s time is {}'.format(self.delta)) #This second demo's time is 0:00:01.000058 return ret @TimeIt def add(x,y): """This is a add function""" time.sleep(1) return x + y add(4,5) # print(add.__doc__) #This is a add function # print(add.__name__) #add # print(add.__call__) #<bound method TimeIt.__call__ of <__main__.TimeIt object at 0x00000000010C0780>> #應用場景: # 1、增強功能: # 在代碼執行的前后增加代碼,以增強其功能。類似裝飾器的功能 # 2、資源管理: # 打開了資源需要關閉,例如文件對象、網絡連接、數據庫連接的 # 3、權限驗證: # 在執行代碼之前,做權限的驗證,在__enter__中處理
class A: def __init__(self): self.a1 = 'a1' print('A.init') def __get__(self, instance, owner): print("A.__get__{} {} {}".format(self, instance, owner)) #self指的是A的實例,owner是B類,instance是說明 # return 1 class B: x = A() def __init__(self): print('B.init') # print(B.x) #A.init,A.__get__<__main__.A object at 0x00000000010954E0> None <class '__main__.B'>, None:這個None是get方法沒有給返回值,默認return None # print(B.x.a1) #報錯:AttributeError: 'NoneType' object has no attribute 'a1' b = B() print(b.x) # A.init,B.init,A.__get__<__main__.A object at 0x00000000008454E0> <__main__.B object at 0x0000000000845518> <class '__main__.B'>,None #打印結果解釋:定義了__get__方法,類A就是一個描述器,對類或者類B的實例的x屬性讀取,稱為對類A的實例的訪問就會調用__get__方法
class Point: def __init__(self, x, y): self.x = x self.y = y def __str__(self): return "Point({}, {})".format(self.x, self.y) def show(self): print(self) # return self p1 = Point(4,5) p2 = Point(10,10) #print(p1, p2) #打印出字符串 Point(4, 5) Point(10, 10) #print(repr(p1), repr(p2), sep = '\n') #打印出實例對象 <__main__.Point object at 0x000000000109E978> <__main__.Point object at 0x00000000010A52E8> setattr(p1, 'y', 16) setattr(p1, 'z', 10) print(getattr(p1, '__dict__')) #{'y': 16, 'z': 10, 'x': 4} #動態調用方法: if hasattr(p1, 'show'): getattr(p1, 'show')() #動態增加方法 #為類增加方法 if not hasattr(Point, 'add'): setattr(Point, 'add', lambda self,other:Point(self.x + other.x, self.y + other.y)) # print(Point.add) #<function <lambda> at 0x00000000010EA6A8> # print(p1.add) #<bound method <lambda> of <__main__.Point object at 0x00000000010F5630>> print(p1.__dict__) #{'z': 10, 'y': 16, 'x': 4} print(Point.__dict__) # {'__module__': '__main__', '__doc__': None, '__str__': <function Point.__str__ at 0x000000000107A8C8>, 'show': <function Point.show at 0x000000000107A950>, '__weakref__': <attribute '__weakref__' of 'Point' objects>, '__init__': <function Point.__init__ at 0x000000000107A840>, 'add': <function <lambda> at 0x000000000107A6A8>, '__dict__': <attribute '__dict__' of 'Point' objects>} # print(p1.add(p2)) #Point(14, 26) #為實例增加方法,未綁定 # if not hasattr(p1, 'sub'): # setattr(p1, 'sub', lambda self,other:Point(self.x - other.x, self.y - other.y)) # # print(p1.sub(p1,p1)) #Point(0, 0) # print(p1.sub) #<function <lambda> at 0x00000000006AA9D8> # # print(p1.__dict__) #{'sub': <function <lambda> at 0x000000000070A9D8>, 'z': 10, 'y': 16, 'x': 4} # print(Point.__dict__) #{'__module__': '__main__', '__init__': <function Point.__init__ at 0x000000000070A840>, 'add': <function <lambda> at 0x000000000070A6A8>, '__str__': <function Point.__str__ at 0x000000000070A8C8>, '__dict__': <attribute '__dict__' of 'Point' objects>, '__weakref__': <attribute '__weakref__' of 'Point' objects>, '__doc__': None, 'show': <function Point.show at 0x000000000070A950>} #print(Point.sub) #AttributeError: type object 'Point' has no attribute 'sub'
from functools import partial #partial用法:將所作用的函數作為partial()函數的第一個參數,原函數的各個參數依次作為partial()函數的后續參數,原函數有關鍵字參數的一定要帶上關鍵字,沒有的話,按原有參數順序進行補充。 #簡單的說就是作用在原函數上,通過參數順序填充,得到一個新函數 #例如一個非常簡單的例子 # max1 = partial(max,5) # print(max(1,3,6)) #打印結果是6 class ClassMethod: def __init__(self, fn): self._fn = fn def __get__(self, instance, owner): ret = partial(self._fn, owner) #為了方便這里的owner可以改成cls,但是上面的也要改,就是instance后面的 return ret class A: @ClassMethod #等價式: def clsmtd(cls): print(cls.__name__) print(A.__dict__) print(A.clsmtd) #<function A.clsmtd at 0x0000000001134488> print(A.clsmtd())
class Point: def __init__(self, x, y): self.x = x self.y = y def __str__(self): return ("{},{}".format(self.x, self.y)) def show(self): print("{}, {}".format(self.x ,self.y)) p = Point(4,5) setattr(Point,'z', 8) #setattr(object,name,value):object的屬性存在,則覆蓋,不存在,新增 # print(Point.__dict__) print(hasattr(Point, 'z')) # True hasattr(object,name):判斷對象是否有這個名字的屬性,name必須為字符串 print(p.__dict__) #{'x': 4, 'y': 5} print(Point.__dict__) #{'__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Point' objects>, '__doc__': None, 'show': <function Point.show at 0x000000000108A950>, '__dict__': <attribute '__dict__' of 'Point' objects>, '__str__': <function Point.__str__ at 0x000000000108A8C8>, '__init__': <function Point.__init__ at 0x000000000108A840>, 'z': 8} print(getattr(Point,'z')) #8 getattr(object, name[,default])通過name返回object的屬性值,當屬性不存在,將使用default返回,如果沒有default,則拋出AttributeError。name必須為字符串
class A: def __init__(self): self.a1 = 'a1' print('A.init') class B: x = A() def __init__(self): #沒有實例化是不會執行的 # self.b1 = 'b1' print('B.init') # print(B.x.a1) b = B() print(b.x.a1) ##類B的x屬性是類A的實例,所以類A先實例化,先打印A.init ## 然后執行到打印B.x.a1 ##然后實例化并初始化B的實例b ##打印b.x.a1會查找類屬性b.x,指向A的實例,所以返回A的實例的屬性a1的值
class A: def __init__(self): self.a1 = 'a1' print('A.init') def __get__(self, instance, owner): print("A.__get__ {} {} {}".format(self, instance, owner)) class B: x = A() def __init__(self): print('B.init') # print(B.x) #打印結果,A.init,A.__get__ <__main__.A object at 0x00000000010A5550> None <class '__main__.B'>,None # print(B.x.a1) #AttributeError: 'NoneType' object has no attribute 'a1',看上面的打印結果就是None,因為__get__沒有返回值,就相當于return一個None b = B() # print(b.x) #A.init,B.init,A.__get__ <__main__.A object at 0x0000000001095550> <__main__.B object at 0x0000000001095588> <class '__main__.B'>,None # print(b.x.a1) #AttributeError: 'NoneType' object has no attribute 'a1' print(B.x.a1) #AttributeError: 'NoneType' object has no attribute 'a1', 道理都一樣,因為上面沒有return值,所以跟一個None要a1,自然要不到 #定義了__get__方法,類A就是一個描述器,對類B或者類B的實例的x屬性讀取,成為對類A的實例的訪問,就會調用__get__方法
class A: def __init__(self): self.a1 = 'a1' print('A.init') def __get__(self, instance, owner): print("A.__get__ {} {} {}".format(self, instance, owner)) return self class B: x = A() def __init__(self): print('B.init') self.x = 'b.x' #增加實例屬性x print(B.x) #A.init , A.__get__ <__main__.A object at 0x0000000000BE5518> None <class '__main__.B'> , <__main__.A object at 0x0000000000BE5518> print(B.x.a1) #調用了get方法:A.__get__ <__main__.A object at 0x0000000001095518> None <class '__main__.B'> ,打印結果為:a1 b = B() print(b.x) #B.init , b.x # print(b.x.a1) # AttributeError: 'str' object has no attribute 'a1' #b.x訪問到了實例的屬性,但不是描述器
class Base: n = 0 class Point(Base): z = 6 def __init__(self, x, y): self.x = x self.y = y def show(self): print(self.x, self.y) def __getattr__(self, item): return "missing {}".format(item) def __setattr__(self, key, value): print("setattr {}={}".format(key, value)) p1 = Point(5,8) #setattr(object, name, value):object的屬性存在,則覆蓋,不存在新增 #__setattr__:通過.訪問實例屬性,進行增加、修改都要調用它 # __getattr__()通過搜索實例、實例的類及祖先類查不到屬性,就會調用此方法 # print(p1.x) # setattr x=5 setattr y=8 missing x # print(p1.z) #6 # print(p1.n) #0 # print(p1.t) #missing t # print(p1.__dict__) #{} # print('########',Point.__dict__) p1.x = 50 #setattr x=50 # print(p1.__dict__) #{} p1.__dict__['x'] = 60 print(p1.__dict__) #{'x': 60} print(p1.x) #60 # print(Point.__dict__) #實例中通過.點設置屬性,如同self.x = x,就會調用__setattr__(),屬性要加到實例的__dict__中
class A: def __init__(self): self.a1 = 'a1' print('A.init') def __get__(self, instance, owner): print("A.__get__ {} {} {}".format(self, instance, owner)) return self def __set__(self, instance, value): print('A.__set__ {} {} {}'.format(self, instance, value)) self.data = value class B: x = A() def __init__(self): print('B.init') self.x = 'b.x' #增加實例屬性x print(B.x) #A.init , A.__get__ <__main__.A object at 0x0000000001095518> None <class '__main__.B'> , <__main__.A object at 0x0000000001095518> print(B.x.a1) #A.__get__ <__main__.A object at 0x00000000010C5518> None <class '__main__.B'> , a1 發現會調用get方法 print('='*100) b = B() print(b.x) #B.init , A.__set__ <__main__.A object at 0x00000000010955F8> <__main__.B object at 0x00000000010956A0> b.x , A.__get__ <__main__.A object at 0x00000000010955F8> <__main__.B object at 0x00000000010956A0> <class '__main__.B'> , <__main__.A object at 0x00000000010955F8> print(b.x.a1) #A.__get__ <__main__.A object at 0x00000000007855F8> <__main__.B object at 0x00000000007856A0> <class '__main__.B'> , a1 訪問到了描述器
#getattr(object, name [,default]):通過name返回object的屬性值,不存在,默認default,沒有default,拋異常 #setattr(object, name, value):object屬性存在,覆蓋;不存在,新增 #hasattr(object, name):判斷對象是否存在name的屬性,name必須為字符串 class Point: def __init__(self, x, y): self.x = x self.y = y def __str__(self): return 'Point({}, {})'.format(self.x, self.y) def show(self): # print(self.x, self.y) return self p1 = Point(5,6) # print(p1) #Point(5, 6) # print(p1.__dict__) #{'y': 6, 'x': 5} p2 = Point(6,3) # print(p2) #Point(6, 3) # print(p2.__dict__) #{'x': 6, 'y': 3} # print(repr(p1), repr(p2)) #<__main__.Point object at 0x000000000109E9E8> <__main__.Point object at 0x00000000010A5588> 兩個實例 # setattr(p1, 'y', 30) # print(p1) #Point(5, 30) # setattr(p1, 'z', 100) # print(p1) #Point(5, 30) # print(p1.__dict__) #{'y': 30, 'x': 5, 'z': 100} #動態調用方法 # if hasattr(p1, 'show'): # getattr(p1, 'show')() # #動態增加方法 #為類增加方法 # if not hasattr(Point, 'add'): # setattr(Point, 'add', lambda self,other:Point(self.x + other.x, self.y + other.y)) # print(Point.add) #<function <lambda> at 0x0000000000B6A6A8> # print(p1.add) #<bound method <lambda> of <__main__.Point object at 0x0000000000775668>> # print(p1.add(p2)) #Point(11, 9) #綁定,意思就是出現了bound #為實例增加方法,未綁定,就是沒有出現過bound if not hasattr(p1, 'sub'): setattr(p1, 'sub', lambda self,other:Point(self.x - other.x, self.y - other.y)) print(p1.sub(p1,p1)) #Point(0, 0) print(p1.sub) #<function <lambda> at 0x00000000010AA6A8> #動態增刪屬性的方式是運行時改變類或者實例的方式,但是裝飾器或Mixin都是定義時就決定了,因此反射能力具有更大的靈活性。
class Point: def __init__(self, x, y): #如果多個參數可以修改成def __init__(self, *args) self_arg = args self.x = x self.y = y def __str__(self): return "Point({} ,{})".format(self.x, self.y) def show(self): print(self.x, self.y) # return self p1 = Point(8,9) # print(p1) #Point(8 ,9) # print(p1.__dict__) #{'y': 9, 'x': 8} # print(p1.__dict__['y']) #9 p1.z = 1000 # print(p1.__dict__) #{'x': 8, 'y': 9, 'z': 1000} # print(dir(p1)) #['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'show', 'x', 'y', 'z'] #'show', 'x', 'y', 'z' print(p1.__dir__()) #['__lt__', '__setattr__', '__format__', 'y', '__repr__', '__reduce_ex__', '__le__', '__gt__', '__ge__', '__delattr__', '__dir__', '__hash__', '__reduce__', '__subclasshook__', '__new__', '__eq__', '__doc__', '__module__', 'show', 'z', '__getattribute__', '__weakref__', '__sizeof__', '__str__', '__init__', '__ne__', 'x', '__dict__', '__class__']
本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/88656