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

Python装饰器传*args/**kwargs报错,为何无法直接传**kwargs?

问题

刚接触Python装饰器,想要实现一个装饰器函数,在执行被装饰函数前验证用户指定的关键字参数是否合法。被装饰函数可接受2个或3个参数,但在装饰器的wrapper函数else分支中,直接传递**kwargs会触发UnexpectedArgument错误,只能逐个传递args中的元素,对此存在疑问。相关代码如下:

@staticmethod
def verify_quantity(func):

    def wrapper(*args, **kwargs):
        valid_quantities = ['voltage', 'current', 'power']
        try:
            quantity = kwargs['quantity']
            args = list(kwargs.values())
        except KeyError:
            quantity = args[0]
        if quantity.lower() not in valid_quantities:
            gf.report_msg(f'Parameter "{quantity}" is not a valid scalar quantity. Valid options:', level='error')
            for valid_quantity in valid_quantities:
                print(f'	   > {valid_quantity}')
        else:
            if len(args) == 2:
                return func(args[0], args[1])
            elif len(args) == 3:
                return func(args[0], args[1], args[2])

    return wrapper

@staticmethod
@verify_quantity
def scalar_to_bytes(quantity: str, value: (float, int), num_bytes: int) -> list:
    if quantity.lower() == 'current':
        const = 1e4
    else:
        const = 1e3
    scaled_value = int(const * value)
    min_bytes = (len(hex(scaled_value)) - 2) // 2
    if num_bytes < min_bytes:
        gf.report_msg(f'Minimum bytes required for conversion: {min_bytes}', 'warning')
        num_bytes = min_bytes
    byte_list = list(scaled_value.to_bytes(num_bytes, 'little'))

    return byte_list
解答

报错原因

直接传**kwargs触发错误的核心原因:

  • 当用户用位置参数调用函数时,kwargs是空字典,传递**kwargs等于不给原函数传任何参数,而原函数需要2-3个参数,必然触发参数缺失的错误。
  • 装饰器逻辑修改了args的原始含义:原本args是位置参数元组,在try块里被替换成kwargs.values()的列表,导致参数传递逻辑混乱,无法兼容位置、关键字、混合等多种传参方式。
  • 现有代码只处理了args长度为2或3的情况,其他场景(比如混合传参时args长度为1)会直接跳过函数调用,引发异常。

修正后的装饰器实现

正确的做法是保留原函数的参数传递逻辑,仅提取quantity做验证,验证通过后直接传递原始参数给原函数:

@staticmethod
def verify_quantity(func):
    def wrapper(*args, **kwargs):
        valid_quantities = ['voltage', 'current', 'power']
        # 提取quantity参数:优先取关键字参数,无则取第一个位置参数
        if 'quantity' in kwargs:
            quantity = kwargs['quantity']
        else:
            if not args:
                gf.report_msg('必须提供quantity参数', level='error')
                return
            quantity = args[0]
        
        # 验证合法性
        if quantity.lower() not in valid_quantities:
            gf.report_msg(f'参数"{quantity}"不是合法的标量类型,合法选项:', level='error')
            for valid_q in valid_quantities:
                print(f'    > {valid_q}')
            return
        
        # 验证通过,直接传递原始参数给原函数
        return func(*args, **kwargs)
    return wrapper

说明

  • 该实现兼容位置参数(如scalar_to_bytes('voltage', 12.5, 2))、关键字参数(如scalar_to_bytes(quantity='current', value=0.5))、混合传参等所有调用方式。
  • 无需手动判断参数长度,原函数的参数定义(包括是否有默认值)会自动处理参数数量的问题,逻辑更健壮。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 22:05:07