Python中关于装饰器的一个小问题请教
def get(path):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
return func(*args, **kw)
wrapper.__method__ = 'GET'
return wrapper
return decorator
假设 func 函数名是 a
print(a.__method__) 的结果就是‘ GET'
我的问题:
这个__method__属性是怎么传递给 func 的,不是 wrapper 的属性么?
Python中关于装饰器的一个小问题请教
a 被 get 装饰后, a 就成了 wrapper 了啊,访问 a 就是访问 wrapper
装饰器是Python里一个挺实用的特性,本质上就是个返回函数的高阶函数。它能在不修改原函数代码的情况下,给函数添加额外功能。
最常见的用法就是在函数定义前加个@decorator。比如下面这个记录函数运行时间的装饰器:
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 执行耗时: {end - start:.4f}秒")
return result
return wrapper
@timer
def my_function():
time.sleep(1)
return "完成"
print(my_function())
这里@timer相当于my_function = timer(my_function)。装饰器timer接收原函数func作为参数,返回一个新的wrapper函数。这个wrapper在调用原函数前后加了计时逻辑。
如果装饰器本身需要参数,就得再包一层。比如要自定义日志消息:
def log_message(msg):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"[日志] {msg}")
return func(*args, **kwargs)
return wrapper
return decorator
@log_message("函数被调用")
def another_func():
return "运行中"
print(another_func())
还有个细节是用functools.wraps来保留原函数的元信息,避免调试时出问题:
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
总结:装饰器就是个包装函数,用@语法糖能让代码更干净。
听说有个叫 functools 的包,里面有个叫 wraps 的装饰器
func 被装饰后相当于 a=wrapper(func),这里的 a 其实就是一个 wrapper ,所以 a 就有了__method__属性;需要注意的是: functools.wraps 装饰器会把 func 的一些 metadata 更新到 a 中,比如__name__,doc,__module__等属性
参考 Cookbook 9.1/9.2 http://python3-cookbook.readthedocs.io/zh_CN/latest/c09/p01_put_wrapper_around_function.html
"[@wraps](/user/wraps)" 会保留被装饰函数的元信息

