2

I came across some code like this:

def func(tree):
 nodes = tree
 for node in nodes:
  yield node
  nodes += [42]

gen = func([-42, 3, 1, 4, 159])

for i in range(10):
 print(next(gen))

Does this code have undefined behaviour?

Specifically, does:

for node in nodes:
 yield node
 nodes += [42]

show undefined behviour?

I know that:

for node in nodes:
 # yield node
 nodes += [42]

may cause unexpected behaviour because the variable we are iterating through (nodes) is being updated in the for loop.

Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
ubndpdhsc
  • 43
  • 5

1 Answers1

2

No, why would the behavior be undefined?

The generator yields all original elements from the tree argument and then 42 to infinity.

>>> gen = func([1, 2, 3])
>>> next(gen)
1
>>> next(gen)
2
>>> next(gen)
3
>>> next(gen)
42
>>> next(gen)
42
>>> next(gen)
42

Extending nodes with [42] for each yield makes sure that the generator will never run out of numbers to yield.

The only problem is that if you call next enough times you will encounter a MemoryError because nodes grew too large.

timgeb
  • 76,762
  • 20
  • 123
  • 145
  • 1
    This will run out of memory eventually? You're not returning 42 everytime... You're extending the list by 42 everytime and then returning it. – SkryptX May 30 '20 at 21:00
  • 1
    just as an aside, you can use `itertools.chain(iterable, itertools.repeat(42))` to get a memory efficient version of this. – juanpa.arrivillaga May 30 '20 at 21:10
  • @timgeb I think the `for node in nodes: nodes += [42]` is undefined behaviour because I read somewhere that changing the `y` in `for x in y` inside the loop causes the object to be reallocated or something making the variable we are iterating through invalid (something to do with how memory or pointers work). – ubndpdhsc May 30 '20 at 21:28
  • 1
    @ubndpdhsc Nothing of what you read is true. See [this](https://stackoverflow.com/a/6260097/3620003) and [this](https://stackoverflow.com/a/47532461/3620003) answer for more details. Mutating or reassigning the loop variable might give you another result than what you wanted, but the behavior is well defined. – timgeb May 31 '20 at 07:36