Skip to content

Instantly share code, notes, and snippets.

@K900
Created March 19, 2020 08:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save K900/86ca8f043c59cec3a7c029bf27124113 to your computer and use it in GitHub Desktop.
Save K900/86ca8f043c59cec3a7c029bf27124113 to your computer and use it in GitHub Desktop.
#
# Введение: про термины
#
# iterable - это любой объект, который определяет метод __iter__,
# то есть от него можно получить итератор.
#
# Итератор - это объект, который определяет метод __next__.
# По нему можно итерироваться (т.е. дергать у него __next__, пока не
# вылетит StopIteration).
#
# Есть аналогичные асинхронные методы __aiter__ и __anext__, которые
# отличаются тем, что возвращают Future<T> вместо T.
#
# Вместо x.__iter__() принято писать iter(x), вместо x.__next__() - next(x).
# Это стандартные функции, как len(x) вместо x.__len__().
#
# немножко бойлерплейта
class assert_raises:
def __init__(self, ty):
self.ty = ty
def __enter__(self):
return self
def __exit__(self, ty, e, tb):
assert ty == self.ty
return True
# ...поехали!
# списки - iterable
my_list = [1, 2, 3]
# мы можем получить итератор, вызвав __iter__()
first_iterator = iter(my_list)
second_iterator = iter(my_list)
print(f'{type(first_iterator) = }')
# каждый вызов __iter__ у списка возвращает независимый итератор
assert first_iterator != second_iterator
# а __iter__ итератора возвращает сам себя!
assert iter(first_iterator) is first_iterator
# у итераторов можно дергать __next__
assert next(first_iterator) == 1
assert next(first_iterator) == 2
assert next(first_iterator) == 3
# пока не вылетит StopIteration
with assert_raises(StopIteration):
next(first_iterator)
# второй итератор не зависит от первого!
assert next(second_iterator) == 1
# сам список - не итератор!
with assert_raises(TypeError):
next(my_list)
# функции-генераторы позволяют описывать сложные итераторы
def genfunc():
yield 1
yield 2
yield 3
# функция - не iterable и не итератор
with assert_raises(TypeError):
iter(genfunc)
with assert_raises(TypeError):
next(genfunc)
# но если ее вызвать, то мы получим итератор!
gen = genfunc()
print(f'{type(gen) = }')
assert iter(gen) is gen
assert next(gen) == 1
assert next(gen) == 2
assert next(gen) == 3
with assert_raises(StopIteration):
next(gen)
# каждый вызов функции создает новый итератор
assert genfunc() != genfunc()
# generator expressions сразу создают итератор
genexpr = (i for i in [1, 2, 3])
print(f'{type(genexpr) = }')
assert iter(genexpr) is genexpr
assert next(genexpr) == 1
assert next(genexpr) == 2
assert next(genexpr) == 3
with assert_raises(StopIteration):
next(genexpr)
# list/dict/set comprehensions создают структуру данных
my_list = [-i for i in (-1, -2, -3)]
assert type(my_list) == list
# к которой потом применимы все остальные операции
it = iter(my_list)
assert next(it) == 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment