possibly trivial newbie list/array question
Skip Montanaro
skip at pobox.com
Wed Aug 22 08:18:56 EDT 2001
Paul> I just tried your example in Python 2.1.1, Linux, P3-750, lots of
Paul> ram, but with a 100 element list instead of 3 elements.
Paul> a = map(lambda x: x+1.0, range(100))
Paul> Results (running each method 10,000 times like in your example):
Paul> map(lambda x: 4.0*x, a) 1.97 seconds
Paul> [4.0*x for x in a] 3.57 seconds
Paul> I don't know why the list comprehension is slower than the
Paul> map/lambda for this larger list.
A peek at the bytecode might help. Here's the bytecode for calling map:
0 LOAD_GLOBAL 0 (map)
3 LOAD_CONST 1 (<code object <lambda> at 0x8281890, file "<stdin>", line 2>)
6 MAKE_FUNCTION 0
9 LOAD_FAST 0 (a)
12 CALL_FUNCTION 2
and the bytecode for the lambda:
0 LOAD_CONST 1 (4.0)
3 LOAD_FAST 0 (x)
6 BINARY_MULTIPLY
7 RETURN_VALUE
Here's the list comprehension bytecode:
0 BUILD_LIST 0
3 DUP_TOP
4 LOAD_ATTR 0 (append)
7 STORE_FAST 2 (_[1])
10 LOAD_FAST 0 (a)
13 LOAD_CONST 1 (0)
16 FOR_LOOP 20 (to 39)
19 STORE_FAST 1 (x)
22 LOAD_FAST 2 (_[1])
25 LOAD_CONST 2 (4.0)
28 LOAD_FAST 1 (x)
31 BINARY_MULTIPLY
32 CALL_FUNCTION 1
35 POP_TOP
36 JUMP_ABSOLUTE 16
39 DELETE_FAST 2 (_[1])
I think the map/lambda version has a relatively high cost to crank up (make
the lambda, call map), while the list comprehension version has a lower
startup cost, but a higher per-iteration cost.
Also, note that the performance of the list comprehension version will be
hurt more than the map/lambda version if you ran your code at a module scope
(the dis output above was from code inside functions). All the LOAD_FAST
and STORE_FAST instructions (both array indexing operations with no function
call) inside the for loop would become LOAD_GLOBAL and STORE_GLOBAL
instructions (both call PyDict_* functions). The map/lambda case doesn't
suffer from this problem. Using this code:
import time
a = map(lambda x: x+1.0, range(100))
t = time.clock()
for i in range(10000):
x = map(lambda x: 4.0*x, a)
print "map/lambda:", round(time.clock()-t, 2)
t = time.clock()
for i in range(10000):
x = [4.0*x for x in a]
print "list comprehension:", round(time.clock()-t, 2)
def f(a):
t = time.clock()
for i in range(10000):
x = map(lambda x: 4.0*x, a)
print "map/lambda (func):", round(time.clock()-t, 2)
f(a)
def f(a):
t = time.clock()
for i in range(10000):
x = [4.0*x for x in a]
print "list comprehension (func):", round(time.clock()-t, 2)
f(a)
I got this output:
% python lcvsmap.py
map/lambda: 2.88
list comprehension: 5.17
map/lambda (func): 2.94
list comprehension (func): 4.18
which suggests to me that you didn't put your tests in functions. Alex may
have. ;-)
bake-offs-always-need-recipes-ly y'rs,
--
Skip Montanaro (skip at pobox.com)
http://www.mojam.com/
http://www.musi-cal.com/
More information about the Python-list
mailing list