iter

Terry Reedy tjreedy at udel.edu
Mon Aug 9 19:11:56 CEST 2010


On 8/9/2010 12:11 PM, daryn wrote:
> I'm just playing around with the iter function and I realize that I
> can use the iterator returned by it long after the original object has
> any name bound to it.  Example:
>
>>>> a=[1,2,3,4]
>>>> b=iter(a)
>>>> b.next()
> 1
>>>> a[1]=99

Changing a list while iterating through it is possible, sometimes 
useful, but error prone, especially with insert or delete. Changing a 
dict while iterating through it is prohibited since the iteration order 
depends on the exact internal structure. That in turn depends on the 
history of additions and deletions.

>>>> a[3]=101
>>>> del a
>>>> b.next()
> 99
>>>> b.next()
> 3
>>>> b.next()
> 101
>
> it seems as if the original object is never being garbage collected
> even though there is no name bound to it.

The fact that CPython currently deletes some things immediately is a 
current implementation detail, subject to change.

>  Does the name bound to the
> iterator object count as a reference to the original object for
> garbage collection purposes?

Not quite. The iterator obviously has to have an internal reference, 
which amount to the almost the same thing. However, if you put the 
iterator in a list and deleted the name binding, both the iterator and 
list are still kept around.

> Is there some way to retrieve/manipulate
> the original object via the iterator?

If you do dir(b), you will only see the standard __xx__ methods, most of 
which are inherited. Iterators can be written to expose an underlying 
object, if there is one, but some do not have one and this is not part 
of the simple iterator protocol. Hence builtin iterators for builtins do 
not do so.

If one actually needed such lookup, this wrapper should work.

class myiter():
     def __init__(self, ob):
         self.ob = ob
         self.__itnext__ = iter(ob).__next__
     def __iter__(self):
         return self
     def __next__(self):
         return self.__itnext__()

it = myiter([1,2,3])
print (it.ob, list(it))

# [1, 2, 3] [1, 2, 3]

> Just trying to understand how this all works.

Keep experimenting. Python makes is so easy, especially with an edit 
window such as with IDLE and a Run command. I initially tried not 
defining myiter.__next__ and instead wrote:
         self.__next__ = iter(ob).__next__
but that does not work because special __xx__ methods are typically 
looked up on the class, not the instance. I know that but was not 
completely sure about this case.

-- 
Terry Jan Reedy




More information about the Python-list mailing list