Iteratoration question

  • Thread starter grocery_stocker
  • Start date
G

grocery_stocker

Give the following code..
.... def __init__(self):
.... self.count = -1
.... def next(self):
.... self.count +=1
.... if self.count < 4:
.... return self.count
.... else:
.... raise StopIteration
........ return it()
....<__main__.it instance at 0xb7f4862c>

How come when I call some_func().next(), the counter doesn't get
incremented?0

But when I call iterator.next(), it does.
 
G

grocery_stocker

Give the following code..


... def __init__(self):
... self.count = -1
... def next(self):
... self.count +=1
... if self.count < 4:
... return self.count
... else:
... raise StopIteration
...>>> def some_func():

... return it()
...>>> iterator = some_func()

<__main__.it instance at 0xb7f482ac>>>> some_func

<function some_func at 0xb7f45e64>>>> some_func()

<__main__.it instance at 0xb7f4862c>

How come when I call some_func().next(), the counter doesn't get
incremented?>>> some_func().next()
0

0

But when I call iterator.next(), it does.

3
 
G

grocery_stocker

in summary: iterator is bound to one instance of "it", while some_func()
returns a new instance each time it is called.

BUT

while what you are doing is interesting, it is not the same as Python's
iterators, which use "yield" from a function and don't require storing a
value in a class. look for "yield" in the python docs. this comment may
be irrelevant; i am just worried you are confusing the above (which apart
from the mistake about instances is perfectly ok) and python's iterators
(which use next(), yield, etc).

Okay, one last question for now

When I have the follow class
.... def __init__(self):
.... self.count = -1
.... def next(self):
.... self.count +=1
.... if self.count < 4:
.... return self.count
.... else:
.... raise StopIteraton
....



How comes I can;t go over 'value' like in the following
.... print x
....
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: iteration over non-sequence


But yet, I can do...
 
R

Robert Kern

replace return with yield and it might work.

i have to go eat, but if it doesn't read the python docs on iterators -
for example http://docs.python.org/reference/expressions.html#index-1825

No, .next() needs to be a regular function that returns a value. What he needs
is an __iter__() method that returns self. Alternately, __iter__ could be a
generator, and you wouldn't implement a .next() at all.

In [1]: class it(object):
...: def __init__(self):
...: self.count = -1
...: def __iter__(self):
...: return self
...: def next(self):
...: self.count += 1
...: if self.count < 4:
...: return self.count
...: else:
...: raise StopIteration
...:
...:

In [2]: class it2(object):
...: def __init__(self):
...: self.count = -1
...: def __iter__(self):
...: self.count += 1
...: while self.count < 4:
...: yield self.count
...: self.count += 1
...:
...:

In [3]: list(it())
Out[3]: [0, 1, 2, 3]

In [4]: list(it2())
Out[4]: [0, 1, 2, 3]


--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
 
M

MRAB

grocery_stocker said:
yeah, sorry, i was in a rush and not thinking straight. andrew

Okay, I was thinking more about this. I think this is also what is
irking me. Say I have the following..
a = [1,2,3,4]
for x in a:
... print x
...
1
2
3
4

Would 'a' somehow call __iter__ and next()? If so, does python just
perform this magically?
The for loop calls the __iter__() method to get an iterator object and
then calls the next() method of the iterator object repeatedly to get
the values.

Sometimes you want to give an existing iterator to the for loop; for
that reason iterator objects (can) have an __iter__() method which just
returns the object itself.

For example:

The 'list' class has the __iter__() method:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
'__delslice__', '__doc__', '__eq__', '__format__', '__ge__',
'__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__',
'__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__',
'__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__',
'__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append',
'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse',
'sort']

The __iter__() method returns a 'listiterator' instance:
<type 'listiterator'>

The 'listiterator' class also has the __iter__() method:
['__class__', '__delattr__', '__doc__', '__format__',
'__getattribute__', '__hash__', '__init__', '__iter__',
'__length_hint__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'next']

which just returns itself:
True
 
G

grocery_stocker

Okay, I was thinking more about this. I think this is also what is
irking me. Say I have the following..
a = [1,2,3,4]
for x in a:
... print x
...
1
2
3
4
Would 'a' somehow call __iter__ and next()? If so, does python just
perform this magically?

No. It's "for" that invokes the iteration protocol; that's pretty
much the definition of it. You have read the iteration protocol
after it's been mentioned so many times now, haven't you?

"for" calls iter(a), which in turn calls a.__iter__(), to get an
iterator. Once it's got, "for" calls next() on the iterator each
time round the loop. Very approximately, that little for-loop
translates to:

a = [1,2,3,4]
i = iter(a)
try:
while True:
x = i.next()
print x
except StopIteration:
pass

Okay, at the risk of sounding like a total slacker, I've only briefly
scanned over the iteration protocol. After I get up in the morning,
I'll probably read it more closely.
 
D

Diez B. Roggisch

while what you are doing is interesting, it is not the same as Python's
iterators, which use "yield" from a function and don't require storing a
value in a class. look for "yield" in the python docs. this comment may
be irrelevant; i am just worried you are confusing the above (which apart
from the mistake about instances is perfectly ok) and python's iterators
(which use next(), yield, etc).

You are confusing generators with the iterator-protocol. Iteration has
been part of python long before generators appeared on the scene.

Diez
 
S

Steven D'Aprano

Okay, I was thinking more about this. I think this is also what is
irking me. Say I have the following..
a = [1,2,3,4]
for x in a:
... print x
...
1
2
3
4Would 'a' somehow call __iter__ and next()? If so, does python just
perform this magically?

Not necessarily.

For loops will call __iter__ automatically if it exists, but that isn't
the only way that for loops can work. There is an older sequence protocol
that the for loop will use as well:
.... def __getitem__(self, i):
.... if i < 5: return i
.... raise IndexError
........ print i
....
0
1
2
3
4
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,150
Members
46,697
Latest member
AugustNabo

Latest Threads

Top