iter jitters

S

Steven Brent

Hi folks,

In the snippet below, I'm trying to overload the __iter__ list method:

def __iter__(self):
print "using custom iter"
counter = 0
end = len(self.data) - 1
while counter <= end:
print self.data[counter]
counter += 1

It pretty much works, except that the output is ugly when the while loop
falls off the end of the list:
>>> L3 = [1,2,3,'x','y',z']
>>> for item in L3: print item,

using custom iter
1
2
3
x
y
z
Traceback (most recent call last):
File "mylist.py", line 38, in ?
for item in L3:print item,
TypeError: iter() returned non-iterator of type 'NoneType'

Oh, yeah, plus it's adding a newline at the end of each item even though
I've got the comma there. I'm gonna keep plugging away to see if I can
figure this out, but stuff like this makes me frustrated... Thanks a
million.
 
D

Diez B. Roggisch

Steven said:
In the snippet below, I'm trying to overload the __iter__ list method:

def __iter__(self):
print "using custom iter"
counter = 0
end = len(self.data) - 1
while counter <= end:
print self.data[counter]
counter += 1

It pretty much works, except that the output is ugly when the while loop
falls off the end of the list:
File "mylist.py", line 38, in ?
for item in L3:print item,
TypeError: iter() returned non-iterator of type 'NoneType'

Oh, yeah, plus it's adding a newline at the end of each item even though
I've got the comma there. I'm gonna keep plugging away to see if I can
figure this out, but stuff like this makes me frustrated... Thanks a
million.

I think you've got something wrong here - __iter__ is supposed to return an
object that supports the iteration protocol - mainly a next() method that
throws an exception when no more elements are available.

Today, this kind of thingy is usually done using generators:

class foo:
def __init__(self):
self.data = range(10)

def __iter__(self):
def _my_iter():
for e in self.data:
yield e
return _my_iter()


for i in foo():
print i
 
H

Heiko Wundram

Even easier:

"""
class foo:
def __init__(self):
self.data = range(10)

def __iter__(self):
for e in self.data:
yield e

for i in foo():
print i

__iter__ may itself be a generator (I mostly use it exactly in this way).

HTH!

Heiko.
 
S

Steven Brent

OK, thanks ... that explains why my other idea of returning a new list
to iterate over didn't work either. Talk about chasing one's tail...

Btw, I just realized that a custom __getitem__ method I defined earlier
in the module(and unhelpfully didnt post), handles the iteration in 2 lines!

def __getitem__(self, index):
return self.data[index]

This is the kind of thing I was after, because I didn't want any
iteration going on in the __iter__ definition itself. Trying to reinvent
the wheel for exercise.

But generators are cool, and I promise to use them lots :)

This seems to be a recurring pattern for me; I get deep into confusion
by skipping over the obvious. Thanks for the clarity and knowledge.

--Steven the newbie

===========================
Diez said:
Steven Brent wrote:

In the snippet below, I'm trying to overload the __iter__ list method:

def __iter__(self):
print "using custom iter"
counter = 0
end = len(self.data) - 1
while counter <= end:
print self.data[counter]
counter += 1

It pretty much works, except that the output is ugly when the while loop
falls off the end of the list:


File "mylist.py", line 38, in ?
for item in L3:print item,
TypeError: iter() returned non-iterator of type 'NoneType'

Oh, yeah, plus it's adding a newline at the end of each item even though
I've got the comma there. I'm gonna keep plugging away to see if I can
figure this out, but stuff like this makes me frustrated... Thanks a
million.


I think you've got something wrong here - __iter__ is supposed to return an
object that supports the iteration protocol - mainly a next() method that
throws an exception when no more elements are available.

Today, this kind of thingy is usually done using generators:

class foo:
def __init__(self):
self.data = range(10)

def __iter__(self):
def _my_iter():
for e in self.data:
yield e
return _my_iter()


for i in foo():
print i
 
D

Diez B. Roggisch

Steven said:
Btw, I just realized that a custom __getitem__ method I defined earlier
in the module(and unhelpfully didnt post), handles the iteration in 2
lines!

def __getitem__(self, index):
return self.data[index]

This is the kind of thing I was after, because I didn't want any
iteration going on in the __iter__ definition itself. Trying to reinvent
the wheel for exercise.

Interesting. Just played around with my example and found that in case of
absence of an __iter__-method the for - in generates keys from 0 to - well,
I guess something like max_int, but I won't wait so long... - and then
tries __getitem__ with that key.
 
P

Peter Otten

Heiko said:
def __iter__(self):
for e in self.data:
yield e

Another option:
.... def __init__(self):
.... self.data = range(10)
.... def __iter__(self):
.... return iter(self.data)
........ print i,
....
0 1 2 3 4 5 6 7 8 9
Peter
 

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

No members online now.

Forum statistics

Threads
473,989
Messages
2,570,207
Members
46,782
Latest member
ThomasGex

Latest Threads

Top