Generator expression uses list assigned after the generator's creation
Clash Royale CLAN TAG#URR8PPP
up vote
7
down vote
favorite
I found this example and I can't understand why it works unpredictably?
I supposed it must output [1, 8, 15] or [2, 8, 22]
array = [1, 8, 15]
g = (x for x in array if array.count(x) > 0)
array = [2, 8, 22]
print(list(g))
>>>[8]
python expression generator
add a comment |Â
up vote
7
down vote
favorite
I found this example and I can't understand why it works unpredictably?
I supposed it must output [1, 8, 15] or [2, 8, 22]
array = [1, 8, 15]
g = (x for x in array if array.count(x) > 0)
array = [2, 8, 22]
print(list(g))
>>>[8]
python expression generator
aside:if array.count(x) > 0
=>x in array
is smarter & faster :)
– Jean-François Fabre
40 mins ago
add a comment |Â
up vote
7
down vote
favorite
up vote
7
down vote
favorite
I found this example and I can't understand why it works unpredictably?
I supposed it must output [1, 8, 15] or [2, 8, 22]
array = [1, 8, 15]
g = (x for x in array if array.count(x) > 0)
array = [2, 8, 22]
print(list(g))
>>>[8]
python expression generator
I found this example and I can't understand why it works unpredictably?
I supposed it must output [1, 8, 15] or [2, 8, 22]
array = [1, 8, 15]
g = (x for x in array if array.count(x) > 0)
array = [2, 8, 22]
print(list(g))
>>>[8]
python expression generator
python expression generator
edited 38 mins ago


Carcigenicate
16.4k42855
16.4k42855
asked 51 mins ago


