通八洲科技

Python装饰器参数怎么传递_带参数装饰器示例解析【教程】

日期:2025-12-20 00:00 / 作者:冰川箭仙
带参数的装饰器本质是“装饰器工厂”,需三层嵌套:外层接收装饰器参数并返回中层函数,中层接收被装饰函数并返回内层函数,内层接收调用参数、执行逻辑并返回原函数结果;漏掉任一层return将导致TypeError或返回None。

带参数的装饰器本质是“装饰器工厂”,它先接收参数,再返回一个真正的装饰器函数。关键在于多一层函数嵌套:外层接收装饰器参数,中层接收被装饰函数,内层执行实际逻辑。

装饰器参数传递的三层结构

带参数装饰器必须有三层嵌套函数:

一个实用的带参日志装饰器

下面是一个记录执行级别和函数名的日志装饰器:

def log(level='INFO'):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f'[{level}] Calling {func.__name__}')
            result = func(*args, **kwargs)
            print(f'[{level}] {func.__name__} finished')
            return result
        return wrapper
    return decorator

@log('DEBUG') # 传入装饰器参数 'DEBUG' def greet(name): return f'Hello, {name}!'

print(greet('Alice'))

输出为:

[DEBUG] Calling greet
[DEBUG] greet finished
Hello, Alice!

为什么不能直接在中层接收装饰器参数?

因为 Python 解析@log('DEBUG')时,会立即调用log('DEBUG'),期望它返回一个可调用对象(即真正的装饰器)。如果log没有外层,它就只能接收func,无法拿到'DEBUG'——此时@log('DEBUG')等价于log('DEBUG')(func),而log('DEBUG')必须返回一个能接收func的函数。

带参装饰器配合 functools.wraps 保持元信息

不加@wraps会导致被装饰函数的__name____doc__丢失。正确写法:

from functools import wraps

def log(level='INFO'): def decorator(func): @wraps(func) # 修复函数元信息 def wrapper(*args, *kwargs): print(f'[{level}] {func.name} start') return func(args, **kwargs) return wrapper return decorator

这样greet.__name__仍是'greet',而非'wrapper'

常见错误:漏掉某一层 return

容易出错的点:

记住:每一层函数体末尾都要有明确的return,且返回值类型要匹配调用预期。