why doesn't ** unpack kwargs in function calls?
这是困扰我一段时间的事情:
1 2 3 4 | def test (*args, **kwargs): print target test(foo='bar', target='baz') |
我假设底部的afunc调用中的
编辑:我整理了一个案例,在这个案例中,解包*args和**kwargs可能会有所帮助:
假设我有一个打印列表的函数:
1 2 | def printList (inputList=None): print inputList |
我希望能够传递无列表并提供默认列表:
1 2 3 4 5 6 7 8 | def ensureList (listFunc): def wrapper (inputList=None): listFunc(inputList=inputList or ['a','default','list']) return wrapper @ensureList def printList (inputList=None): print inputList |
现在我想让列表中继器变得更复杂一点:
1 2 3 | @ensureList def repeatList (inputList=None): print inputList*2 |
那很好。但现在我想重复变量:
1 2 3 | @ensureList def repeatList (times, inputList=None): print inputList*times |
现在你可以说:
1 | repeatList(5) |
它将生成默认列表并重复5次。
当然,这失败了,因为包装器无法处理times参数。我当然可以这样做:
1 2 | @ensureList def repeatList (inputList=None, times=1) |
但我总是要这样做:
1 | repeatList(times=5) |
也许在某些情况下,我想强制提供一个值,所以非关键字arg是有意义的。
当我去年第一次遇到这样的问题时,我认为一个简单的解决方案是删除包装器上的需求:
1 2 3 4 5 | def ensureList (listFunc): "info here re: operating on/requiring an inputList keyword arg" def wrapper (*args, **kwargs): listFunc(inputList=inputList or ['a','default','list']) return wrapper |
不过,这行不通。这就是为什么我想让args和kwargs实际扩展,或者我想有一种方法来扩展。然后无论我提供什么args和kwargs,它们实际上都会填充参数,而不是列表和dict。包装器中的文档将解释需求。如果传入inputlist,它实际上会进入,并且从包装器回调repeatlist中的inputlist是有效的。如果没有传入inputlist,它将在回调中创建带有默认列表的repeatlist。如果您的功能不关心,而是使用了*Kwargs,它将优雅地接受它,而不会有任何问题。
如果上述任何一个错误(超出了一般概念),请道歉。我在这里打出来的,还没有测试过,很晚了。
回答"为什么在函数调用中**不解包kwargs?"是:因为这是一个坏主意,开发函数的人不希望局部变量只根据调用参数出现。
所以,这不是它的工作方式,而且您肯定不希望Python这样做。
要访问函数中的
1 2 | def test(target='<default-value>', *args, **kwargs): print target |
或
1 2 3 | def test(*args, **kwargs): target = kwargs.get('target', '<default-value>') print target |
但是,如果您希望黑客(仅限教育使用)解包**Kwargs,可以尝试:
1 2 3 4 | def test(*args, **kwargs): for i in kwargs: exec('%s = %s' % (i, repr(kwargs[i]))) print target |
对于这个特殊的案例,显而易见的方法是
1 2 3 4 | def test(foo=None, target=None): print target test(foo='bar', target='baz') |
如果要按名称访问函数内部的参数,请在参数列表中显式命名该参数。