假设有一个函数,这个函数需要接收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]
这招还是非常巧妙的。缺点是能读懂的人不多。不过没关系,计算机世界中某些东西知道就好,你并不一定需要去使用它。
比如本文中的这几种解决方案,日常生活工作中一般用不到,所以你不需要死记硬背,但你需要知道【有这样的问题】和【有这些解决方案】,万一遇到了相似的场景,你就可以回忆起这篇文章并快速找到解决的方法。
我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。
有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。
原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!
Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典