Is Python `list.extend(iterator)` guaranteed to be lazy? : <h1>Summary</h1>

<p>Suppose I have an <code>iterator</code> that, as elements are consumed from it, performs some side effect, such as modifying a list.  If I define a list <code>l</code> and call <code>l.extend(iterator)</code>, is it guaranteed that <code>extend</code> will push elements onto <code>l</code> one-by-one, <em>as elements from the iterator are consumed</em>, as opposed to kept in a buffer and then pushed on all at once?</p>

<h1>My experiments</h1>

<p>I did a quick test in Python 3.7 on my computer, and <code>list.extend</code> seems to be lazy based on that test.  (See code below.)  Is this guaranteed by the spec, and if so, where in the spec is that mentioned?</p>

<p>(Also, feel free to criticize me and say "this is not Pythonic, you fool!"--though I would appreciate it if you also answer the question if you want to criticize me.  Part of why I'm asking is for my own curiosity.)</p>

<p>Say I define an iterator that pushes onto a list as it runs:</p>

<pre class="lang-py prettyprint-override"><code>l = []

def iterator(k):
  for i in range(5):
    print([j in k for j in range(5)])
    yield i

l.extend(iterator(l))
</code></pre>

<p>Here are examples of non-lazy (i.e. buffered) vs. lazy possible <code>extend</code> implementations:</p>

<pre class="lang-py prettyprint-override"><code>def extend_nonlazy(l, iterator):
  l += list(iterator)

def extend_lazy(l, iterator):
  for i in iterator:
    l.append(i)
</code></pre>

<h1>Results</h1>

<p>Here's what happens when I run both <em>known</em> implementations of <code>extend</code>.</p>

<hr>

<p>Non-lazy:</p>

<pre class="lang-py prettyprint-override"><code>l = []
extend_nonlazy(l, iterator(l))
</code></pre>

<pre><code># 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]
</code></pre>

<hr>

<p>Lazy:</p>

<pre class="lang-py prettyprint-override"><code>l = []
extend_lazy(l, iterator(l))
</code></pre>

<pre><code>[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]
</code></pre>

<hr>

<p>My own experimentation shows that native <code>list.extend</code> seems to work like the lazy version, but my question is: does the Python spec guarantee that?</p>
