7

Is there any reason for memory, speed or whatever, that I would want to use:

tuple(i for i in range(5000))

instead of:

[i for i in range(5000)]

If I didn't mind the immutability of tuples

Mazdak
  • 105,000
  • 18
  • 159
  • 188
ragardner
  • 1,836
  • 5
  • 22
  • 45
  • 1
    Use the former if you need a tuple, use the latter (or `list(range(5000))`) if you need a list. – vaultah May 05 '17 at 15:01
  • the choice between `tuple` or `list` is based on what you are planning on doing with it and not resources. – Ma0 May 05 '17 at 15:02
  • Apart from the overhead of the conversion, the tuple will be smaller and faster, since it lacks the mechanism to make it mutable, allow fast inserts etc. But the conversion of course costs extra time (once). – Jacques de Hooge May 05 '17 at 15:02
  • The first one will be slower, though it might take a bit less memory (in the end) – Eli Korvigo May 05 '17 at 15:02
  • @EliKorvigo slower to construct? – ragardner May 05 '17 at 15:03
  • 1
    For speed, you could remove the unneeded comprehension ;) `tuple(range(5000))` and `list(range(5000))`, or, depending on your needs, just `range(5000)`. – Eric Duminil May 05 '17 at 15:06
  • @new_to_coding yep – Eli Korvigo May 05 '17 at 22:13
  • Does this answer your question? [Generator Expressions vs. List Comprehension](https://stackoverflow.com/questions/47789/generator-expressions-vs-list-comprehension) – ggorlen Jul 12 '20 at 20:01

2 Answers2

6

Basically a list comprehension is faster than a generator expression and as the reason is that its iteration performs in C (Read the @Veedrac's comment for the reason). But the only reason that should use a generator expression within tuple is that you want to perform some operations on your items and/or filter them and more importantly you want a tuple (because of the immutability and its benefits against mutable objects).

After all you can always timeit your code:

In [10]: %timeit tuple(i for i in range(5000))
1000 loops, best of 3: 325 µs per loop

In [11]: %timeit [i for i in range(5000)]
1000 loops, best of 3: 199 µs per loop

Also note that as I mentioned, if you want to use comprehensions you must needed to perform an operation on your items otherwise you can call the function directly on your iterator, which is faster:

In [12]: %timeit list(range(5000))
10000 loops, best of 3: 98.3 µs per loop
Mazdak
  • 105,000
  • 18
  • 159
  • 188
  • 6
    "its iteration performs in C" → This is one of the most pervasive, utterly false myths about Python. The list comprehension is faster because suspending and resuming a function's frame is slow, not because there's anything particularly special about list comprehensions. – Veedrac May 05 '17 at 18:20
  • @Veedrac Do you have any reliable resource for that? 'Cause, as far as I remember I've read that from Mark Lutz Learning python's book a long while ago. If it's not like so (which now that I think more probably you're right) not only that book but also other famous resources that might have mentioned this statement need a serious criticism. – Mazdak May 05 '17 at 18:46
  • I could walk you through the code that compiles this (I've even contributed to parts of it), but I can't find any reference on Google at the moment. I know they exist because I've written about this before, but my Google-fu is failing me. – Veedrac May 05 '17 at 19:26
2

Generator expressions (or genexps, for short) are best used in loops to save memory when handling a lot of data. It's not considered good practice to expand a genexp to an interable data type (such as a list, tuple, set).

Also keep in mind that range() in Python 3 is like xrange() in Python 2. It returns a generator. In fact, xrange() tends to be faster even for 5000. Note: xrange() does not exist in Python 3.

Ricardo Branco
  • 5,740
  • 1
  • 21
  • 31