Gvyntyk
11927
11927
aside:if array.count(x) > 0
=>x in array
is smarter & faster :)
– Jean-François Fabre
40 mins ago
add a comment |Â
aside:if array.count(x) > 0
=>x in array
is smarter & faster :)
– Jean-François Fabre
40 mins ago
aside:
if array.count(x) > 0
=> x in array
is smarter & faster :)– Jean-François Fabre
40 mins ago
aside:
if array.count(x) > 0
=> x in array
is smarter & faster :)– Jean-François Fabre
40 mins ago
add a comment |Â
6 Answers
6
active
oldest
votes
up vote
6
down vote
The reason is that, at creation time, the generator (a for b in c if d)
only evaluates c
(which sometimes makes b
predictable as well). But a
, b
, d
are evaluated at consumption time (at each iteration). And since a generator does not open its own namespace, it uses the current binding of array
when evaluating d
(array.count(x) > 0
).
You can for instance do:
g = (x for x in if a)
Without having declared a
in advance. You have to make sure a
exists when the generator is consumed.
But you cannot do similarly:
g = (x for x in a if True)
Upon request:
You can observe similar (however not identical) patterns with a common generator function:
def yielder():
for x in array:
if array.count(x) > 0:
yield x
array = [1, 8, 15]
y = yielder()
array = [2, 8, 22]
list(y)
# [2, 8, 22]
The generator function does not execute any of its body ahead of consumption. Hence, even the array
in the for-loop header is bound late. An even more disturbing example occurs where we "switch out" array
during iteration:
array = [1, 8, 15]
y = yielder()
next(y)
# 1
array = [3, 7]
next(y) # still iterating [1, 8, 15], but evaluating condition on [3, 7]
# StopIteration raised
Can you explain why the generator expression seems to behave differently to the generator functiondef yielder(): for x in array: if array.count(x) > 0: yield x
. Usinglist(yielder)
exhausts so you get[1, 8, 15]
, whilelist(g)
only gives[8]
.
– jpp
36 mins ago
1
@jpp You cannot calllist
on a function object. But nitpicking aside =) I added some explanation to that end.
– schwobaseggl
25 mins ago
Thank you, very helpful. Of courselist(yielder())
is what I meant :)
– jpp
24 mins ago
add a comment |Â
up vote
0
down vote
Actually, it is not really crazy if you look more carefully.
look at
g = (x for x in array if array.count(x) > 0)
it will create a generator that looks through the array and will search if the count of already existing values is more than zero. so your generator only looks for 1
, 8
and 15
, and when you change the values to another, the generator just looks for the previous values again not new ones. because it(generator) creates when array had them.
so if you put thousands of values in the array it only looks for those three only.
It is not clear to me whether this answer says that the condition or thearray
is instantly evaluated
– lucidbrot
25 mins ago
add a comment |Â
up vote
0
down vote
when you first create the array and assign the elements in it, elements of the array points to some memory location and generator keeps that location (not the array's) for its execution.
but when you modify its elements of the array it gets changed but as '8' is common for both of them python does not reassign it and points to the same element after modification.
Look the below example for better understanding
array = [1, 8, 15]
for i in array:
print(id(i))
g = (x for x in array if array.count(x) > 0)
print('<======>')
array = [2, 8, 22]
for i in array:
print(id(i))
print(array)
print(list(g))
Output
140208067495680
140208067495904
140208067496128
<======>
140208067495712
140208067495904 # memory location is still same
140208067496352
[2, 8, 22]
[8]
add a comment |Â
up vote
0
down vote
The confusion, and so is the answer, lies in the line:g = (x for x in array if array.count(x) > 0)
If we simplify this line then it will become: g = (x for x in array1 if array2.count(x) > 0)
Now, when generator is created then it keeps the copy of array1
. So even if I will change the value of array1
to any other value, it will not affect the generator's copy of array1
. But array2
is checked dynamically. So if we change its value it will be reflected.
You can see outputy from following code to understand it batter. See it working online here:
array1 = [1, 8, 15] #Set value of `array1`
array2 = [2, 3, 4, 5, 8] #Set value of `array2`
g = (x for x in array1 if array2.count(x) > 0)
array1 = [0, 9] #Changed value of `array1`
array2 = [2, 8, 22, 1] #Changed value of `array2`
print(list(g))
>>> [1, 8]
add a comment |Â
up vote
0
down vote
From the docs on Generator expressions:
Variables used in the generator expression are evaluated lazily when
the__next__()
method is called for the generator object (in the same
fashion as normal generators). However, the iterable expression in the
leftmostfor
clause is immediately evaluated, so that an error
produced by it will be emitted at the point where the generator
expression is defined, rather than at the point where the first value
is retrieved.
So when you run
array = [1, 8, 15]
g = (x for x in array if array.count(x) > 0)
only the first array
in the generator expression is evaluated. Since you change the value to [2, 8, 22]
before consuming the generator you get the 'unexpected' result.
array = [2, 8, 22]
print(list(g)) # [8]
add a comment |Â
up vote
0
down vote
You can show this behavior more clearly with a simple example:
array = [1, 8, 15]
g = ((array[i], x) for i, x in enumerate(array))
array = [2, 8, 22]
print(list(g))
# [(2, 1), (8, 8), (22, 15)]
# ^ 0th value is array[i] from the new array
# ^ 1st value is x from the original array
So as others have indicated, the results of the generator expression are only generated when you iterate over the generator (here via a list()
call). But the original array
is evaluated when the generator is built, as can also easily be illustrated in isolation:
(undefined_x for undefined_x in undefined_y)
# NameError: name 'undefined_y' is not defined
add a comment |Â
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
6
down vote
The reason is that, at creation time, the generator (a for b in c if d)
only evaluates c
(which sometimes makes b
predictable as well). But a
, b
, d
are evaluated at consumption time (at each iteration). And since a generator does not open its own namespace, it uses the current binding of array
when evaluating d
(array.count(x) > 0
).
You can for instance do:
g = (x for x in if a)
Without having declared a
in advance. You have to make sure a
exists when the generator is consumed.
But you cannot do similarly:
g = (x for x in a if True)
Upon request:
You can observe similar (however not identical) patterns with a common generator function:
def yielder():
for x in array:
if array.count(x) > 0:
yield x
array = [1, 8, 15]
y = yielder()
array = [2, 8, 22]
list(y)
# [2, 8, 22]
The generator function does not execute any of its body ahead of consumption. Hence, even the array
in the for-loop header is bound late. An even more disturbing example occurs where we "switch out" array
during iteration:
array = [1, 8, 15]
y = yielder()
next(y)
# 1
array = [3, 7]
next(y) # still iterating [1, 8, 15], but evaluating condition on [3, 7]
# StopIteration raised
Can you explain why the generator expression seems to behave differently to the generator functiondef yielder(): for x in array: if array.count(x) > 0: yield x
. Usinglist(yielder)
exhausts so you get[1, 8, 15]
, whilelist(g)
only gives[8]
.
– jpp
36 mins ago
1
@jpp You cannot calllist
on a function object. But nitpicking aside =) I added some explanation to that end.
– schwobaseggl
25 mins ago
Thank you, very helpful. Of courselist(yielder())
is what I meant :)
– jpp
24 mins ago
add a comment |Â
up vote
6
down vote
The reason is that, at creation time, the generator (a for b in c if d)
only evaluates c
(which sometimes makes b
predictable as well). But a
, b
, d
are evaluated at consumption time (at each iteration). And since a generator does not open its own namespace, it uses the current binding of array
when evaluating d
(array.count(x) > 0
).
You can for instance do:
g = (x for x in if a)
Without having declared a
in advance. You have to make sure a
exists when the generator is consumed.
But you cannot do similarly:
g = (x for x in a if True)
Upon request:
You can observe similar (however not identical) patterns with a common generator function:
def yielder():
for x in array:
if array.count(x) > 0:
yield x
array = [1, 8, 15]
y = yielder()
array = [2, 8, 22]
list(y)
# [2, 8, 22]
The generator function does not execute any of its body ahead of consumption. Hence, even the array
in the for-loop header is bound late. An even more disturbing example occurs where we "switch out" array
during iteration:
array = [1, 8, 15]
y = yielder()
next(y)
# 1
array = [3, 7]
next(y) # still iterating [1, 8, 15], but evaluating condition on [3, 7]
# StopIteration raised
Can you explain why the generator expression seems to behave differently to the generator functiondef yielder(): for x in array: if array.count(x) > 0: yield x
. Usinglist(yielder)
exhausts so you get[1, 8, 15]
, whilelist(g)
only gives[8]
.
– jpp
36 mins ago
1
@jpp You cannot calllist
on a function object. But nitpicking aside =) I added some explanation to that end.
– schwobaseggl
25 mins ago
Thank you, very helpful. Of courselist(yielder())
is what I meant :)
– jpp
24 mins ago
add a comment |Â
up vote
6
down vote
up vote
6
down vote
The reason is that, at creation time, the generator (a for b in c if d)
only evaluates c
(which sometimes makes b
predictable as well). But a
, b
, d
are evaluated at consumption time (at each iteration). And since a generator does not open its own namespace, it uses the current binding of array
when evaluating d
(array.count(x) > 0
).
You can for instance do:
g = (x for x in if a)
Without having declared a
in advance. You have to make sure a
exists when the generator is consumed.
But you cannot do similarly:
g = (x for x in a if True)
Upon request:
You can observe similar (however not identical) patterns with a common generator function:
def yielder():
for x in array:
if array.count(x) > 0:
yield x
array = [1, 8, 15]
y = yielder()
array = [2, 8, 22]
list(y)
# [2, 8, 22]
The generator function does not execute any of its body ahead of consumption. Hence, even the array
in the for-loop header is bound late. An even more disturbing example occurs where we "switch out" array
during iteration:
array = [1, 8, 15]
y = yielder()
next(y)
# 1
array = [3, 7]
next(y) # still iterating [1, 8, 15], but evaluating condition on [3, 7]
# StopIteration raised
The reason is that, at creation time, the generator (a for b in c if d)
only evaluates c
(which sometimes makes b
predictable as well). But a
, b
, d
are evaluated at consumption time (at each iteration). And since a generator does not open its own namespace, it uses the current binding of array
when evaluating d
(array.count(x) > 0
).
You can for instance do:
g = (x for x in if a)
Without having declared a
in advance. You have to make sure a
exists when the generator is consumed.
But you cannot do similarly:
g = (x for x in a if True)
Upon request:
You can observe similar (however not identical) patterns with a common generator function:
def yielder():
for x in array:
if array.count(x) > 0:
yield x
array = [1, 8, 15]
y = yielder()
array = [2, 8, 22]
list(y)
# [2, 8, 22]
The generator function does not execute any of its body ahead of consumption. Hence, even the array
in the for-loop header is bound late. An even more disturbing example occurs where we "switch out" array
during iteration:
array = [1, 8, 15]
y = yielder()
next(y)
# 1
array = [3, 7]
next(y) # still iterating [1, 8, 15], but evaluating condition on [3, 7]
# StopIteration raised
edited 6 mins ago
answered 44 mins ago


