My Generator Paradox!

Michal Kwiatkowski ruby at no.spam
Thu Mar 16 19:36:20 EST 2006


vbgunz wrote:
> def generatorFunction(sequence=['item1', 'item2', 'item3']):
>     for item in sequence:
>         yield item
> 
> yieldedValue = generatorFunction()

You're creating an iterator here and binding it to name yieldedValue
(which is bogus, it should be named valueGenerator or sth like that).

> '''this seems to work perfectly.'''
> print '-' * 32
> print yieldedValue          # <generator object at 0xb723014c>
> print yieldedValue.next()   # item1
> print yieldedValue.next()   # item2
> print yieldedValue.next()   # item3

You're calling your iterator's next() method getting all of values, as
expected.

> '''this is where things don't make any sense!'''
> print '-' * 32
> print generatorFunction()           # <generator object at 0xb723022c>
You're creating a new iterator here.

> print generatorFunction().next()    # item1
Another anonymous iterator gets created here. Instantly its next()
method is called, yielding first value.

> print generatorFunction().next()    # item1
And so on...

> generatorFunction() is a call (obvious) when calling the second set, I
> am resetting the iteration and this explains why I only and always get
> item1.
> 
> ok. *but* why in the world does the first set of calls work?
> technically, isn't yieldedValue == generatorFunction() on a name
> basis? I mean isn't the following technically the same?
> 
> generatorFunction()
> yieldedValue = generatorFunction()

Well, first statement creates new iterator which is garbage collected
right away (as it has no bindings). Second statement creates an
iterator and binds it to name yieldedValue. Then it can be used as
typical iterator. Calling yieldedValue.next() just calls method of the
same iterator you've created a moment ago. It's still the same object.
The difference is like the difference between following two lines:

list()  # creating a new list
new_list = list()  # creating a new list and binding its name

So, rewriting your example from generator to dictionary objects:

alist = [1, 2, 3, 4, 5]
print alist       # [1, 2, 3, 4, 5]
print alist.pop() # 5
print alist.pop() # 4
print alist.pop() # 3

print [1, 2, 3, 4, 5]       # [1, 2, 3, 4, 5]
print [1, 2, 3, 4, 5].pop() # 5
print [1, 2, 3, 4, 5].pop() # 5
print [1, 2, 3, 4, 5].pop() # 5

Remember that generator is an object and you'll be fine.

mk
-- 
 . o .       >>  http://joker.linuxstuff.pl  <<
 . . o   It's easier to get forgiveness for being wrong
 o o o   than forgiveness for being right.



More information about the Python-list mailing list