Iteratory

  • relacja konsument - producent
  • obiekt, który wie jak poruszać się po kolejnych elementach kolekcji
  • implementuje protokół iteratora
  • iteratory na tej samej kolekcji są niezależne od siebie
  • brak możliwości uruchomienia iteratora od początku
  • implementuje funkcję __next__, która zwraca strumień danych
  • gdy przejdzie do końca kolekcji rzuca wyjątkiem StopIteration
  • implementuje funkcję __iter__, która zwraca iterator

In [ ]:
lista = [1, 2, 3]
for el in lista:
    print(el)

In [ ]:
lista = [1, 2, 3]
iterator = iter(lista)
print(iterator)
print(type(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))

In [ ]:
class CustomIterator():
    def __init__(self):
        self.liczby = [1, 2, 3]
        self.index = -1
        
    def __iter__(self):
        print("pobieram iterator")
        return self
        
    def __next__(self):
        print("pobieram kolejna wartosc")
        self.index = self.index + 1
        if (self.index == len(self.liczby)):
            raise StopIteration
        else:
            return self.liczby[self.index]

In [ ]:
for x in CustomIterator():
    print(x)

In [ ]:
import random

class CustomRandomIterator():
    def __init__(self):
        self.liczby = random.sample(range(10), 5)
        
    def __iter__(self):
        return iter(self.liczby)

In [ ]:
for x in CustomRandomIterator():
    print(x)

In [ ]:
class CustomCollection():
    def __init__(self, collection):
        self.collection = collection
        
    def __iter__(self):
        return CustomIterator(self.collection)
    

class CustomIterator():
    def __init__(self, collection):
        self.collection = collection
        self.index = -1
        self.stop_index = len(collection)
        
    def __next__(self):
        self.index = self.index + 1
        if (self.index == self.stop_index):
            raise StopIteration
        else:
            return self.collection[self.index]

In [ ]:
for x in CustomCollection(list(range(5))):
    print(x)

In [ ]:
class CustomCollection():
    def __init__(self, collection):
        self.collection = collection
        
    def __iter__(self):
        return CustomIterator(self.collection)
    

class CustomIterator():
    def __init__(self, collection):
        self.collection = collection
        self.index = -1
        self.stop_index = len(collection)
        
    def __next__(self):
        self.index = self.index + 1
        if (self.index == self.stop_index):
            raise StopIteration
        else:
            return self.collection[self.index]

In [ ]:
iterator = iter(CustomCollection(list(range(10))))
print(type(iterator))
print(next(iterator))

Generatory

  • implementuje protokół iteratora
  • funkcja zawierająca słowo kluczowe yield
  • yield zatrzymuje wykonanie funkcji, przy ponownym wywołaniu uruchamia wykonywanie od słowa yield

In [ ]:
import random
def frange(start, stop, step=1):
    x = start
    while x < stop:
        yield x
        x += step
        
for el in frange(1, 4, 0.5):
    print(el)

In [ ]:
import random
def random_numbers_generator(quantity=5, start=0, stop=10):
    while quantity > 0:
        yield random.randrange(start, stop)
        quantity -= 1
        
for el in random_numbers_generator():
    print(el)

In [ ]:
import random
def random_numbers_generator(quantity=5, start=0, stop=10):
    while quantity > 0:
        yield random.randrange(start, stop)
        quantity -= 1
        
for el in random_numbers_generator():
    print(el)

In [ ]:
def only_unique(items):
    seen = set()
    for item in items:
        if item in seen:
            continue
        else:
            seen.add(item)
            yield item
            
list(only_unique('aaaabbbcccddeeefff'))

In [ ]:
from collections import deque
import random

class RandomNumbersGenerator():
    
    def __init__(self, count=5, historylen=3):
        self._count = count
        self.history = deque(maxlen=historylen)
        
    def __enter__(self):
        return self
    
    def __exit__(self, *args):
        pass
    
    def __iter__(self):
        while self._count > 0:
            random_number = random.randrange(10)
            self.history.append(random_number)
            self._count = self._count - 1
            yield random_number

In [ ]:
with RandomNumbersGenerator(count=10) as rng:
    for el in iter(rng):
       print(el, rng.history)

In [ ]:
from collections import Iterable
def flatten(items):
    for item in items:
        if isinstance(item, Iterable):
            yield from flatten(item)
        else:
            yield item

x = [1, 2, 3, [4, 5, [6, 7], 8], 9]
for el in flatten(x):
    print(el)

Python2

from collections import Iterable def flatten(items): for item in items: if isinstance(item, Iterable): for y in flatten(item): yield y else: yield item x = [1, 2, 3, [4, 5, [6, 7], 8], 9] for el in flatten(x): print(el)