You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python装饰器中wrapper的*args与**kwargs参数工作机制咨询

装饰器示例代码

旧版本(仅支持单个参数)

# This version only accepts one argument
def shout(fn):
    def wrapper(name):
        return fn(name).upper()
    return wrapper

新版本(支持任意参数)

# This version works with any number of args
def shout(fn):
    def wrapper(*args, **kwargs):
        print(f"abc is {fn.__name__}")
        return fn(*args, **kwargs).upper()
    return wrapper

@shout
def greet(name):
    return f"Hi, I'm {name}."
@shout
def order(main, side):
    return f"Hi, I'd like the {main}, with a side of {side}, please."
@shout
def lol():
    return "lol"

print(greet("todd"))
print(order(side="burger", main="fries"))
print(lol())

问题

当wrapper函数执行时,它如何获知要赋值给*args和**kwargs的参数值?我们并未在此定义这些参数值,而是为被装饰函数传递了side="burger"、main="fries"这类参数。**kwargs会展开字典,但该字典是何时定义的?side="burger"、main="fries"如何成为wrapper函数的参数并被分配给args和kwargs?为何传给被装饰函数的参数会被分配给wrapper函数的参数?


解答

这问题问得特别关键!核心要搞懂Python装饰器的调用逻辑和参数传递机制,咱们一步步拆解:

  • 装饰器本质是「函数替换」
    当你用@shout装饰greet、order这些函数时,Python在后台悄悄执行了这样的操作:greet = shout(greet)。也就是说,原来的greet函数被替换成了shout返回的wrapper函数!所以当你调用greet("todd")时,你其实是在调用wrapper函数,而非最初定义的那个greet。

  • 参数直接传给了wrapper
    既然实际调用的是wrapper,那你传入的所有参数(不管是位置参数还是关键字参数)自然会直接传递给wrapper。这里的*args和**kwargs是Python的语法糖:

    • *args会把所有位置参数打包成一个元组;
    • **kwargs会把所有关键字参数打包成一个字典。
      比如你调用order(side="burger", main="fries"),实际上是调用wrapper(side="burger", main="fries"),这时候wrapper的**kwargs就会自动被赋值为{"side": "burger", "main": "fries"}——这个字典是Python解释器在你调用函数时自动临时创建的,不需要你手动定义。
  • 参数最终会传递给原函数
    wrapper里的fn(*args, **kwargs)是「解包」操作:把args元组里的元素作为位置参数传给原函数fn,把kwargs字典里的键值对作为关键字参数传给fn。这样原函数(比如order)就能拿到它需要的main和side参数,正常执行逻辑。

  • 整个流程梳理
    调用被装饰后的函数 → 实际调用wrapper函数 → wrapper接住所有传入的参数 → wrapper把参数原封不动传给原函数 → 拿到原函数的返回值后做额外处理(比如转大写) → 返回最终结果。

内容的提问来源于stack exchange,提问作者v7676

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 11:27:34