Created
March 19, 2020 08:59
-
-
Save K900/86ca8f043c59cec3a7c029bf27124113 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Введение: про термины | |
# | |
# 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