what should __iter__ return?

E

ernest

Hi,

What is better:

def __iter__(self):
for i in len(self):
yield self

or

def __iter__(self):
return iter([self for i in range(len(self))])

The first one, I would say is more correct,
however what if in a middle of an iteration
the object changes in length? Then, the
iterator will fail with IndexError (if items
have been removed), or it will fail to iterate
over the whole sequence (if items have
been added).

What do you think?

Cheers.
Ernest
 
T

Thomas Jollans

Hi,

What is better:

def __iter__(self):
for i in len(self):
yield self

or

def __iter__(self):
return iter([self for i in range(len(self))])

The first one, I would say is more correct,
however what if in a middle of an iteration
the object changes in length? Then, the
iterator will fail with IndexError (if items
have been removed), or it will fail to iterate
over the whole sequence (if items have
been added).

What do you think?


Hmm. Modifying an object while iterating over it isn't a great idea, ever:
L = [1,2,3,4]
i = iter(L)
next(i) 1
next(i) 2
del L[0]
next(i)
4

You second version is wasteful. It creates a copy of the object just for
iteration. I don't think that's something you should be doing. If you want
"correct" behaviour as with lists, you might want something like this:

def __iter__(self):
class _Iter:
def __init__(it):
it.i = -1

def __next__(it):
it.i += 1
try:
return self[it.i]
except IndexError:
raise StopIteration

return _Iter()
 
M

MRAB

Hi,

What is better:

def __iter__(self):
for i in len(self):
yield self

or

def __iter__(self):
return iter([self for i in range(len(self))])

The first one, I would say is more correct,
however what if in a middle of an iteration
the object changes in length? Then, the
iterator will fail with IndexError (if items
have been removed), or it will fail to iterate
over the whole sequence (if items have
been added).

What do you think?

I'd say the first one is less correct because you can't iterate over an
int. :)
 
G

Gregory Ewing

Thomas said:
Hmm. Modifying an object while iterating over it isn't a great idea, ever:

I wouldn't say never. Algorithms that calculate some kind of
transitive closure can be expressed rather neatly by appending
items to a list being iterated over.

You can accommodate that kind of thing by writing the iterator
like this:

def __iter__(self):
i = 0
while i < len(self):
yield self
i += 1
 
T

Terry Reedy

I wouldn't say never.

How about "Modifying a collection while iterating over it without
understanding the dangers is a bad idea."

" Algorithms that calculate some kind of
transitive closure can be expressed rather neatly by appending
items to a list being iterated over.

Which is one reason list modification while iterating is not prohibited.
Deleting items while forward iterating and adding items while backward
iterating may miss items unexpectedly. Adding items ahead of forward
iteration and deleting items behind backward iterating are ok. The most
common example of the latter is successively popping item off a stack.
 
S

Steven D'Aprano

How about "Modifying a collection while iterating over it without
understanding the dangers is a bad idea."

"... unless you're being paid by the hour for debugging your code."

*wink*
 

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,995
Messages
2,570,236
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top