How does Python manage a 'for' loop internally?

前端 未结 4 1983
臣服心动
臣服心动 2021-02-02 12:55

I\'m trying to learn Python, and I started to play with some code:

a = [3,4,5,6,7]
for b in a:
    print(a)
    a.pop(0)
<         


        
4条回答
  •  抹茶落季
    2021-02-02 13:25

    kjaquier and Felix have talked about the iterator protocol, and we can see it in action in your case:

    >>> L = [1, 2, 3]
    >>> iterator = iter(L)
    >>> iterator
    
    >>> next(iterator)
    1
    >>> L.pop()
    3
    >>> L
    [1, 2]
    >>> next(iterator)
    2
    >>> next(iterator)
    Traceback (most recent call last):
      File "", line 1, in 
    StopIteration
    

    From this we can infer that list_iterator.__next__ has code that behaves something like:

    if self.i < len(self.list):
        return self.list[i]
    raise StopIteration
    

    It does not naively get the item. That would raise an IndexError which would bubble to the top:

    class FakeList(object):
        def __iter__(self):
            return self
    
        def __next__(self):
            raise IndexError
    
    for i in FakeList():  # Raises `IndexError` immediately with a traceback and all
        print(i)
    

    Indeed, looking at listiter_next in the CPython source (thanks Brian Rodriguez):

    if (it->it_index < PyList_GET_SIZE(seq)) {
        item = PyList_GET_ITEM(seq, it->it_index);
        ++it->it_index;
        Py_INCREF(item);
        return item;
    }
    
    Py_DECREF(seq);
    it->it_seq = NULL;
    return NULL;
    

    Although I don't know how return NULL; eventually translates into a StopIteration.

提交回复
热议问题