Python 简化函数调用的3种技巧
Python 简化函数调用的3种技巧
亚马逊又要放大招?7月15日亚马逊大咖在线直播带你一探究竟
全能型容器服务的技术架构是什么样?亚马逊容器专家在线深度剖析并演示,马上预约!
假设有一个函数,这个函数需要接收4个参数,并返回这4个参数的和:
def sum_four(a, b, c, d):
return a + b + c + d
如果需要固定*后前三个参数,仅改变*后一个参数的值,这时候可能需要这么调用:
>>> a, b, c = 1, 2, 3
>>> sum_four(a=a, b=b, c=c, d=1)
7
>>> sum_four(a=a, b=b, c=c, d=2)
8
>>> sum_four(a=a, b=b, c=c, d=3)
9
>>> sum_four(a=a, b=b, c=c, d=4)
10
这样写实在是太丑了,如果用 Map 函数,是否能简化代码?
答案是肯定的,但是Map函数【一般】只能接受单一元素,如果你强行使用的话,它会报这样的错:
>>> list(map(sum_four, [(1, 2, 3, 4)]))
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
TypeError: sum_four() missing 3 required positional arguments: ‘b’, ‘c’, and ‘d’
怎么解决?
方案1: itertools.starmap
可以使用 itertools 的函数 starmap 替换Map.
它与Map不同,允许接受一个元组作为传入sum_four的参数。
>>> import itertools
>>> list(itertools.starmap(sum_four, [(1, 2, 3, 4)]))
[10]
非常棒,这样的话,上述问题就可以使用starmap函数解决:
>>> import itertools
>>> ds = [1, 2, 3, 4]
>>> items = ((a, b, c, d) for d in ds)
>>> list(items)
[(1, 2, 3, 1), (1, 2, 3, 2), (1, 2, 3, 3), (1, 2, 3, 4)]
>>> list(itertools.starmap(sum_four, items))
[7, 8, 9, 10]
请注意 items 是一个生成器,这是为了避免 items 过大导致内存消耗量过大。平时开发的时候注意这些细节,能够使你和普通的开发者拉开差距。
方案2: functools.partial
第二种解决方案是使用 partial 函数固定前三个参数。
根据文档,partial将“冻结”函数的参数的某些部分,从而生成简化版的函数。
因此上述问题的解决方案就是:
>>> import functools
>>> partial_sum_four = functools.partial(sum_four, a, b, c)
>>> partial_sum_four(3)
9
>>> # 这样就可以使用map函数了:
>>> list(map(partial_sum_four, ds))
[7, 8, 9, 10]
方案3: itertools.repeat()
事实上,Map 函数是允许传递可迭代参数的,但是有一个有趣的特点,他会用每个可迭代对象里的项作为传入函数的不同参数。这样说可能太过于抽象了,来看看实际的例子:
>>> list(map(sum_four, [1,1,1,1], [2,2,2,2], [3,3,3,3], [1,2,3,4]))
[7, 8, 9, 10]
明显,每次都使用了不同数组中对应下标的项传入函数进行计算。
这样,我们可以使用这个特点进行优化。
itertools.repeat() 函数能够根据参数产生一个迭代器,该迭代器一次又一次返回对象。不指定times参数,它将无限期运行。
而 Map 函数会在*短的可迭代对象被迭代完后,就会自动停止运行。
结合这两个特点,上述问题的解决方案就出来了:
>>> import itertools
>>> list(map(sum_four, itertools.repeat(a), itertools.repeat(b), itertools.repeat(c), ds))
[7, 8, 9, 10]
这招非常巧妙,缺点是能读懂的人不多。不过没关系,计算机世界中某些东西知道就好,你并不一定需要去使用它