Итераторы

In [1]:
class Range:
    def __init__(self, start, stop):
        self._current = start
        self._stop = stop
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self._current < self._stop:
            result = self._current
            self._current += 1
            return result
        else:
            raise StopIteration
            
for e in Range(0, 3):
    print(e)
            
i = Range(0, 3)
print(next(i))
print(next(i))
i = iter(i)
print(next(i))
print(next(i))
0
1
2
0
1
2
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-1-362d28f4cab1> in <module>()
     23 i = iter(i)
     24 print(next(i))
---> 25 print(next(i))

<ipython-input-1-362d28f4cab1> in __next__(self)
     13             return result
     14         else:
---> 15             raise StopIteration
     16 
     17 for e in Range(0, 3):

StopIteration: 

Генераторные функции

In [2]:
def range(start, stop):
    current = start
    while current < stop:
        yield current
        current += 1

        
g = range(0, 3)
for e in g:
    print(e)

g = range(0, 3)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
0
1
2
0
1
2
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-2-4a5e9870810c> in <module>()
     14 print(next(g))
     15 print(next(g))
---> 16 print(next(g))

StopIteration: 
In [3]:
def range(start, stop):
    current = start
    while current < stop:
        reset = yield current
        if reset is not None:
            current = reset - 1
        current += 1

        
g = range(0, 3)
print(next(g))
print(next(g))
print(g.send(0))
print(next(g))
0
1
0
1

yield from

In [4]:
def range(start, stop):
    current = start
    while current < stop:
        reset = yield current
        if reset is not None:
            current = reset - 1
        current += 1

def two_ranges(start, stop):
    for x in range(start, stop):
        yield x
    for x in range(start, stop):
        yield x
        
g = two_ranges(0, 3)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
0
1
2
0
1
2
In [5]:
g = two_ranges(0, 3)
print(next(g))
print(next(g))
print(g.send(-1))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
0
1
2
0
1
2
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-5-f319fcd1c73f> in <module>()
      6 print(next(g))
      7 print(next(g))
----> 8 print(next(g))

StopIteration: 
In [6]:
def range(start, stop):
    current = start
    while current < stop:
        reset = yield current
        if reset is not None:
            current = reset - 1
        current += 1

def two_ranges(start, stop):
    yield from range(start, stop)
    yield from range(start, stop)
        
g = two_ranges(0, 3)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
0
1
2
0
1
2
In [7]:
g = two_ranges(0, 3)
print(next(g))
print(next(g))
print(g.send(-1))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
0
1
-1
0
1
2
0

Генераторные выражения

In [1]:
g = (x for x in [1, 2, 3])
print(next(g))
print(next(g))
print(next(g))
print(next(g))
1
2
3
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-1-bf891876bdc5> in <module>()
      3 print(next(g))
      4 print(next(g))
----> 5 print(next(g))

StopIteration: 
In [2]:
g = (x * x for x in [1, 2, 3])
for e in g:
    print(e)
1
4
9
In [3]:
g = (x * x for x in range(10) if x % 2 == 0)
list(g)
Out[3]:
[0, 4, 16, 36, 64]
In [4]:
g = (x * y for x in range(3) for y in range(4))
list(g)
Out[4]:
[0, 0, 0, 0, 0, 1, 2, 3, 0, 2, 4, 6]

Comprehensions

In [5]:
a = [x * x for x in [1, 2, 3]]
a
Out[5]:
[1, 4, 9]
In [6]:
s = {x * x for x in [1, 2, 3]}
s
Out[6]:
{1, 4, 9}
In [7]:
d = {x: x * x for x in [1, 2, 3]}
d
Out[7]:
{1: 1, 2: 4, 3: 9}

itertools

In [8]:
import itertools


i = itertools.chain(range(3), range(5), range(2))
for e in i:
    print(e)
0
1
2
0
1
2
3
4
0
1
In [9]:
i = itertools.combinations(range(4), 3)
list(i)
Out[9]:
[(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]
In [10]:
i = itertools.permutations(range(4), 3)
list(i)
Out[10]:
[(0, 1, 2),
 (0, 1, 3),
 (0, 2, 1),
 (0, 2, 3),
 (0, 3, 1),
 (0, 3, 2),
 (1, 0, 2),
 (1, 0, 3),
 (1, 2, 0),
 (1, 2, 3),
 (1, 3, 0),
 (1, 3, 2),
 (2, 0, 1),
 (2, 0, 3),
 (2, 1, 0),
 (2, 1, 3),
 (2, 3, 0),
 (2, 3, 1),
 (3, 0, 1),
 (3, 0, 2),
 (3, 1, 0),
 (3, 1, 2),
 (3, 2, 0),
 (3, 2, 1)]
In [11]:
i = itertools.cycle(range(4))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
0
1
2
3
0
1
2
3
0
In [12]:
i = itertools.product("abcdefgh", range(1, 9))
list(i)
Out[12]:
[('a', 1),
 ('a', 2),
 ('a', 3),
 ('a', 4),
 ('a', 5),
 ('a', 6),
 ('a', 7),
 ('a', 8),
 ('b', 1),
 ('b', 2),
 ('b', 3),
 ('b', 4),
 ('b', 5),
 ('b', 6),
 ('b', 7),
 ('b', 8),
 ('c', 1),
 ('c', 2),
 ('c', 3),
 ('c', 4),
 ('c', 5),
 ('c', 6),
 ('c', 7),
 ('c', 8),
 ('d', 1),
 ('d', 2),
 ('d', 3),
 ('d', 4),
 ('d', 5),
 ('d', 6),
 ('d', 7),
 ('d', 8),
 ('e', 1),
 ('e', 2),
 ('e', 3),
 ('e', 4),
 ('e', 5),
 ('e', 6),
 ('e', 7),
 ('e', 8),
 ('f', 1),
 ('f', 2),
 ('f', 3),
 ('f', 4),
 ('f', 5),
 ('f', 6),
 ('f', 7),
 ('f', 8),
 ('g', 1),
 ('g', 2),
 ('g', 3),
 ('g', 4),
 ('g', 5),
 ('g', 6),
 ('g', 7),
 ('g', 8),
 ('h', 1),
 ('h', 2),
 ('h', 3),
 ('h', 4),
 ('h', 5),
 ('h', 6),
 ('h', 7),
 ('h', 8)]