Comments 8
Небольшой трюк для любителей итераторов.
class MyRange:
def __init__(self, start, end):
self.start = start
self.end = end
def __iter__(self):
return iter(range(self.start, self.end))
Классная статья
Неплохая статья, но обнаружил неточность в описании пункта 4(__getitem__ ).
Все-таки к элементам по индексу в словаре мы не можем обращаться, только по ключу.
numbers = MyRange(1, 5)
iterator = iter(numbers) # Получаем итератор
print(next(iterator)) # Выведет: 1
print(next(iterator)) # Выведет: 2
print(next(iterator)) # Выведет: 3
print(next(iterator)) # Выведет: 4
print(next(iterator)) # Выведет: StopIteration исключение
iterator = iter(numbers) # Пытаемся получить новый итератор
print(next(iterator)) # Надеемся, что он выдаст 1, но получаем StopIteration исключение
# WTF?! Нам подсунули использованный итератор!!
ну да, мы возвращаем self, который не меняется если ещё раз выполнить iter(numbers)
, а внутри iter метода мы счётчик start
никак не обнуляем, поэтому вызывается исключение. Если бы автор выделил для переменной счётчика отдельную переменную и обнулил её, тогда при попытке второй раз воспользоваться итератором всё было бы хорошо.
Не стоит называть эти методы магическими. В них нет никакой магии, когда мы получаем результат, но не знаем, что происходит внутри в процессе его получения. Эти методы стоит называть специальными или предзаданными (predefined), т.к. они предназначены для решения конкретных задач понятным описанным в документации способом и не могут быть переопределены.
Python-волшебство: как магические методы облегчают жизнь программиста