вторник, 1 октября 2019 г.

ЛМНты Python, 21 - 25

>>> Последовательность из итератора

Последовательность можно задать явно, перечислив ее элементы, или аналитически, передав конструктору итератор, порождающий элементы последовательности. Наверное, самый популярный итератор – тот, что предоставляется объектом класса range, получаемым с помощью функции range().

>>> it = iter(range(5))
>>> type(it)
<class 'range_iterator'>
>>> next(it)
0
>>> next(it)
1
>>> next(it)
2
>>> next(it)
3
>>> next(it)
4
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

Последовательности с его помощью задаются так:

>>> list(range(5))
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> bytes(range(127))
b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'

>>> Свой итератор

Чтобы написать итератор, нужно в собственном классе реализовать методы __iter__ и __next__, которые вызываются функциями iter() и next(), соответственно. Пример:

>>> class Tens(object):
...     
...     def __init__(self, upper=100):
...         self.currval = 0
...         self.upper = upper
...     
...     def __iter__(self):
...         return self
...     
...     def __next__(self):
...         currval = self.currval
...         if currval < self.upper:
...             self.currval += 10
...             return currval
...         else:
...             raise StopIteration
...

>>> list(Tens())
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

>>> for i in Tens(50):
...     print(i)
...
0
10
20
30
40

>>> Бесконечные итерации

Модуль itertools стандартной библиотеки Python предоставляет ряд готовых итераторов. Среди них три бесконечных итератора, поэтому в следующих примерах нужно позаботиться о выходе из циклов:

>>> from itertools import count, cycle, repeat

>>> # считать от нуля
... for i, v in enumerate(count(0)):
...     print(v)
...     if i == 4:
...         break
...
0
1
2
3
4
>>> # зациклить последовательность
... for i, v in enumerate(cycle([0, 1, 2])):
...     print(v)
...     if i == 4:
...         break
...
0
1
2
0
1
>>> # повторять указанное значение
... for i, v in enumerate(repeat('hello')):
...     print(v)
...     if i == 4:
...         break
...
hello
hello
hello
hello
hello

>>> Файл как итератор

Еще один замечательный итератор позволяет построчно читать файлы. В следующем примере вначале создается пятистрочный текстовый файл, а затем построчно читается и выводится:

>>> with open('file.txt', 'w') as f:
...     f.writelines(['%i\n' % i for i in range(5)])
...
>>> with open('file.txt') as f:
...     for line in f:
...         print(line, end='')
...
0
1
2
3
4

Как обычно, с помощью итератора можно инициализировать последовательность:

>>> with open('file.txt') as f:
...     lines = tuple(f)
...
>>> print(lines)
('0\n', '1\n', '2\n', '3\n', '4\n')

>>> Что умеет range

Тема функции range не будет раскрыта, если не привести примеры со вторым и третьим параметрами: верхней границей диапазона и шагом приращения, соответственно.

>>> list(range(3, 9))
[3, 4, 5, 6, 7, 8]
>>> list(range(3, 9, 2))
[3, 5, 7]

Если шаг отрицательный, то первый параметр должен быть больше второго:

>>> list(range(9, 3, -1))
[9, 8, 7, 6, 5, 4]
>>> list(range(9, 3, -2))
[9, 7, 5]

Проверка на вхождение в range учитывает, что диапазон разреженный при шаге, не равном единице:

>>> 10**90 in range(0, 10**100, 2)
True
>>> 10**90-1 in range(0, 10**100, 2)
False

Комментариев нет:

Отправить комментарий