像这样的操作并不需要使用 map
,实际上通过使用列表推导式可以提高代码的可读性:
>>> [RPS_winner(a, b) for a, b in rounds]
[1, 2, 2, 2, 0, 1, 1, 2, 0, 1]
另一种可能性是使用
itertools.starmap
,它专门为此设计:
from itertools import starmap
list(starmap(RPS_winner, rounds))
当然,您也可以手动完成相同的操作:
list(map(lambda ab: RPS_winner(*ab), rounds)
如果您打算使用非常长的轮次
列表,则最好将其重写为:
def RPS_winner_star(ab):
return RPS_winner(*ab)
list(map(RPS_winner_star, rounds))
注意
使用map
或类似方法的合理理由是,rounds
实际上不是一个列表而是另一个迭代器。在这种情况下,获得一个新的迭代器,可以在rounds
进行时输出赢家,而不需要创建列表,这样很好。例如,你可以把这个结果迭代器"管道化"到一个Counter
中:
irounds = generate_rounds(n=1_000_000)
iwinner = map(RPS_winner_star, irounds)
score_board = Counter(iwinner)
这里是一个完整的示例和时间记录:
(注意:为了减少总体测量时间,generate_rounds生成器现在具有可预测的重复性;我们还在最后的时间比较中减去了生成器中花费的时间。)
import random
from collections import Counter
from itertools import starmap
def generate_rounds(n):
choices = list('RPS')
m = len(choices)
for k in range(n):
i = k % m
j = (k // m) % m
yield choices[i], choices[j]
def f_onlygen(n):
for _ in generate_rounds(n):
pass
def f_map(n):
irounds = generate_rounds(n)
iwinner = map(RPS_winner_star, irounds)
return Counter(iwinner)
def f_starmap(n):
irounds = generate_rounds(n)
iwinner = starmap(RPS_winner, irounds)
return Counter(iwinner)
def f_listmap(n):
rounds = list(generate_rounds(n))
winner = list(map(RPS_winner_star, rounds))
return Counter(winner)
def f_listcomprehension(n):
rounds = list(generate_rounds(n))
winner = [RPS_winner(a, b) for a, b in rounds]
return Counter(winner)
def f_comprehension(n):
irounds = generate_rounds(n)
winner = [RPS_winner(a, b) for a, b in rounds]
return Counter(winner)
测量:
n = 1_000_000
t = {}
t['onlygen'] = %timeit -o f_onlygen(n)
t['map'] = %timeit -o f_map(n)
t['starmap'] = %timeit -o f_starmap(n)
t['listmap'] = %timeit -o f_listmap(n)
t['listcomprehension'] = %timeit -o f_listcomprehension(n)
t['comprehension'] = %timeit -o f_comprehension(n)
结果:
res = sorted([
(k, v.average, v.average - t['onlygen'].average)
for k, v in t.items()
], key=lambda tup: tup[2])
print(f'{"name":<17} {"total":<6} above onlygen')
for name, tot, rel in res:
print(f'{name:<17} {tot*1000:3.0f} ms, {rel*1000:3.0f} ms')
name total above onlygen
onlygen 172 ms, 0 ms
comprehension 235 ms, 62 ms
starmap 376 ms, 204 ms
map 432 ms, 260 ms
listcomprehension 470 ms, 298 ms
listmap 482 ms, 310 ms
generate_rounds
的工作时间吗?这似乎不太好。 - no comment