查阅官方文档、大神博客等,总结如下文档。目的是备份资料,方便以后查阅温习,也希望对大家有所帮助!
环境: python3.7
一、相关理论知识
- python的常识,函数和其他任何东西一样,都是对象。这意味着可以将函数当做实参传递给函数,或者在函数中将函数作为返回值。
- 装饰器的作用是什么呢?简单的理解就是:装饰原有的函数。什么意思呢?比如有一个函数func(a, b),它的功能是求a,b的差值,我现在有一个需求,就是想对函数功能再装饰下,求完差值后再取绝对值,但是不能在func函数内部实现,这时候就需要装饰器函数了,比如func = decorate(func)函数,将func函数作为参数传递给decorate函数,由decorate来丰富func函数,丰富完成后再返回给func,此时func的功能就丰富了。
- 装饰器符号“@”属于语法糖,什么意思呢?就是说,我不按照@装饰器的语法要求来写,而是按照一般python的语法要求来写完全可以。那么用@装饰器的格式来写的目的就是为了书写简单方便。2. 装饰器符号“@”属于语法糖,什么意思呢?就是说,我不按照@装饰器的语法要求来写,而是按照一般python的语法要求来写完全可以。那么用@装饰器的格式来写的目的就是为了书写简单方便。
二、案例(加深对装饰器的理解)
例1: 定义并应用一个装饰器(不建议使用这种方式)
def decorate1(func): #定义一个装饰器
def inner(a,b):
z=func(a,b)
return abs(z)
return inner
def sub(x,y):
return x-y
sub2=decorate1(sub) #应用装饰器decorate1
print(sub2(1,2)) #结果是1
例2: 定义并应用一个装饰器(建议使用这种方式)
def decorate1(func):
def inner(a,b):
z=func(a,b)
return abs(z)
return inner
#个人认为,下面的3行代码的本质是:定义了一个inner函数,其中,先调用func函数z=func(a,b),然后对返回值取绝对值并返回。
@decorate1
def sub(x,y):
return x-y
print(sub(1,2)) #结果是1
特别说明:
1、装饰器的定义要注意3点:参数是函数;内部再定义一个函数;返回内部定义的函数
2、’’‘当我们调用sub函数时,实际上是调用经过decorate1装饰的sub函数,返回值由表面的x-y,变成了abs(x-y).’’’
例3: 定义并应用一个装饰器,同时使用封皮wraps(建议使用这种方式)
例2中定义并使用装饰器的方式存在一个问题:经过装饰后函数的__name__、doc__等变量的值也会发生变化,会变成装饰函数中内部函数的___name、doc__等的值,但我们常常有这么一种需求,经过装饰后原函数发生变化,但__name、__doc__等属性不发生变化。为解决这个问题,引入了python装饰器之@functools.wraps。
python装饰器之@functools.wraps的作用就是,不改变原函数的结构(即__name__、__doc__等)。
例3-1(未使用wraps):
def logged(func):
def with_logging(*args, **kwargs):
"""doc of with_logging"""
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logged
def f(x):
"""doc of f"""
return x + x * x
if __name__ == '__main__':
print(f.__name__) # 结果是:with_logging
print(f.__doc__) # 结果是:doc of with_logging
例3-2(使用wraps):
import functools
def logged(func):
@functools.wraps(func)
def with_logging(*args, **kwargs):
"""doc of with_logging"""
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logged
def f(x):
"""doc of f"""
return x + x * x
if __name__ == '__main__':
print(f.__name__) # 结果是:f
print(f.__doc__) # 结果是:doc of f
@functools.wraps(func)部署在with_logging函数前,可以理解为:with_logging内部函数只是装饰func,并没有改变func的本质(即没有改变__name__、__doc__等)。