Как на самом деле работает для -l oop в python - PullRequest
0 голосов
/ 26 апреля 2020

Раньше я думал, что for-l oop в python работает так: сначала он делает итератор, выполняя iter(iterable), затем next(that_new_iterator_object), а когда он поднимает StopIteration, то for-l oop заканчивается и переходит в блок else (если имеется), но здесь он работает по-другому

>>> a = [1,2,3,4,5,6,7,8,9]
>>> for i in a:
        del a[-1]
        print(i)

1
2
3
4
5

, где остальные числа 6,7,8, 9 новый объект итератора, который создается для -l oop, а переменная a отличается

Ответы [ 3 ]

5 голосов
/ 26 апреля 2020

для l oop работает так же, как вы описали. Однако вот как работает итератор списка , примерно:

class ListIterator:
    def __init__(self, lst):
        self.lst = lst
        self.idx = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.idx >= len(self.lst):
            raise StopIteration
        else:
            val = self.lst[self.idx]
            self.idx += 1
            return val

IOW, итератор зависит от списка, который вы модифицируете.

Итак, обратите внимание:

>>> class ListIterator:
...     def __init__(self, lst):
...         self.lst = lst
...         self.idx = 0
...     def __iter__(self):
...         return self
...     def __next__(self):
...         if self.idx >= len(self.lst):
...             raise StopIteration
...         else:
...             val = self.lst[self.idx]
...             self.idx += 1
...             return val
...
>>> a = list(range(10))
>>> iterator = ListIterator(a)
>>> for x in iterator:
...     print(x)
...     del a[-1]
...
0
1
2
3
4
>>>
2 голосов
/ 26 апреля 2020

Объект итератора содержит ссылку на список, он не копирует его для итерации.

Вы сокращаете список на каждой итерации, итератор закрывается, когда у него заканчивается 5 элементов.

(Тем не менее, мутирование итерируемого во время итерации не является хорошей практикой; dict s будет прямо жаловаться, если вы сделаете это.)

0 голосов
/ 26 апреля 2020

То, что - это примерно как for -l oop. Вы можете переписать его так, чтобы доказать себе, что поведение такое же:

>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> for_iter = iter(a)
>>> while True:
...     try:
...         i = next(for_iter)
...         del a[-1]
...         print(i)
...     except StopIteration:
...         break
... 
1
2
3
4
5
>>> 

iter(a) не содержит собственных ссылок на все элементы в a, только на список сам по себе.

...