python函数装饰器详解,python装饰器获取被装饰函数的参数
装饰包装纸
装饰品的功能
装饰器用于向现有函数或对象添加其他函数。
Decorators本质上是Python函数,其他函数可以添加到其他函数中,而无需更改代码。装饰器的返回值也是一个函数对象。通常用于有严格要求的场景,如日志插入、性能测试、事务处理、缓存和权限检查。Decorator是解决这个问题的优秀设计。有了decorator,很多类似的与函数本身无关的代码都可以画出来,重用。
无参数装饰器
调试(功能):
defwrapper(:
打印((调试) :输入{ }))。格式)func。__name_))
返回函数()
返回包装
@调试
def say_hello():
打印(“你好!”)
说你好()
[调试]:输入say_hello()
你好!
把@debug放在say_hello()之前就大功告成了。
say_hello=debug(say_hello))。
Debug))是一个返回包装函数的decorator,所以原来的say_hello))仍然存在。但由于当前同名的now变量指向新函数,调用say_hello)会执行新函数(即debug)(函数返回的包装器)。
可变参数装饰器
调试(功能):
EFwrapper(*Args,**kwargs)):
打印((调试) :输入{ }))。格式)func。__name_))
returnfunc(*Args,**kwargs)))))))))return func(* Args,* * kwargs))
返回包装
@调试
defsay_Hello(名字什么的) :
打印(你好!{}{}.格式(名字什么的) )
说你好(罗征,.) )。
[调试]:输入say_hello()
你好!罗征。
Python提供了变量参数*args和关键字参数**kwargs。有了这两个参数,装饰器可以用于任何目标函数。
高级装饰工
带参数的装饰器
假设前面提到的decorator必须执行的函数不仅在进入某个函数后发出一条log消息,还需要指定log的级别。装修工就是这种情况。
Eflogging(级别):
efwrapper(func):
definer _ wrapper(* Args,**kwargs):
print([{ level }]:enter func(func)))。格式(
水平=水平,
函数=函数。__name__))
returnfunc(*Args,**kwargs)))))))))return func(* Args,* * kwargs))
返回内部包装
返回包装
@logging(level=info ).
定义(某事) :
打印(说)!格式(东西) )
# @如果没有使用语法,它与
#say=logging(level=info ) (say)).
@logging(level=debug ).
默认(某事):
打印( do {}。。格式)(什么的))
if __name__==__main__ :
说(你好).
我的工作)。
【信息】:企业功能存储(
打个招呼!
[调试]:输入函数do(
做我的工作。
如果你遇到一个带参数的decorator的函数,比如@ logging (level= debug),它其实就是一个函数,会立即执行。如果这个函数返回的结果是decorator,那就没问题了。让我们仔细看看。
基于类实现的装饰器
装饰函数实际上是一个接口约束,它必须接受一个可调用对象作为参数,并返回一个可调用对象。在Python中,可调用对象通常是函数,但也有例外。只要对象是重载的_ _
调用__()方法,那么这个对象是可调用的。重载__call__ magic方法一般会改变一个对象的内部行为,这样一个类对象就有了被调用的行为。
类测试():
def __call__(self):
打印“打电话给我!”
t=测试()
打电话给我
Decorator要求接受一个可调用对象并返回一个可调用对象(不太严格,见后面)。那么用类来实现也是可以的。我们可以让类的构造函数__init__()接受一个函数,然后重载__call__()返回一个函数,也可以达到装饰函数的效果。
类日志记录(对象):
def __init__(self,func):
self.func=func
def __call__(self,*args,**kwargs):
print([DEBUG]:输入函数{func}()。格式(
func=self.func.__name__))
返回self.func(*args,**kwargs)
@日志记录
def说(某事):
打印(说{} )。格式(东西))
说(‘爱你。’)
[调试]:输入函数say()
说爱你。
带参数的类装饰器
类日志记录(对象):
def __init__(self,level=INFO ):
自我水平=水平
def __call__(self,func): #接受函数
极好的包装(*args,**kwargs):
打印([{level}]:输入函数{func}() .格式(
级别=自我级别,
函数=函数. __姓名_ _))
func(*args,**kwargs)
退货包装#返回函数
@日志记录(级别=信息)
极好的说(某事):
打印(说{} )。格式(东西))
说(爱你。)
打印(说__name__) #包装器
内置装饰器@属性
进行类属性读写的限制,Python基础(十二)—面向对象拾遗(插槽,@属性,)枚举类、元类)有讲解到。
装饰器的注意事项
不确定的代码执行顺序
最好不要在装饰器函数之外添加逻辑功能,否则这个装饰器就不受你控制了。
def html_tags(tag_name):
打印(开始外部函数。)
def wrapper_(func):
打印(内部包装函数的开始)
极好的包装(*args,**kwargs):
content=func(*args,**kwargs)
打印(“{content}{tag}”).格式(tag=tag_name,content=content))
打印(内部包装函数结束)
返回包装
打印("外部函数结束")
返回包装_
@html_tags(b )
def hello(name=Toby ):
回复"你好{}!"。格式(名称)
你好()
你好()
开始外部函数。
外部函数结束
内部包装函数的开始。
内部包装函数的结尾。
你好托比。
你好托比。
functools.wraps
上面的一个例子:
打印(说. name_) #包装器
这是因为@等同于这样的写法:
说=记录(说)
记录其实返回的函数名字刚好是包装,那么上面的这个语句刚好就是把这个结果赋值给说,说的__姓名_ _自然也就是包装材料了,不仅仅是姓名,其他属性也都是来自包装,比如文档,来源等等。
使用标准库里的functools.wraps,可以基本解决这个问题。
从函数工具导入包装
导入日期时间
定义日志记录(函数):
@wraps(func)
极好的包装(*args,**kwargs):
在函数前打印日志。
打印([调试] {}:输入{}()。format(datetime.now()、func .__name__))
return func(*args,**kwargs)
返回包装
@日志记录
极好的说(某事):
说点什么
打印(说{}!。格式(东西))
打印(说__name__) #说
打印(说. doc__) #说点什么
多层装饰器
使用场景较小,可以参考以下代码或文章:Python装饰器执行顺序迷思。
定义一个(函数):
打印(- 1 -)
def two():
打印(- 2 -)
函数()
返回二
定义一个(函数):
打印(- a -)
定义b():
打印(- b - )
函数()
返回b
@一个
@a
极好的演示():
打印(- 3 -)
演示()
-一个-
- 1 -
- 2 -
- b -
- 3 -
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。