Резюме
Предположим, у меня есть 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?