Ho trovato le varie risposte davvero eleganti (soprattutto quelle di Alex Martelli) ma volevo quantificare le prestazioni in prima persona, quindi ho elaborato il seguente script:
from itertools import repeat
N = 10000000
def payload(a):
pass
def standard(N):
for x in range(N):
payload(None)
def underscore(N):
for _ in range(N):
payload(None)
def loopiter(N):
for _ in repeat(None, N):
payload(None)
def loopiter2(N):
for _ in map(payload, repeat(None, N)):
pass
if __name__ == '__main__':
import timeit
print("standard: ",timeit.timeit("standard({})".format(N),
setup="from __main__ import standard", number=1))
print("underscore: ",timeit.timeit("underscore({})".format(N),
setup="from __main__ import underscore", number=1))
print("loopiter: ",timeit.timeit("loopiter({})".format(N),
setup="from __main__ import loopiter", number=1))
print("loopiter2: ",timeit.timeit("loopiter2({})".format(N),
setup="from __main__ import loopiter2", number=1))
Ho anche trovato una soluzione alternativa che si basa su quella di Martelli e utilizza map()
per chiamare la funzione di payload. OK, ho tradito un po 'il fatto che mi sono preso la libertà di far accettare al parametro payload un parametro che viene scartato: non so se c'è un modo per aggirare questo. Tuttavia, ecco i risultati:
standard: 0.8398549720004667
underscore: 0.8413165839992871
loopiter: 0.7110594899968419
loopiter2: 0.5891903560004721
quindi l'utilizzo di map produce un miglioramento di circa il 30% rispetto allo standard per loop e di un ulteriore 19% rispetto a Martelli.