Уступить за в

Я наткнулся на такой код:

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))

Имеет ли этот код неопределенное поведение?

В частности, делает:

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

показать неопределенное поведение?

Я знаю это:

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

может привести к неожиданному поведению, поскольку переменная, которую мы итерируем (nodes), обновляется в цикле for.


person ubndpdhsc    schedule 30.05.2020    source источник
comment
Да не получится. На самом деле это просто вызовет бесконечный цикл и, вероятно, рано или поздно приведет к ошибке.   -  person SkryptX    schedule 30.05.2020
comment
Нет, это не неопределенно   -  person juanpa.arrivillaga    schedule 30.05.2020
comment
@SkryptX работает. Почему вы говорите, что это не работает? Это неэффективная память, но она работает.   -  person juanpa.arrivillaga    schedule 31.05.2020
comment
@juanpa.arrivillaga Считаете ли вы, что код с тривиальной и полностью предотвратимой утечкой памяти работает? Я бы решительно возражал против этого. Неэффективная память — это не то же самое, что съедать память до тех пор, пока она не выйдет из строя   -  person SkryptX    schedule 31.05.2020


Ответы (1)


Нет, почему поведение не определено?

Генератор выдает все исходные элементы из аргумента дерева, а затем 42 до бесконечности.

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

Расширение nodes с помощью [42] для каждого выхода гарантирует, что у генератора никогда не закончатся числа для выхода.

Единственная проблема заключается в том, что если вы вызовете next достаточное количество раз, вы столкнетесь с MemoryError, потому что nodes стало слишком большим.

person timgeb    schedule 30.05.2020
comment
Это исчерпает память в конце концов? Вы не возвращаете 42 каждый раз... Вы каждый раз расширяете список на 42, а затем возвращаете его. - person SkryptX; 31.05.2020
comment
кроме того, вы можете использовать itertools.chain(iterable, itertools.repeat(42)), чтобы получить версию с эффективным использованием памяти. - person juanpa.arrivillaga; 31.05.2020
comment
@timgeb Я думаю, что for node in nodes: nodes += [42] - это неопределенное поведение, потому что я где-то читал, что изменение y в for x in y внутри цикла приводит к перераспределению объекта или к чему-то, что делает переменную, которую мы итерируем, недействительной (что-то связанное с тем, как работает память или указатели). - person ubndpdhsc; 31.05.2020