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.178linux.com/88656