[英]How can I treat positional arguments as keyword arguments in Python 2
对于我正在编写的装饰器,我想操作 function 的特定命名参数。 考虑以下装饰器:
def square_param(param):
def func_decorator(func):
def func_caller(*args,**kwargs):
kwargs[param] = kwargs[param] * kwargs[param]
return func(*args,**kwargs)
return func_caller
return func_decorator
应用于下一个 function:
@square_param('dividend')
def quotient(divisor=1,dividend=0):
return dividend/divisor
如果将股息作为关键字参数调用,这将起作用,例如:
>>> quotient(dividend=2)
4
但是,当作为位置参数给出时,这将失败。
>>> quotient(3,4)
TypeError: quotient() got multiple values for keyword argument 'dividend'
使用 Python 3 我可以通过强制参数始终作为关键字给出来解决这个问题:
@square_param('dividend')
def quotient(divisor=1,*,dividend=0):
return dividend/divisor
但我想支持 Python 2 并且我想对 function 施加尽可能少的限制。
有没有办法可以在我的装饰器中修复这种行为?
首先,您的square_param
装饰器不起作用,因为它不返回函数。 它需要是:
def square_param(param):
def func_decorator(func):
def func_caller(*args,**kwargs):
kwargs[param] = kwargs[param] * kwargs[param]
return func(*args,**kwargs)
return func_caller
return func_decorator
现在我接受了@Dirk 的建议并查看了inspect
模块。 您可以通过首先检查参数是否为函数的位置 arguments 之一,其次是否已指定该位置参数,然后修改该参数 position 来做到这一点。 您还需要确保仅在参数作为关键字参数提供时才修改 kwargs。
import inspect
def square_param(param):
def func_decorator(func):
def func_caller(*args,**kwargs):
funparams = inspect.getargspec(func).args
if param in funparams:
i = funparams.index(param)
if len(args) > i:
args = list(args) # Make mutable
args[i] = args[i] * args[i]
if param in kwargs:
kwargs[param] = kwargs[param] * kwargs[param]
return func(*args,**kwargs)
return func_caller
return func_decorator
即使不使用 Inspect 我们也可以获得 function 参数
>>> func = lambda x, y, args: (x, y, {})
>>> func.func_code.co_argcount
3
>>> func.func_code.co_varnames
('x', 'y', 'args')
这可能只是切线相关,但我发现解决类似问题很有用。 我想将*args
和**kwargs
合并到一个字典中,这样我的以下代码就可以在不考虑 args 是如何进入的情况下进行处理,并且我不想改变现有的kwargs
变量,否则我只会使用kwargs.update()
. kwargs.update()
。
all_args = {**kwargs, **{k: v for k, v in zip(list(inspect.signature(func).parameters), args)}}
# optionally delete `self`
del (all_args['self'])
更新:虽然这有效,但这个答案有更好的技术。 部分:
bound_args = inspect.signature(f).bind(*args, **kwargs)
bound_args.apply_defaults()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.