schwobaseggl
32.7k31936
32.7k31936
Can you explain why the generator expression seems to behave differently to the generator functiondef yielder(): for x in array: if array.count(x) > 0: yield x
. Usinglist(yielder)
exhausts so you get[1, 8, 15]
, whilelist(g)
only gives[8]
.
– jpp
36 mins ago
1
@jpp You cannot calllist
on a function object. But nitpicking aside =) I added some explanation to that end.
– schwobaseggl
25 mins ago
Thank you, very helpful. Of courselist(yielder())
is what I meant :)
– jpp
24 mins ago
add a comment |Â
Can you explain why the generator expression seems to behave differently to the generator functiondef yielder(): for x in array: if array.count(x) > 0: yield x
. Usinglist(yielder)
exhausts so you get[1, 8, 15]
, whilelist(g)
only gives[8]
.
– jpp
36 mins ago
1
@jpp You cannot calllist
on a function object. But nitpicking aside =) I added some explanation to that end.
– schwobaseggl
25 mins ago
Thank you, very helpful. Of courselist(yielder())
is what I meant :)
– jpp
24 mins ago
Can you explain why the generator expression seems to behave differently to the generator function
def yielder(): for x in array: if array.count(x) > 0: yield x
. Using list(yielder)
exhausts so you get [1, 8, 15]
, while list(g)
only gives [8]
.– jpp
36 mins ago
Can you explain why the generator expression seems to behave differently to the generator function
def yielder(): for x in array: if array.count(x) > 0: yield x
. Using list(yielder)
exhausts so you get [1, 8, 15]
, while list(g)
only gives [8]
.– jpp
36 mins ago
1
1
@jpp You cannot call
list
on a function object. But nitpicking aside =) I added some explanation to that end.– schwobaseggl
25 mins ago
@jpp You cannot call
list
on a function object. But nitpicking aside =) I added some explanation to that end.– schwobaseggl
25 mins ago
Thank you, very helpful. Of course
list(yielder())
is what I meant :)– jpp
24 mins ago
Thank you, very helpful. Of course
list(yielder())
is what I meant :)– jpp
24 mins ago
add a comment |Â
up vote
0
down vote
Actually, it is not really crazy if you look more carefully.
look at
g = (x for x in array if array.count(x) > 0)
it will create a generator that looks through the array and will search if the count of already existing values is more than zero. so your generator only looks for 1
, 8
and 15
, and when you change the values to another, the generator just looks for the previous values again not new ones. because it(generator) creates when array had them.
so if you put thousands of values in the array it only looks for those three only.
It is not clear to me whether this answer says that the condition or thearray
is instantly evaluated
– lucidbrot
25 mins ago
add a comment |Â
up vote
0
down vote
Actually, it is not really crazy if you look more carefully.
look at
g = (x for x in array if array.count(x) > 0)
it will create a generator that looks through the array and will search if the count of already existing values is more than zero. so your generator only looks for 1
, 8
and 15
, and when you change the values to another, the generator just looks for the previous values again not new ones. because it(generator) creates when array had them.
so if you put thousands of values in the array it only looks for those three only.
It is not clear to me whether this answer says that the condition or thearray
is instantly evaluated
– lucidbrot
25 mins ago
add a comment |Â
up vote
0
down vote
up vote
0
down vote
Actually, it is not really crazy if you look more carefully.
look at
g = (x for x in array if array.count(x) > 0)
it will create a generator that looks through the array and will search if the count of already existing values is more than zero. so your generator only looks for 1
, 8
and 15
, and when you change the values to another, the generator just looks for the previous values again not new ones. because it(generator) creates when array had them.
so if you put thousands of values in the array it only looks for those three only.
Actually, it is not really crazy if you look more carefully.
look at
g = (x for x in array if array.count(x) > 0)
it will create a generator that looks through the array and will search if the count of already existing values is more than zero. so your generator only looks for 1
, 8
and 15
, and when you change the values to another, the generator just looks for the previous values again not new ones. because it(generator) creates when array had them.
so if you put thousands of values in the array it only looks for those three only.
answered 43 mins ago
mehrdad-pedramfar
3,06011231
3,06011231
It is not clear to me whether this answer says that the condition or thearray
is instantly evaluated
– lucidbrot
25 mins ago
add a comment |Â
It is not clear to me whether this answer says that the condition or thearray
is instantly evaluated
– lucidbrot
25 mins ago
It is not clear to me whether this answer says that the condition or the
array
is instantly evaluated– lucidbrot
25 mins ago
It is not clear to me whether this answer says that the condition or the
array
is instantly evaluated– lucidbrot
25 mins ago
add a comment |Â
up vote
0
down vote
when you first create the array and assign the elements in it, elements of the array points to some memory location and generator keeps that location (not the array's) for its execution.
but when you modify its elements of the array it gets changed but as '8' is common for both of them python does not reassign it and points to the same element after modification.
Look the below example for better understanding
array = [1, 8, 15]
for i in array:
print(id(i))
g = (x for x in array if array.count(x) > 0)
print('<======>')
array = [2, 8, 22]
for i in array:
print(id(i))
print(array)
print(list(g))
Output
140208067495680
140208067495904
140208067496128
<======>
140208067495712
140208067495904 # memory location is still same
140208067496352
[2, 8, 22]
[8]
add a comment |Â
up vote
0
down vote
when you first create the array and assign the elements in it, elements of the array points to some memory location and generator keeps that location (not the array's) for its execution.
but when you modify its elements of the array it gets changed but as '8' is common for both of them python does not reassign it and points to the same element after modification.
Look the below example for better understanding
array = [1, 8, 15]
for i in array:
print(id(i))
g = (x for x in array if array.count(x) > 0)
print('<======>')
array = [2, 8, 22]
for i in array:
print(id(i))
print(array)
print(list(g))
Output
140208067495680
140208067495904
140208067496128
<======>
140208067495712
140208067495904 # memory location is still same
140208067496352
[2, 8, 22]
[8]
add a comment |Â
up vote
0
down vote
up vote
0
down vote
when you first create the array and assign the elements in it, elements of the array points to some memory location and generator keeps that location (not the array's) for its execution.
but when you modify its elements of the array it gets changed but as '8' is common for both of them python does not reassign it and points to the same element after modification.
Look the below example for better understanding
array = [1, 8, 15]
for i in array:
print(id(i))
g = (x for x in array if array.count(x) > 0)
print('<======>')
array = [2, 8, 22]
for i in array:
print(id(i))
print(array)
print(list(g))
Output
140208067495680
140208067495904
140208067496128
<======>
140208067495712
140208067495904 # memory location is still same
140208067496352
[2, 8, 22]
[8]
when you first create the array and assign the elements in it, elements of the array points to some memory location and generator keeps that location (not the array's) for its execution.
but when you modify its elements of the array it gets changed but as '8' is common for both of them python does not reassign it and points to the same element after modification.
Look the below example for better understanding
array = [1, 8, 15]
for i in array:
print(id(i))
g = (x for x in array if array.count(x) > 0)
print('<======>')
array = [2, 8, 22]
for i in array:
print(id(i))
print(array)
print(list(g))
Output
140208067495680
140208067495904
140208067496128
<======>
140208067495712
140208067495904 # memory location is still same
140208067496352
[2, 8, 22]
[8]
answered 27 mins ago


ansu5555
1916
1916
add a comment |Â
add a comment |Â
up vote
0
down vote
The confusion, and so is the answer, lies in the line:g = (x for x in array if array.count(x) > 0)
If we simplify this line then it will become: g = (x for x in array1 if array2.count(x) > 0)
Now, when generator is created then it keeps the copy of array1
. So even if I will change the value of array1
to any other value, it will not affect the generator's copy of array1
. But array2
is checked dynamically. So if we change its value it will be reflected.
You can see outputy from following code to understand it batter. See it working online here:
array1 = [1, 8, 15] #Set value of `array1`
array2 = [2, 3, 4, 5, 8] #Set value of `array2`
g = (x for x in array1 if array2.count(x) > 0)
array1 = [0, 9] #Changed value of `array1`
array2 = [2, 8, 22, 1] #Changed value of `array2`
print(list(g))
>>> [1, 8]
add a comment |Â
up vote
0
down vote
The confusion, and so is the answer, lies in the line:g = (x for x in array if array.count(x) > 0)
If we simplify this line then it will become: g = (x for x in array1 if array2.count(x) > 0)
Now, when generator is created then it keeps the copy of array1
. So even if I will change the value of array1
to any other value, it will not affect the generator's copy of array1
. But array2
is checked dynamically. So if we change its value it will be reflected.
You can see outputy from following code to understand it batter. See it working online here:
array1 = [1, 8, 15] #Set value of `array1`
array2 = [2, 3, 4, 5, 8] #Set value of `array2`
g = (x for x in array1 if array2.count(x) > 0)
array1 = [0, 9] #Changed value of `array1`
array2 = [2, 8, 22, 1] #Changed value of `array2`
print(list(g))
>>> [1, 8]
add a comment |Â
up vote
0
down vote
up vote
0
down vote
The confusion, and so is the answer, lies in the line:g = (x for x in array if array.count(x) > 0)
If we simplify this line then it will become: g = (x for x in array1 if array2.count(x) > 0)
Now, when generator is created then it keeps the copy of array1
. So even if I will change the value of array1
to any other value, it will not affect the generator's copy of array1
. But array2
is checked dynamically. So if we change its value it will be reflected.
You can see outputy from following code to understand it batter. See it working online here:
array1 = [1, 8, 15] #Set value of `array1`
array2 = [2, 3, 4, 5, 8] #Set value of `array2`
g = (x for x in array1 if array2.count(x) > 0)
array1 = [0, 9] #Changed value of `array1`
array2 = [2, 8, 22, 1] #Changed value of `array2`
print(list(g))
>>> [1, 8]
The confusion, and so is the answer, lies in the line:g = (x for x in array if array.count(x) > 0)
If we simplify this line then it will become: g = (x for x in array1 if array2.count(x) > 0)
Now, when generator is created then it keeps the copy of array1
. So even if I will change the value of array1
to any other value, it will not affect the generator's copy of array1
. But array2
is checked dynamically. So if we change its value it will be reflected.
You can see outputy from following code to understand it batter. See it working online here:
array1 = [1, 8, 15] #Set value of `array1`
array2 = [2, 3, 4, 5, 8] #Set value of `array2`
g = (x for x in array1 if array2.count(x) > 0)
array1 = [0, 9] #Changed value of `array1`
array2 = [2, 8, 22, 1] #Changed value of `array2`
print(list(g))
>>> [1, 8]
answered 24 mins ago


cse
2,80221029
2,80221029
add a comment |Â
add a comment |Â
up vote
0
down vote
From the docs on Generator expressions:
Variables used in the generator expression are evaluated lazily when
the__next__()
method is called for the generator object (in the same
fashion as normal generators). However, the iterable expression in the
leftmostfor
clause is immediately evaluated, so that an error
produced by it will be emitted at the point where the generator
expression is defined, rather than at the point where the first value
is retrieved.
So when you run
array = [1, 8, 15]
g = (x for x in array if array.count(x) > 0)
only the first array
in the generator expression is evaluated. Since you change the value to [2, 8, 22]
before consuming the generator you get the 'unexpected' result.
array = [2, 8, 22]
print(list(g)) # [8]
add a comment |Â
up vote
0
down vote
From the docs on Generator expressions:
Variables used in the generator expression are evaluated lazily when
the__next__()
method is called for the generator object (in the same
fashion as normal generators). However, the iterable expression in the
leftmostfor
clause is immediately evaluated, so that an error
produced by it will be emitted at the point where the generator
expression is defined, rather than at the point where the first value
is retrieved.
So when you run
array = [1, 8, 15]
g = (x for x in array if array.count(x) > 0)
only the first array
in the generator expression is evaluated. Since you change the value to [2, 8, 22]
before consuming the generator you get the 'unexpected' result.
array = [2, 8, 22]
print(list(g)) # [8]
add a comment |Â
up vote
0
down vote
up vote
0
down vote
From the docs on Generator expressions:
Variables used in the generator expression are evaluated lazily when
the__next__()
method is called for the generator object (in the same
fashion as normal generators). However, the iterable expression in the
leftmostfor
clause is immediately evaluated, so that an error
produced by it will be emitted at the point where the generator
expression is defined, rather than at the point where the first value
is retrieved.
So when you run
array = [1, 8, 15]
g = (x for x in array if array.count(x) > 0)
only the first array
in the generator expression is evaluated. Since you change the value to [2, 8, 22]
before consuming the generator you get the 'unexpected' result.
array = [2, 8, 22]
print(list(g)) # [8]
From the docs on Generator expressions:
Variables used in the generator expression are evaluated lazily when
the__next__()
method is called for the generator object (in the same
fashion as normal generators). However, the iterable expression in the
leftmostfor
clause is immediately evaluated, so that an error
produced by it will be emitted at the point where the generator
expression is defined, rather than at the point where the first value
is retrieved.
So when you run
array = [1, 8, 15]
g = (x for x in array if array.count(x) > 0)
only the first array
in the generator expression is evaluated. Since you change the value to [2, 8, 22]
before consuming the generator you get the 'unexpected' result.
array = [2, 8, 22]
print(list(g)) # [8]
edited 23 mins ago
answered 28 mins ago
Eugene Yarmash
80.2k21170254
80.2k21170254
add a comment |Â
add a comment |Â
up vote
0
down vote
You can show this behavior more clearly with a simple example:
array = [1, 8, 15]
g = ((array[i], x) for i, x in enumerate(array))
array = [2, 8, 22]
print(list(g))
# [(2, 1), (8, 8), (22, 15)]
# ^ 0th value is array[i] from the new array
# ^ 1st value is x from the original array
So as others have indicated, the results of the generator expression are only generated when you iterate over the generator (here via a list()
call). But the original array
is evaluated when the generator is built, as can also easily be illustrated in isolation:
(undefined_x for undefined_x in undefined_y)
# NameError: name 'undefined_y' is not defined
add a comment |Â
up vote
0
down vote
You can show this behavior more clearly with a simple example:
array = [1, 8, 15]
g = ((array[i], x) for i, x in enumerate(array))
array = [2, 8, 22]
print(list(g))
# [(2, 1), (8, 8), (22, 15)]
# ^ 0th value is array[i] from the new array
# ^ 1st value is x from the original array
So as others have indicated, the results of the generator expression are only generated when you iterate over the generator (here via a list()
call). But the original array
is evaluated when the generator is built, as can also easily be illustrated in isolation:
(undefined_x for undefined_x in undefined_y)
# NameError: name 'undefined_y' is not defined
add a comment |Â
up vote
0
down vote
up vote
0
down vote
You can show this behavior more clearly with a simple example:
array = [1, 8, 15]
g = ((array[i], x) for i, x in enumerate(array))
array = [2, 8, 22]
print(list(g))
# [(2, 1), (8, 8), (22, 15)]
# ^ 0th value is array[i] from the new array
# ^ 1st value is x from the original array
So as others have indicated, the results of the generator expression are only generated when you iterate over the generator (here via a list()
call). But the original array
is evaluated when the generator is built, as can also easily be illustrated in isolation:
(undefined_x for undefined_x in undefined_y)
# NameError: name 'undefined_y' is not defined
You can show this behavior more clearly with a simple example:
array = [1, 8, 15]
g = ((array[i], x) for i, x in enumerate(array))
array = [2, 8, 22]
print(list(g))
# [(2, 1), (8, 8), (22, 15)]
# ^ 0th value is array[i] from the new array
# ^ 1st value is x from the original array
So as others have indicated, the results of the generator expression are only generated when you iterate over the generator (here via a list()
call). But the original array
is evaluated when the generator is built, as can also easily be illustrated in isolation:
(undefined_x for undefined_x in undefined_y)
# NameError: name 'undefined_y' is not defined
edited 15 mins ago
answered 27 mins ago
Chris_Rands
14.3k53764
14.3k53764
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52968312%2fgenerator-expression-uses-list-assigned-after-the-generators-creation%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
aside:
if array.count(x) > 0
=>x in array
is smarter & faster :)– Jean-François Fabre
40 mins ago