Python: iterating over a non-empty list without an if clause becomes empty. What for?

How does an iterator in a nonempty sequence without filtering and without aggregation ( sum() , etc.) produce nothing?

Consider a simple example:

 sequence = ['a', 'b', 'c'] list((el, ord(el)) for el in sequence) 

This gives [('a', 97), ('b', 98), ('c', 99)] , as expected.

Now just replace ord(el) out with an expression that extracts the first value from some generator using (...).next() - forgives a far-fetched example:

 def odd_integers_up_to_length(str): return (x for x in xrange(len(str)) if x%2==1) list((el, odd_integers_up_to_length(el).next()) for el in sequence) 

This gives [] . Yes, an empty list. No ('a', stuff ) tuples. Nothing.

But we do not filter, do not aggregate and do not reduce. A generator expression over n objects without filtering or aggregation should give n objects, right? What's happening?

+4
source share
4 answers

odd_integers_up_to_length(el).next() will call StopIteration, which does not get there, but falls on the generator expression inside it, stopping it, bringing nothing.

look at the first iteration when the value is 'a':

 >>> odd_integers_up_to_length('a').next() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration 
+13
source

What happens is that a call to next() throws a StopIteration exception, which aligns the stack to an external generator expression and stops this iteration.

A StopIteration is a normal way for an iterator to signal this. Usually we do not see this, because usually the next() call occurs inside a construct that consumes an iterator, for example. for x in iterator or sum(iterator) . But when we call next() directly, we are responsible for catching StopIteration . This does not lead to a leak in the abstraction, which leads to unexpected behavior on the external iteration.

Lesson, I suppose: be careful with direct calls to next() .

+4
source

str is a reserved word, you must specify your variable in different ways

I also had to report the following

0
source
 >>> seq=['a','b','c'] >>> list((el,4) for el in seq) [('a',4), ('b',4), ('c',4)] 

So this is not a list gives you problems here ...

0
source

All Articles