装饰器Python库隐藏kwargs在args中

3 投票
1 回答
813 浏览
提问于 2025-04-16 21:33

我遇到了一个很奇怪的情况,跟装饰器库有关,下面的代码解释了这个问题:

from decorator import decorator    

@decorator
def wrap(f, a, *args, **kwargs):
    print 'Decorator:', a, args, kwargs
    return f(a, *args, **kwargs)

def mywrap(f):
    def new_f(a, *args, **kwargs):
        print 'Home made decorator:', a, args, kwargs
        return f(a, *args, **kwargs)
    return new_f

@wrap
def funcion(a, b, *args, **kwargs):
    pass

@mywrap
def myfuncion(a, b, *args, **kwargs):
    pass

funcion(1, b=2)
myfuncion(1, b=2)

运行这个脚本会打印出:

$ python /tmp/test.py 
Decorator: 1 (2,) {}
Home made decorator: 1 () {'b': 2}

这个'decorator'把关键字参数(kwargs)藏在了位置参数(args)里面,我该怎么解决这个问题,而不想自己写一个装饰器呢?

谢谢。

1 个回答

6

你在调用这个函数的时候用 b=2 并不意味着 b 就是一个关键字参数;在原来的函数里,b 是一个位置参数。如果原本没有叫 b 的参数,而你指定了 b=2,那么这时候 b 才会变成一个关键字参数。

decorator 的行为其实是最正确的;它生成的包装器和 funcion() 的参数列表是一样的,而你自己做的“自制”装饰器生成的包装器并没有把 b 作为一个命名参数。这个“自制”的包装器“错误地”把 b 放到了 kwargs 里,因为 myfuncion() 的参数列表清楚地表明 b 不是一个关键字参数,但这个信息对调用者是隐藏的。

保留函数的参数列表是一种特性,而不是错误,这在 decorator 中是很重要的。

撰写回答