Question
Please help understand why the two cases act differently although both use a generator (i for i in range(5))
.
>>> print(i for i in range(5)) <generator object <genexpr> at 0x7fc409c02900> >>> print(*(i for i in range(5))) 0 1 2 3 4 >>> print(*(i for i in range(5)), 5) 0 1 2 3 4 5
>>> _r = (i for i in range(5)) >>> print(_r) <generator object <genexpr> at 0x7fc409c029e0> >>> print(*_r) 0 1 2 3 4 >>> print(*_r, 5) 5 >>> print(*(_r), 5) 5
Advertisement
Answer
When you use the *
operator on a generator expression (or any iterator for that matter), it consumes it:
my_iterator = (i for i in range(3)) second_iterator = iter(list(range(3))) # splat operator consumes the generator expression print(*my_iterator) 0 1 2 print(*my_iterator, "Empty!") Empty! # splat operator also consumes the iterator print(*second_iterator) 0 1 2 print(*second_iterator, "Also empty!") Also empty!
You’d need to recreate it to re-use it, which is what you’re doing in your first example:
s = (i for i in range(3)) print(*s) 0 1 2 # You create a new generator expression/iterator s = (i for i in range(3)) print(*s) 0 1 2 # And so it isn't empty # same with the shorthand print(*(i for i in range(3)) 0 1 2
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:
x = range(3) print(*x) 0 1 2 print(*x) 0 1 2 # the range object isn't consumed and can be re-used a = iter(x) print(*a) 0 1 2 print(*a) # prints nothing because `a` has been exhausted
More detail can be found in this answer