Frage

Why this code throws "StopIteration":

stub_generator = (x for x in range(5))
stub_dict = {}
stub_dict[next(stub_generator)] = list(stub_generator)

and this works?

stub_generator = (x for x in range(5))
stub_dict = {}
temp_1 = next(stub_generator)
temp_2 = list(stub_generator)
stub_dict[temp_1] = temp_2
War es hilfreich?

Lösung

This behavior is because of two things:

  1. The right-hand side of an assignment statement is evaluated before the left-hand side.

  2. Generator objects can be iterated over only once.


To explain further, when this code is executed:

stub_dict[next(stub_generator)] = list(stub_generator)

this part:

list(stub_generator) 

will be evaluated before this part:

stub_dict[next(stub_generator)]

Moreover, placing stub_generator in list will cause the generator to be iterated over entirely and thus exhausted. When next(stub_generator) is then evaluated afterwards, a StopIteration exception is raised because stub_generator is now empty.


This code however is different:

temp_1 = next(stub_generator)
temp_2 = list(stub_generator)

It will execute next(stub_generator) before executing list(stub_generator). Meaning, stub_generator will still have some items in it when it is converted to a list.

Andere Tipps

As per the language reference for assignment statements,

assignment_stmt ::=  (target_list "=")+ (expression_list | yield_expression)

An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.

So, the expression on the right hand side is evaluated first. So, list(stub_generator) is executed first and that exhausts the generator and then you are doing next(stub_generator) which tries to iterate an already exhausted generator. That is why StopIteration is raised.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top