在以下函数Form
中,我们可以先f
循环,也可以先a
循环。
如何减少代码冗余?
b
我在考虑product
,但我们仍然会:
def myfunction(a):
pass
def f(first_loop_on_a=True):
if first_loop_on_a:
for a in range(10):
A = "%010i" % a
myfunction(a)
for b in range(5):
print A, b
else:
for b in range(5):
for a in range(10):
A = "%010i" % a
myfunction(a)
print A, b
f(True)
f(False)
仍然有点多余。
答案 0 :(得分:1)
首先使用product
值的来源b
时,使用生成器表达式来翻转元组如何:
def f(first_loop_on_a=True):
if first_loop_on_a:
gen = product(range(10, range(5))
else:
gen = (a, b for b, a in product(range(5), range(10)))
for a, b in gen:
myfunction2(a, b)
我会注意到这仍然与原始函数不同,因为在原始函数中,myfunction
在两个分支之间被调用了不同的次数(10次或50次)。新函数总是在内循环中调用它(通过myfunction2
),因此它总是运行50次。
答案 1 :(得分:1)
如果你的功能过于重复,你可以一步一步地重构。
您想要分解的共性是在某些迭代器上调用myfunction2(a, b)
。但是第二个迭代器不仅反转product
args,而且每个对的元素也是如此。所以:
def f(first_loop_on_a=True):
if first_loop_on_a:
prod = product(range(10), range(5))
else:
prod = (b, a for (a, b) in product(range(5), range(10)))
for a, b in prod:
myfunction2(a, b)
如果您多次执行此操作,则可以将元组翻转到函数中:
def flippair(p):
a, b = p
return b, a
def f(first_loop_on_a=True):
if first_loop_on_a:
prod = product(range(10), range(5))
else:
prod = map(flippair, product(range(5), range(10)))
for a, b in prod:
myfunction2(a, b)
(或者,当然,flippair
可以返回p[::-1]
- 或者,因为您不需要元组,但只需要任何类型的可迭代,只需使用reversed
。但这种方式似乎更明确,而且仍然很容易简洁。)
但我认为最好的解决方案是使用myfunction
的关键字参数:
def kwify(order, pairs):
return (dict(zip(order, pair)) for pair in pairs)
def f(first_loop_on_a=True):
if first_loop_on_a:
prod = kwify('ab', product(range(10), range(5)))
else:
prod = kwify('ba', product(range(5), range(10)))
for kwpair in prod:
myfunction2(**kwpair)
这很明显,您将a
值a
和b
值作为b
传递,而不是将它们翻转,以便它们最终成为b
和a
,然后将它们翻转以按相反的顺序传递它们。
虽然我们正在努力,为什么要重复这些范围?
def kwify(order, pairs):
return (dict(zip(order, pair)) for pair in pairs)
def f(first_loop_on_a=True):
arange, brange = range(10), range(5)
if first_loop_on_a:
prod = kwify('ab', product(arange, brange))
else:
prod = kwify('ba', product(brange, arange))
for kwpair in prod:
myfunction2(**kwpair)
...此时您还可以提供他们名称:
def kwify(order, pairs):
return (dict(zip(order, pair)) for pair in pairs)
def f(first_loop_on_a=True):
ranges = {'a': range(10), 'b': range(5)}
order = 'ab' if first_loop_on_a else 'ba'
prod = kwify(order, product(*itemgetter(*order)(ranges)))
for kwpair in prod:
myfunction2(**kwpair)
...或者,甚至可能将对range
的调用分解为:
def kwify(order, pairs):
return (dict(zip(order, pair)) for pair in pairs)
def f(first_loop_on_a=True):
ranges = {'a': 10, 'b': 5}
order = 'ab' if first_loop_on_a else 'ba'
prod = kwify(order, product(*map(range, itemgetter(*order)(ranges))))
for kwpair in prod:
myfunction2(**kwpair)
这可能只是选择" a-then-b"与" b-then-a",但如果你想扩展到选择三个变量的不同排列,或动态列表中的任意顺序等,那么它可能值得做。
答案 2 :(得分:0)
您可以通过reversed
:
>>> import itertools as it
>>>
>>> def itr(A, B, a_first=True):
... return it.product(*map(range, (A, B))) if a_first else map(reversed, it.product(*map(range, (B, A))))
...
>>> [(a, b) for a, b in itr(2, 3, True)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
>>> [(a, b) for a, b in itr(2, 3, False)]
[(0, 0), (1, 0), (0, 1), (1, 1), (0, 2), (1, 2)]