Встроенная функция iter () и оператор for - PullRequest
5 голосов
/ 03 августа 2020

Я пытаюсь понять, как оператор for x in y работает в python. Я нашел здесь документацию: https://docs.python.org/3/reference/compound_stmts.html#for. В нем говорится, что выражение y вычисляется один раз и должно давать итеративный объект.

Следующий код печатает числа 1,2,3,4,5, хотя мой класс не реализует __iter__ ( что является моим пониманием итерации).

class myclass:
    def __init__(self):
        self.x = [1,2,3,4,5]
    def __getitem__(self,index):
        return self.x[index]
m = myclass()
for i in m:
    print(i)

Я знаю, что существует встроенный метод iter(), который возвращает итератор для объекта последовательности, используя его функцию .__getitem__() и счетчик, который начинается с 0.

Я предполагаю, что python вызывает функцию iter() для выражения y в операторе for x in y. Таким образом, он преобразует мой объект, реализующий .__getitem__, в итератор, и когда мой объект вызывает исключение IndexError во время вызова .__getitem__, итератор превращает это в исключение StopIteration, а для l oop заканчивается.

Это правильно? Правильно это или нет, объясняется ли это где-то в документации, или мне нужно go заглянуть внутрь исходного кода реализации?

Ответы [ 3 ]

0 голосов
/ 15 августа 2020

Happy Pythoning.

getitem был единственным методом до версии Python 2.2 для итерации циклов на итераторах. В версии Pyhton 2.2 был введен метод iter . В методе getitem индекс автоматически передается как индекс 0 ie 0 и увеличивается на 1 при каждой итерации выполнения l oop. Мы выходим из l oop при возникновении IndexError. Чтобы иметь обратную совместимость, метод getitem по-прежнему не считается устаревшим (до Python версии 3.8.5). Итак, теперь сначала l oop ищет метод iter в итеративном режиме, и если этот метод отсутствует, выполняется поиск метода getitem . Так как давно вернулся Python 2.2, сегодня разработчики предпочитают использовать методы iter и next , что дает четкое представление об итерации и итераторе.

Вы можете взять еще один пример getitem вместе с вашим примером, чтобы понять итератор и итерацию следующим образом.

class myclass:
    def __init__(self):
        pass
    def __getitem__(self,index):
        return index
m = myclass()
for i in m:
    print(i)

Приведенный выше код создаст бесконечное l oop, потому что первое значение индекса будет будет 0, затем 1, затем 2 и так далее, и никаких ошибок не возникнет.

Вывод приведенного выше кода:

0
1
2
3
4
5
6
7
8
9
10
11
.
.
.
.

Спасибо, что поделились вопросом.

0 голосов
/ 15 августа 2020

Согласно PEP 234, который был полезен в комментариях выше,

iter(obj) звонит PyObject_GetIter(obj).

Он должен сказать следующее: для циклов:

Байт-код Python, сгенерированный для циклов for, изменен для использования новых кодов операций, GET_ITER и FOR_ITER, которые используют протокол итератора, а не протокол последовательности, чтобы получить следующий значение для переменной l oop. Это позволяет использовать от l oop до l oop над непоследовательными объектами, которые поддерживают слот tp_iter. Другие места, где интерпретатор перебирает значения последовательности, также следует изменить для использования итераторов.

Наконец, https://docs.python.org/3/library/dis.html#opcode -GET_ITER объясняет, что GET_ITER эквивалентно вызов iter.

Собирая все вместе, кажется, что for l oop ведет себя так же, как встроенная функция iter.

0 голосов
/ 14 августа 2020

Видите, реальная реализация находится в C с огромным количеством модификаций в самом языке C и несколькими заголовками. Списки, наборы и словари структур данных включают использование enums. enums отлично подходят для итераций со скоростью и эффективностью, как и Python. Однако мне не хотелось бы нырять намного глубже. Вы можете взглянуть на исходный код cpython на GitHub , если вы опытный C или разработчик на C ++. Не стесняйтесь спрашивать меня, хотите ли вы узнать больше :).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...