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中关于装饰器的一个小问题请教

5 回复

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)" 会保留被装饰函数的元信息

回到顶部