Резюме
Предположим, у меня есть iterator который, поскольку элементы потребляются из него, выполняет некоторый побочный эффект, такой как изменение списка. Если я определю список l и вызову l.extend(iterator), гарантируется ли, что extend будет помещать элементы в l один за другим, так как элементы из итератора потребляются, а не хранятся в буфере, а затем помещаются в все сразу?
Мои эксперименты
Я провел быстрый тест в Python 3.7 на своем компьютере, и list.extend кажется ленивым, основываясь на этом тесте. (См. Код ниже.) Гарантируется ли это спецификацией, и если да, то где в спецификации упоминается?
(Кроме того, не стесняйтесь критиковать меня и говорить: "Это не Pythonic, вы дурак!" --though Я был бы признателен, если бы вы также ответили на вопрос, если хотите критиковать меня. собственное любопытство.)
Скажем, я определяю итератор, который добавляется в список во время его работы:
l = []
def iterator(k):
for i in range(5):
print([j in k for j in range(5)])
yield i
l.extend(iterator(l))
Вот примеры не ленивых (то есть буферизованных) и ленивых реализаций extend:
def extend_nonlazy(l, iterator):
l += list(iterator)
def extend_lazy(l, iterator):
for i in iterator:
l.append(i)
Результаты
Вот что происходит, когда я запускаю обе известные реализации extend.
Non-ленивый:
l = []
extend_nonlazy(l, iterator(l))
# output
[False, False, False, False, False]
[False, False, False, False, False]
[False, False, False, False, False]
[False, False, False, False, False]
[False, False, False, False, False]
# l = [0, 1, 2, 3, 4]
Ленивый:
l = []
extend_lazy(l, iterator(l))
[False, False, False, False, False]
[True, False, False, False, False]
[True, True, False, False, False]
[True, True, True, False, False]
[True, True, True, True, False]
Мои собственные эксперименты показывают, что нативный list.extend похоже, работает как ленивая версия, но мой вопрос: гарантирует ли это спецификация Python?