5

Just say I have a list

a = (3, 2, 9, 4)

And I want to add one to each number and store the result, (I won't need to manipulate the result after), my first thought would be to go:

[x + 1 for x in a]

But what about:

tuple(x + 1 for x in a)

Tuples are meant to be faster right? And if I don't need to change the result after is this code more efficient? Also how does it really work, does the tuple constructor have to create a list out of the generator expression to know the size in advance? Thanks in advance for any explanation.

asked Apr 12, 2013 at 14:04
1
  • The best thing to do is to actually time it. The results could vary based on many factors, including which implementation of python you are using. Commented Apr 12, 2013 at 14:09

3 Answers 3

7

just timeit():

In : a = (3, 2, 9, 4)
In : f1 = lambda: [x + 1 for x in a]
In : f2 = lambda: tuple(x + 1 for x in a)
In : timeit.timeit(f1)
Out: 0.595026969909668
In : timeit.timeit(f2)
Out: 2.360887050628662

so it seems that the tuple constructor variant takes about four times as long, I guess because list comprehensions are fairly optimized (in cpython).

But let's take a closer look:

In : f3 = lambda: list(x + 1 for x in a)
In : timeit.timeit(f3)
Out: 2.5421998500823975

so this takes about the same time as the tuple construction, which indicates that the performance penalty lies in the generator expression overhead. (we can rule out list / tuple construction, see edit below)

It is even about twice as slow as to map() the list:

In : inc = partial(operator.add,1)
In : f4 = lambda:map(inc, a)
In : timeit.timeit(f4)
Out: 1.2346529960632324

I think this really boils down to (cpython) implementation details, so don't rely on this. Anyway - don't worry about performance, it's just a factor of 2-4, use the method which is best to read.

If you really hit performance bottlenecks, investigate and optimize them after you noticed them. And I bet a factor 4 in a list manipulation will be the least of your problems, then.

Edit: Someone mentioned that the lookup cost of "tuple" could cause the slowdown, but this is not the case:

In : f5 = lambda: tuple([x + 1 for x in a])
In : timeit.timeit(f5)
Out: 0.7900090217590332

So I guess it really is the generator expressions overhead which slows things down.

answered Apr 12, 2013 at 14:11
Sign up to request clarification or add additional context in comments.

1 Comment

I would be willing to bet that the difference in time is not in the generator expression. I think it's more likely in the global namespace lookup of the names 'list' and 'tuple'. [] is built in syntax and doesn't require a lookup.
3

The dis module can give you some idea of how the code executes internally...

dis.dis(lambda a: [x + 1 for x in a]) yields...

 1 0 BUILD_LIST 0
 3 LOAD_FAST 0 (a)
 6 GET_ITER
 >> 7 FOR_ITER 16 (to 26)
 10 STORE_FAST 1 (x)
 13 LOAD_FAST 1 (x)
 16 LOAD_CONST 1 (1)
 19 BINARY_ADD
 20 LIST_APPEND 2
 23 JUMP_ABSOLUTE 7
 >> 26 RETURN_VALUE

...and dis.dis(lambda a: tuple(x + 1 for x in a)) yields...

 1 0 LOAD_GLOBAL 0 (tuple)
 3 LOAD_CONST 1 (<code object <genexpr> at 0x7f62e9eda930, file "<stdin>", line 1>)
 6 MAKE_FUNCTION 0
 9 LOAD_FAST 0 (a)
 12 GET_ITER
 13 CALL_FUNCTION 1
 16 CALL_FUNCTION 1
 19 RETURN_VALUE

...but you may not be able to infer much from that. If you want to know which is faster, check out the timeit module.

answered Apr 12, 2013 at 14:15

Comments

1

In most cases, the efficiency between tuple and list really doesn't matter much.It you really care about it, you can use timeit to have a test.

The most important difference between tuple and list is that tuple is immutable and list is multable. It means that you can change list's value but can't do it with tuple. You can hash tuple but can't do it to with list. For example

k_tuple = ('a', 'b')
k_list = ['a', 'b']
d = {}
d[k_tuple] = 'c' # It is ok
d[k_list] = 'c' #It raise exception.

What's more, when list is as function's argument, it is assigned by reference. When tuple is as function's argument, it is assigned by value.

answered Apr 12, 2013 at 14:16

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.