python学习笔记 | 一次使用装饰器时引发的思考
前言
今天使用装饰器时,遇到这样一个错误:
根据报错提示,大意是指不能打包一个空值。而我写的装饰器是这样的:
def catch_error(func):
def wrapper(*args,**kwargs):
try:
print(f'正在执行 - {func.__name__}')
func(*args,**kwargs)
except Exception as e:
print(e)
return wrapper
而当我不加上装饰器,单独运行函数的时候,却可以正常执行,并得到函数返回值
于是这时候问题的矛头就指向了我写的这个装饰器,既然报错提示为空值,那我就看一下这个函数返回值有没有问题,正常的返回值应该是「两个列表」
这就很奇怪了,为什么是“None”??👃
于是我进一步检查一下现在的这个函数名
???函数名不应该是"get_aim_note"吗?怎么会是"wrapper"?BTW 这个"wrapper"不是我在装饰器中声明的函数吗?怎么跑到这儿来了
云雾初开
OK,分析完问题,我们得到了两个信息:
-
被装饰后的函数其实不是原来的函数了,而是装饰器中声明的函数,也就是这个"wrapper",因此我在后续调用这个函数的时候,这个函数的返回对象其实是这个“wrapper”函数,而不是本来被装饰的函数,也难怪会返回一个None了。
-
被装饰后的函数其实已经是另外一个函数了,函数名等函数属性,会发生改变
拨云见日
-
第一个问题,我们本意是想得到「被装饰函数」的对象,却得到了装饰器中的嵌套函数“wrapper”。针对这个问题,我的思路是:在「wrapper函数体内」返回(return)「被装饰函数对象」
def catch_error(func): def wrapper(*args,**kwargs): try: print(f"正在运行 - {func.__name__}") return func(*args,**kwargs) except Exception as e: print(e) return wrapper
在第五行的位置我修改为
return func(*args,**kwargs)
,通过这个操作,装饰器装饰函数的时候,返回的是wrapper函数的对象,而wrapper函数,它现在也有返回值了,就是这个func(*args,**kwargs)
,也就是我们最开始的「被装饰函数」。有点绕哈哈,,,㊙️
-
第二个问题,被装饰之后,「函数名等函数属性」会发生改变。针对这个问题,python的functools包提供了一个叫"wraps"的装饰器来消除这样的副作用,它能保留原有函数的名称和docstring -
from functools import wraps
from functools import wraps def catch_error(func): @wraps(func) # wraps装饰器 def wrapper(*args,**kwargs): try: print(f'正在执行 - {func.__name__}') return func(*args,**kwargs) # except Exception as e: print(e) return wrapper
结语
python的装饰器功能十分具有魅力,期待在后续的使用中发现更多的玩法。
更多 - python学习笔记 | 装饰器