Несмотря на то, что я читал об этом, я до сих пор не понимаю, как работает __iter__. Что было бы простым объяснением?
Я видел def__iter__(self): return self. Я не вижу, как это работает, или о том, как это работает.
Несмотря на то, что я читал об этом, я до сих пор не понимаю, как работает __iter__. Что было бы простым объяснением?
Я видел def__iter__(self): return self. Я не вижу, как это работает, или о том, как это работает.
Итератору необходимо определить два метода: __iter__() и __next__() (next() в python2). Обычно сам объект определяет метод __next__() или next(), поэтому он просто возвращает себя как итератор. Это создает итерабельность, которая сама по себе является итератором. Эти методы используются операторами for и in.
Python 3 docs: docs.python.org/3/library/stdtypes.html#iterator-types
Python 2 docs: docs.python.org/2/library/stdtypes.html#iterator-types
Как я могу сказать:
__iter__ определяет метод класса, который возвращает итератор (объект, который последовательно дает следующий элемент, содержащийся в вашем объекте).
Объект итератора, возвращаемый __iter__(), может быть почти любым объектом, если он определяет метод next().
Метод next вызывается операторами типа for ... in ..., чтобы получить следующий элемент, а next() должен поднимать исключение StopIteration, когда больше нет элементов.
Что бы это ни значило, это позволяет определить, как выполняется повторение вашего объекта, а __iter__ предоставляет общий интерфейс, с которым любая другая функция python знает, как работать.
Спецификацией для def __iter__(self): являются: он возвращает итератор. Итак, если self - итератор, то return self явно уместен.
"Являясь итератором" означает "имеющий метод __next__(self)" (в Python 3, в Python 2, имя рассматриваемого метода, к сожалению, просто next, очевидно, что сбой дизайна имени для специального метода).
В Python 2.6 и выше лучшим способом реализации итератора обычно является использование соответствующего абстрактного базового класса из стандартной библиотеки collections module - в Python 2.6, код может быть (не забудьте вызвать метод __next__ вместо этого в Python 3):
import collections
class infinite23s(collections.Iterator):
def next(self): return 23
экземпляр этого класса будет возвращать бесконечно много копий 23 при повторении (например, itertools.repeat(23)), поэтому цикл должен быть завершен иначе. Дело в том, что подклассификация collections.Iterator добавляет правильный метод __iter__ от вашего имени - здесь не большая вещь, но хороший общий принцип (избегайте повторяющихся, стандартных шаблонов, таких как стандартные однострочные итераторы __iter__ - в повторение, нет добавленной стоимости и большого количества вычитаемого значения! -).
Класс, поддерживающий метод __iter__, вернет экземпляр объекта итератора: объект, поддерживающий метод next(). Этот объект будет использоваться в заявлениях "за" и "в".
В Python итератором является любой объект, поддерживающий протокол итератора. Часть этого протокола заключается в том, что объект должен иметь метод __iter__(), который возвращает объект итератора. Я полагаю, это дает вам некоторую гибкость, так что объект может передать обязанности итератора внутреннему классу или создать какой-то специальный объект. В любом случае метод __iter__() обычно имеет только одну строку, и эта строка часто просто return self
Другая часть протокола - это метод next(), и именно здесь выполняется настоящая работа. Этот метод должен выяснить или создать или получить следующее, и вернуть его. Возможно, потребуется отслеживать, где он находится, чтобы в следующий раз, когда он был вызван, он действительно возвращает следующую вещь.
Когда у вас есть объект, который возвращает следующую вещь в последовательности, вы можете свернуть цикл for, который выглядит следующим образом:
myname = "Fredericus"
x = []
for i in [1,2,3,4,5,6,7,8,9,10]:
x.append(myname[i-1])
i = i + 1 # get the next i
print x
в это:
myname = "Fredericus"
x = [myname[i] for i in range(10)]
print x
Обратите внимание, что где-то там, где у нас есть код, который получает следующее значение i, потому что диапазон (10) является объектом, который ПОСЛЕДУЕТ в протокол итератора, а понимание списка - это конструкция, которая ИСПОЛЬЗУЕТ протокол итератора.
Вы также можете напрямую использовать протокол итератора. Например, при написании скриптов для обработки CSV файлов я часто пишу это:
mydata = csv.reader(open('stuff.csv')
mydata.next()
for row in mydata:
# do something with the row.
Я использую итератор напрямую, вызывая next(), чтобы пропустить строку заголовка, а затем косвенно использовать его с помощью встроенного оператора in в инструкции for.