Summary
=======

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

My experiments
==============

I did a quick test in Python 3.7 on my computer, and `list.extend` 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?

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

Say I define an iterator that pushes onto a list as it runs:

```py
l = []

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

l.extend(iterator(l))

```

Here are examples of non-lazy (i.e. buffered) vs. lazy possible `extend` implementations:

```py
def extend_nonlazy(l, iterator):
  l += list(iterator)

def extend_lazy(l, iterator):
  for i in iterator:
    l.append(i)

```

Results
=======

Here's what happens when I run both *known* implementations of `extend`.

---

Non-lazy:

```py
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]

```

---

Lazy:

```py
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]

```

---

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