时间:2021-05-22
函数也是对象
要理解Python装饰器,首先要明白在Python中,函数也是一种对象,因此可以把定义函数时的函数名看作是函数对象的一个引用。既然是引用,因此可以将函数赋值给一个变量,也可以把函数作为一个参数传递或返回。同时,函数体中也可以再定义函数。
装饰器本质
可以通过编写一个纯函数的例子来还原装饰器所要做的事。
def decorator(func): def wrap(): print("Doing someting before executing func()") func() print("Doing someting after executing func()") return wrapdef fun_test(): print("func")fun_test = decorator(fun_test)fun_test()# Output:# Doing someting before executing func()# func# Doing someting after executing func()fun_test所指向的函数的引用传递给decorator()函数
decorator()函数中定义了wrap()子函数,这个子函数会调用通过func引用传递进来的fun_test()函数,并在调用函数的前后做了一些其他的事情
decorator()函数返回内部定义的wrap()函数引用
fun_test接收decorator()返回的函数引用,从而指向了一个新的函数对象
通过fun_test()调用新的函数执行wrap()函数的功能,从而完成了对fun_test()函数的前后装饰
Python中使用装饰器
在Python中可以通过@符号来方便的使用装饰器功能。
def decorator(func): def wrap(): print("Doing someting before executing func()") func() print("Doing someting after executing func()") return wrap@decoratordef fun_test(): print("func")fun_test()# Output:# Doing someting before executing func()# func# Doing someting after executing func()装饰的功能已经实现了,但是此时执行:
print(fun_test.__name__)# Output:# wrapfun_test.__name__已经变成了wrap,这是应为wrap()函数已经重写了我们函数的名字和注释文档。此时可以通过functools.wraps来解决这个问题。wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。
更规范的写法:
from functools import wrapsdef decorator(func): @wraps(func) def wrap(): print("Doing someting before executing func()") func() print("Doing someting after executing func()") return wrap@decoratordef fun_test(): print("func")fun_test()print(fun_test.__name__)# Output:# Doing someting before executing func()# func# Doing someting after executing func()# fun_test带参数的装饰器
通过返回一个包裹函数的函数,可以模仿wraps装饰器,构造出一个带参数的装饰器。
from functools import wrapsdef loginfo(info='info1'): def loginfo_decorator(func): @wraps(func) def wrap_func(*args, **kwargs): print(func.__name__ + ' was called') print('info: %s' % info) return func(*args, **kwargs) return wrap_func return loginfo_decorator @loginfo()def func1(): pass func1()# Output:# func1 was called# info: info1@loginfo(info='info2')def func2(): passfunc2()# Output:# func2 was called# info: info2装饰器类
通过编写类的方法也可以实现装饰器,并让装饰器具备继承等面向对象中更实用的特性
首先编写一个装饰器基类:
from functools import wrapsclass loginfo: def __init__(self, info='info1'): self.info = info def __call__(self, func): @wrap def wrap_func(*args, **kwargs): print(func.__name__ + ' was called') print('info: %s' % self.info) self.after() # 调用after方法,可以在子类中实现 return func(*args, **kwargs) return wrap_func def after(self): pass@loginfo(info='info2')def func1(): pass # Output:# func1 was called# info: info1再通过继承loginfo类,扩展装饰器的功能:
class loginfo_after(loginfo): def __init__(self, info2='info2', *args, **kwargs): self.info2 = info2 super(loginfo_after, self).__init__(*args, **kwargs) def after(self): print('after: %s' % self.info2)@loginfo_after()def func2(): passfunc2() # Output:# func2 was called# info: info1# after: info2以上这篇老生常谈Python进阶之装饰器就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
注:这里忽略了生成器,装饰器,交换变量等熟知技巧1.函数参数unpack老生常谈的了:deffoo(x,y):printx,yalist=[1,2]adict=
本文接上文“老生常谈反射之Class类的使用(必看篇)”,以编写一个用来获取类的信息(成员函数、成员变量、构造函数)的工具类来讲解"反射之获取类的信息"1、获取
老生常谈的配置但是还是需要说明一下EurekaApplication@EnableEurekaServer指定为server端@EnableEurekaServ
原文首发于知乎:https://www.zhihu.com/question/41638271/answer/493551513这个问题是最老生常谈的问题,每个
手机的续航算是老生常谈的一个话题了,毕竟电量就是电子产品的命脉,没电的话,再好的手机也只是一个没太大作用的装饰品。而今年的手机又面临着比以往更为严峻的续航考验,