Generator expression uses list assigned after the generator's creation

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
7
down vote

favorite
1












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]









share|improve this question























  • aside: if array.count(x) > 0 => x in array is smarter & faster :)
    – Jean-François Fabre
    40 mins ago














up vote
7
down vote

favorite
1












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]









share|improve this question























  • aside: if array.count(x) > 0 => x in array is smarter & faster :)
    – Jean-François Fabre
    40 mins ago












up vote
7
down vote

favorite
1









up vote
7
down vote

favorite
1






1





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]









share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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
















  • 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












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





share|improve this answer






















  • 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




    @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


















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.






share|improve this answer




















  • It is not clear to me whether this answer says that the condition or the array is instantly evaluated
    – lucidbrot
    25 mins ago

















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]





share|improve this answer



























    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]





    share|improve this answer



























      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
      leftmost for 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]





      share|improve this answer





























        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





        share|improve this answer






















          Your Answer





          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













           

          draft saved


          draft discarded


















          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






























          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





          share|improve this answer






















          • 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




            @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















          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





          share|improve this answer






















          • 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




            @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













          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





          share|improve this answer














          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






          share|improve this answer














          share|improve this answer



          share|improve this answer








          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 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




            @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

















          • 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




            @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
















          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













          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.






          share|improve this answer




















          • It is not clear to me whether this answer says that the condition or the array is instantly evaluated
            – lucidbrot
            25 mins ago














          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.






          share|improve this answer




















          • It is not clear to me whether this answer says that the condition or the array is instantly evaluated
            – lucidbrot
            25 mins ago












          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.






          share|improve this answer












          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.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 43 mins ago









          mehrdad-pedramfar

          3,06011231




          3,06011231











          • 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















          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










          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]





          share|improve this answer
























            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]





            share|improve this answer






















              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]





              share|improve this answer












              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]






              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered 27 mins ago









              ansu5555

              1916




              1916




















                  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]





                  share|improve this answer
























                    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]





                    share|improve this answer






















                      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]





                      share|improve this answer












                      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]






                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered 24 mins ago









                      cse

                      2,80221029




                      2,80221029




















                          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
                          leftmost for 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]





                          share|improve this answer


























                            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
                            leftmost for 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]





                            share|improve this answer
























                              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
                              leftmost for 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]





                              share|improve this answer














                              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
                              leftmost for 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]






                              share|improve this answer














                              share|improve this answer



                              share|improve this answer








                              edited 23 mins ago

























                              answered 28 mins ago









                              Eugene Yarmash

                              80.2k21170254




                              80.2k21170254




















                                  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





                                  share|improve this answer


























                                    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





                                    share|improve this answer
























                                      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





                                      share|improve this answer














                                      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






                                      share|improve this answer














                                      share|improve this answer



                                      share|improve this answer








                                      edited 15 mins ago

























                                      answered 27 mins ago









                                      Chris_Rands

                                      14.3k53764




                                      14.3k53764



























                                           

                                          draft saved


                                          draft discarded















































                                           


                                          draft saved


                                          draft discarded














                                          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













































































                                          Comments

                                          Popular posts from this blog

                                          List of Gilmore Girls characters

                                          What does second last employer means? [closed]

                                          One-line joke