Я помогаю поддерживать некоторый код, который теперь включает в себя автоматическое тестирование Python 3.7. Это привело меня к некоторым проблемам, связанным с PEP 479 «Изменение обработки StopIteration внутри генераторов». Мое наивное понимание заключалось в том, что вы можете использовать блок try-Кроме того, чтобы изменить старый код, чтобы он был совместим со всеми версиями Python, например,
Старый код:
def f1():
it = iter([0])
while True:
yield next(it)
print(list(f1()))
# [0] (in Py 3.6)
# "RuntimeError: generator raised StopIteration" (in Py 3.7;
# or using from __future__ import generator_stop)
становится:
def f2():
it = iter([0])
while True:
try:
yield next(it)
except StopIteration:
return
print(list(f2()))
# [0] (in all Python versions)
Для этого тривиального примера это работает, но я нашел для более сложного кода, который я рефакторинг это не делает. Вот минимальный пример с Py 3.6:
class A(list):
it = iter([0])
def __init__(self):
while True:
self.append(next(self.it))
class B(list):
it = iter([0])
def __init__(self):
while True:
try:
self.append(next(self.it))
except StopIteration:
raise
class C(list):
it = iter([0])
def __init__(self):
while True:
try:
self.append(next(self.it))
except StopIteration:
return # or 'break'
def wrapper(MyClass):
lst = MyClass()
for item in lst:
yield item
print(list(wrapper(A)))
# [] (wrong output)
print(list(wrapper(B)))
# [] (wrong output)
print(list(wrapper(C)))
# [0] (desired output)
Я знаю, что примеры A
и B
в точности эквивалентны и что случай C
является правильным способом, совместимым с Python 3.7 (я также знаю, что рефакторинг в цикл for
будет иметь смысл для многих примеров, включая этот придуманный).
Но вопрос в том, почему примеры с A
и B
создают пустой список []
, а не [0]
?