Question
Please help understand why the two cases act differently although both use a generator (i for i in range(5))
.
JavaScript
x
7
1
>>> print(i for i in range(5))
2
<generator object <genexpr> at 0x7fc409c02900>
3
>>> print(*(i for i in range(5)))
4
0 1 2 3 4
5
>>> print(*(i for i in range(5)), 5)
6
0 1 2 3 4 5
7
JavaScript
1
10
10
1
>>> _r = (i for i in range(5))
2
>>> print(_r)
3
<generator object <genexpr> at 0x7fc409c029e0>
4
>>> print(*_r)
5
0 1 2 3 4
6
>>> print(*_r, 5)
7
5
8
>>> print(*(_r), 5)
9
5
10
Advertisement
Answer
When you use the *
operator on a generator expression (or any iterator for that matter), it consumes it:
JavaScript
1
16
16
1
my_iterator = (i for i in range(3))
2
3
second_iterator = iter(list(range(3)))
4
5
# splat operator consumes the generator expression
6
print(*my_iterator)
7
0 1 2
8
print(*my_iterator, "Empty!")
9
Empty!
10
11
# splat operator also consumes the iterator
12
print(*second_iterator)
13
0 1 2
14
print(*second_iterator, "Also empty!")
15
Also empty!
16
You’d need to recreate it to re-use it, which is what you’re doing in your first example:
JavaScript
1
14
14
1
s = (i for i in range(3))
2
print(*s)
3
0 1 2
4
5
# You create a new generator expression/iterator
6
s = (i for i in range(3))
7
print(*s)
8
0 1 2
9
10
# And so it isn't empty
11
# same with the shorthand
12
print(*(i for i in range(3))
13
0 1 2
14
Note on range
Since I’ve used range
for this example, it’s important to note that range
doesn’t share this behavior, but an iterator over range
does:
JavaScript
1
18
18
1
x = range(3)
2
3
print(*x)
4
0 1 2
5
6
print(*x)
7
0 1 2
8
# the range object isn't consumed and can be re-used
9
10
a = iter(x)
11
12
print(*a)
13
0 1 2
14
15
print(*a)
16
17
# prints nothing because `a` has been exhausted
18
More detail can be found in this answer