我有一个函数foo
,它有很多关键字参数:
def foo(blah=1, blih='abc', blohp=('improbable', 'towel', 42)):
pass
我有一个函数bar
,它在循环中调用函数foo
,并展开kwargs
:
def bar(n, **kwargs):
for i in range(n):
foo(**kwargs)
我有三个同样重要的用例:
kwargs
是标准dict
,bar
会针对foo
的每次调用展开它(foo
始终使用相同的关键字参数调用) 。这就是上面实现的内容。kwargs
中的所有值都包含在某种迭代中(长度为n
),而bar
会扩展每个新调用foo
中的每个新值1}}(每次使用不同的关键字参数调用foo
)。kwargs
中的某些值包含在某种迭代中,与2.
类似,而有些则不是,与1.
类似的广播。请注意foo
收到的实际关键字参数是任意的(因此它们实际上可能是一个可迭代的对象 - 如blih
和blohp
)。
实现这种行为并同时满足所有用例的简洁,pythonic模式是什么?
答案 0 :(得分:1)
不确定这是否正是您所要求的:
from itertools import product, combinations
from operator import itemgetter
def wrap_as_iterable(val):
"""Make sure a value is always a list or tuple."""
if isinstance(val, (tuple, list)):
return val
else:
return (val, )
def foo(**kwargs):
print(kwargs) # Just printing the arguments
def bar(**kwargs):
# Wrap each keyword argument as iterable
for key, value in kwargs.items():
kwargs[key] = wrap_as_iterable(value)
# Loop through all combinations of the keyword-value combinations, that's
# just the broadcasting case, no repeats. However repeats would be easy to
# implement with the "range" you already have.
for valuecomb in product(*kwargs.values()):
foo(**dict(zip(kwargs, valuecomb)))
只是为了展示一些示例案例:
>>> bar(blah=1, blih='abc', blohp=('improbable', 'towel', 42))
{'blih': 'abc', 'blah': 1, 'blohp': 'improbable'}
{'blih': 'abc', 'blah': 1, 'blohp': 'towel'}
{'blih': 'abc', 'blah': 1, 'blohp': 42}
>>> bar(blah=(1,2,3), blih=('abc', 'def'), blohp=('improbable', 'towel', 42))
{'blih': 'abc', 'blah': 1, 'blohp': 'improbable'}
{'blih': 'abc', 'blah': 1, 'blohp': 'towel'}
{'blih': 'abc', 'blah': 1, 'blohp': 42}
{'blih': 'abc', 'blah': 2, 'blohp': 'improbable'}
{'blih': 'abc', 'blah': 2, 'blohp': 'towel'}
{'blih': 'abc', 'blah': 2, 'blohp': 42}
{'blih': 'abc', 'blah': 3, 'blohp': 'improbable'}
{'blih': 'abc', 'blah': 3, 'blohp': 'towel'}
{'blih': 'abc', 'blah': 3, 'blohp': 42}
{'blih': 'def', 'blah': 1, 'blohp': 'improbable'}
{'blih': 'def', 'blah': 1, 'blohp': 'towel'}
{'blih': 'def', 'blah': 1, 'blohp': 42}
{'blih': 'def', 'blah': 2, 'blohp': 'improbable'}
{'blih': 'def', 'blah': 2, 'blohp': 'towel'}
{'blih': 'def', 'blah': 2, 'blohp': 42}
{'blih': 'def', 'blah': 3, 'blohp': 'improbable'}
{'blih': 'def', 'blah': 3, 'blohp': 'towel'}
{'blih': 'def', 'blah': 3, 'blohp': 42}
答案 1 :(得分:1)
这是一种方法,假设您希望在bar
和所有n==2
都是可迭代时调用kwargs
两次:
from collections import abc
from itertools import repeat
def foo(blah=1, blih='abc', blohp=('improbable', 'towel', 42)):
print(blah, blih, blohp)
def bar(n, **kwargs):
args = []
for v in kwargs.values():
# Turn single argument to iterable, treat strings as single arg
if isinstance(v, str) or not isinstance(v, abc.Iterable):
v = repeat(v)
args.append(v)
# Iterable that returns a tuple containing one item from each of the
# iterables created above
args = zip(*args)
for i in range(n):
foo(**dict(zip(kwargs, next(args))))
d = {
'blah': 1,
'blih': ['abc', 'def'],
'blohp': [
('improbable', 'towel', 42),
('improbable', 'towel', 43)
]
}
bar(2, **d)
bar(2, blah='blah', blih='blih', blohp='blohp')
输出:
1 abc ('improbable', 'towel', 42)
1 def ('improbable', 'towel', 43)
blah blih blohp
blah blih blohp
答案 2 :(得分:1)
设置bar
,以便您可以告诉它您要广播的内容:
def bar(iter_kwargs, broadcast_kwargs):
for iter_kwarg in iter_kwargs:
foo(**dict(broadcast_kwargs, **iter_kwarg))