As we all know, there’s list comprehension, like
[i for i in [1, 2, 3, 4]]
and there is dictionary comprehension, like
{i:j for i, j in {1: 'a', 2: 'b'}.items()}
but
(i for i in (1, 2, 3))
will end up in a generator, not a tuple comprehension. Why is that?
My guess is that a tuple is immutable, but this does not seem to be the answer.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
You can use a generator expression:
tuple(i for i in (1, 2, 3))
but parentheses were already taken for … generator expressions.
Method 2
Raymond Hettinger (one of the Python core developers) had this to say about tuples in a recent tweet:
#python tip: Generally, lists are for looping; tuples for structs. Lists are homogeneous; tuples heterogeneous. Lists for variable length.
This (to me) supports the idea that if the items in a sequence are related enough to be generated by a, well, generator, then it should be a list. Although a tuple is iterable and seems like simply a immutable list, it’s really the Python equivalent of a C struct:
struct {
int a;
char b;
float c;
} foo;
struct foo x = { 3, 'g', 5.9 };
becomes in Python
x = (3, 'g', 5.9)
Method 3
Since Python 3.5, you can also use splat * unpacking syntax to unpack a generator expresion:
*(x for x in range(10)),
Method 4
As another poster macm mentioned, the fastest way to create a tuple from a generator is tuple([generator]).
Performance Comparison
-
List comprehension:
$ python3 -m timeit "a = [i for i in range(1000)]" 10000 loops, best of 3: 27.4 usec per loop
-
Tuple from list comprehension:
$ python3 -m timeit "a = tuple([i for i in range(1000)])" 10000 loops, best of 3: 30.2 usec per loop
-
Tuple from generator:
$ python3 -m timeit "a = tuple(i for i in range(1000))" 10000 loops, best of 3: 50.4 usec per loop
-
Tuple from unpacking:
$ python3 -m timeit "a = *(i for i in range(1000))," 10000 loops, best of 3: 52.7 usec per loop
My version of python:
$ python3 --version Python 3.6.3
So you should always create a tuple from a list comprehension unless performance is not an issue.
Method 5
Comprehension works by looping or iterating over items and assigning them into a container, a Tuple is unable to receive assignments.
Once a Tuple is created, it can not be appended to, extended, or assigned to. The only way to modify a Tuple is if one of its objects can itself be assigned to (is a non-tuple container). Because the Tuple is only holding a reference to that kind of object.
Also – a tuple has its own constructor tuple() which you can give any iterator. Which means that to create a tuple, you could do:
tuple(i for i in (1,2,3))
Method 6
My best guess is that they ran out of brackets and didn’t think it would be useful enough to warrent adding an “ugly” syntax …
Method 7
Tuples cannot efficiently be appended like a list.
So a tuple comprehension would need to use a list internally and then convert to a tuple.
That would be the same as what you do now : tuple( [ comprehension ] )
Method 8
Parentheses do not create a tuple. aka one = (two) is not a tuple. The only way around is either one = (two,) or one = tuple(two). So a solution is:
tuple(i for i in myothertupleorlistordict)
Method 9
I believe it’s simply for the sake of clarity, we do not want to clutter the language with too many different symbols. Also a tuple comprehension is never necessary, a list can just be used instead with negligible speed differences, unlike a dict comprehension as opposed to a list comprehension.
Method 10
On my python (3.5) using a generator with deque from collections is slightly quicker then using a list comprehension:
>>> from collections import deque >>> timeit.timeit(lambda: tuple([i for i in range(10000000)]),number=10) 9.294099200000005 >>> timeit.timeit(lambda: tuple(deque((i for i in range(10000000)))),number=10) 9.007653800000014
Method 11
Because you can not append items to a tuple. This is how a simple list comprehension can be converted into more basic python code.
_list = [1,2,3,4,5]
clist = [ i*i for i in _list ]
print(clist)
clist1 = []
for i in _list:
clist1.append(i*i)
print(clist1)
Now using a tuple comprehension for above example means appending items into a tuple which is not allowed. Though you can covert this list to a tuple once it is ready by using tuple(clist1)
Method 12
We can generate tuples from a list comprehension. The following one adds two numbers sequentially into a tuple and gives a list from numbers 0-9.
>>> print k [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99] >>> r= [tuple(k[i:i+2]) for i in xrange(10) if not i%2] >>> print r [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0