inspirovane http://www.python-course.eu/python3_generators.php
__next__
a funkciu __iter__
, ktora vracia self
__next__
. Podobny koncept sa da najst vo vela jazykoch. Napriklad aj v Jave.
In [ ]:
cities = ["Paris", "Berlin", "Hamburg", "Frankfurt", "London", "Vienna", "Amsterdam", "Den Haag"]
for location in cities:
print("location: " + location)
In [ ]:
dir(cities.__iter__())
In [ ]:
print(type(cities.__iter__()))
print(type(cities.__iter__().__iter__()))
print(cities.__iter__().__next__())
In [ ]:
capitals = { "France":"Paris", "Netherlands":"Amsterdam", "Germany":"Berlin", "Switzerland":"Bern", "Austria":"Vienna"}
for country in capitals:
print("The capital city of " + country + " is " + capitals[country])
yield
na zastavenie vykonavania a na vratenie hodnotynext()
(alebo metody __next__()
)yield
yield
ako je v Rubyyield
volanie bloku asociovaneho s metodouEnumerator
http://stackoverflow.com/questions/2504494/are-there-something-like-python-generators-in-ruby
In [ ]:
def city_generator():
yield "Konstanz"
yield "Zurich"
yield "Schaffhausen"
yield "Stuttgart"
In [ ]:
gen = city_generator()
In [ ]:
next(gen)
In [ ]:
cities = ["Konstanz", "Zurich", "Schaffhausen", "Stuttgart"]
def city_generator():
for city in cities:
yield city
gen = city_generator()
In [ ]:
next(gen)
Tento genereator vlastne len supluje iterator, ktory je nad polom, ale ten cyklus moze robit aj nieco viac a vtedy to uz moze byt zaujimavejsie (ukazem neskor)
In [ ]:
def city_generator(local_cities):
for city in local_cities:
yield city
gen = city_generator(["Konstanz", "Zurich", "Schaffhausen", "Stuttgart"])
In [ ]:
next(gen)
In [ ]:
sequence = [1,2,3,4,5]
previous = 0
for actual in sequence:
print((actual + previous) / 2)
previous = actual
In [ ]:
sequence = [1,2,3,4,5]
def moving_average(sequence):
previous = 0
for actual in sequence:
print((actual + previous) * 0.5)
previous = actual
moving_average(sequence)
In [ ]:
sequence = [1,2,3,4,5]
def moving_average(sequence):
previous = 0
for actual in sequence:
yield (actual + previous) * 0.5
previous = actual
In [ ]:
print(list(moving_average(sequence)))
In [ ]:
def map(f, seq):
for x in seq:
print(f(x))
In [ ]:
def map(f, seq):
for x in seq:
yield f(x)
In [ ]:
def map(f, seq): # V pythone 2 map vracia list, implementacia by mohla byt napriklad takato
result = [] # mame premennu, ktoru postupne upravujeme a nafukujeme
for x in seq:
result.append(f(x))
return result
In [ ]:
def map(f, seq): # V pythone 3 map je generator a zabera konstantne mnozstvo pamati
for x in seq:
yield f(x)
In [ ]:
a, b = 1, 10
def squares(start, stop):
for i in range(start, stop):
yield i * i
generator = squares(a, b)
print(generator)
print(next(generator))
print(list(generator))
In [ ]:
generator = map(lambda i: i*i, range(a, b))
print(generator)
print(next(generator))
print(list(generator))
In [ ]:
generator = (i*i for i in range(a, b)) # rozdiel oproti kalsickemu LC je v zatvorkach [] => ()
print(generator)
print(next(generator))
print(list(generator))
In [ ]:
def generator(funkcia, iterator):
for i in iterator:
yield funkcia(i)
In [ ]:
def fun1(pole):
print('prva')
return False
def fun2(pole):
print('druha')
return True
if fun1(pole) or fun2(pole):
pass
In [ ]:
pom = (x*x for x in range(5))
next(pom) #prvok z generatora sa vyberie az ked ho je treba a nie pri vytvoreni generatora
In [ ]:
pom = [x*x for x in range(5)]
pom[4] # vyraz sa hned vyhodnocuje cely
Moderne kompilatory ale uz niektore veci vedia optimalizovat za programatora
In [ ]:
%%time
print(2+2)
In [ ]:
%%time
import time
def slow_square(x):
time.sleep(0.2)
return x**2
generator = map(slow_square, range(10))
print(generator)
In [ ]:
# co sa stane ak budeme chciet transformovat generator na zoznam. Teda spustit ru pomalu funkciu na kazdom prvku?
%%time
print(list(generator))
In [ ]:
# Aj ked chceme len cast pola, tak musime transformovat vsetky prvky
%%time
generator = map(slow_square, range(10))
pole = list(generator)
print(pole[:5])
In [ ]:
# Mozeme si ale skusit definovat funkciu, ktora nam vyberie len tu cast prvkov, ktore chceme
def head(iterator, n):
result = []
for _ in range(n):
result.append(next(iterator))
return result
In [ ]:
%%time
print(head(map(slow_square, range(10)), 5))
In [ ]:
%%time
# tuto funkciu sme si ale nemuseli definovat sami. Nieco take uz existuje
from itertools import islice
generator = map(slow_square, range(10000))
print(list(islice(generator, 5)))
In [ ]:
from operator import add
from functools import reduce
reduce(add, [x*x for x in range(10000000)])
reduce(add, (x*x for x in range(10000000))) # rozdiel je len v zatvorkach
In [ ]:
from functools import reduce
import gc
import os
import psutil
process = psutil.Process(os.getpid())
def print_memory_usage():
print(process.memory_info().rss)
counter = [0] # Toto je hnusny hack a slubujem, ze nabuduce si povieme ako to spravit lepsie. Spytajte sa ma na to!
# Problem je v tom, ze potrebujem pocitadlo, ktore bude dostupne vo funkcii ale zaroven ho potrebujem inicializovat mimo tejto funkcie
# Teraz som zaspinil funkciu pouzitim mutable datovej struktury a globalneho priestoru mien. 2xFuj!
def measure_add(a, result, counter=counter):
if counter[0] % 2000000 == 0:
print_memory_usage()
counter[0] = counter[0] + 1
return a + result
In [ ]:
gc.collect()
counter[0] = 0
print_memory_usage()
print(reduce(measure_add, [x*x for x in range(10000000)]))
In [ ]:
gc.collect()
counter[0] = 0
print_memory_usage()
print(reduce(measure_add, (x*x for x in range(10000000))))
In [ ]:
gc.collect()
counter[0] = 0
print_memory_usage()
print(reduce(measure_add, filter(lambda x: x%2 == 0, map(lambda x: x*x, range(10000000)))))
# a pokojne by som to mohol vnarat dalej
In [ ]:
def fibonacci():
"""Fibonacci numbers generator"""
a, b = 1, 1
while True:
yield a
a, b = b, a + b
f = fibonacci()
In [ ]:
print(list(islice(f, 10)))
In [ ]:
list(fibonacci()) # toto netreba pustat
Predstavte si, ze mate subor, do ktoreho nejaky proces zapisuje logy po riadkoch a vy ich spracovavate.
Ako by ste spravili iterovanie cez riadky suboru tak, aby ste cakali na dalsie riadky ak dojdete na koniec suboru?
inspirovane - http://stackoverflow.com/questions/6162002/whats-the-benefit-of-using-generator-in-this-case
In [ ]:
%%bash
echo -n 'log line' > log.txt
In [ ]:
import time
In [ ]:
# s generatorom napriklad takto
def read(file_name):
with open(file_name) as f:
while True:
line = f.readline()
if not line:
time.sleep(0.1)
continue
yield line
lines = read("log.txt")
print(next(lines))
In [ ]:
print(next(lines))
In [ ]:
for line in lines:
print(line)
In [ ]:
while True:
line = logfile.readline()
if not line:
time.sleep(0.1)
continue
print line
In [ ]:
class Node(object):
def __init__(self, title, children=None):
self.title = title
self.children = children or []
tree = Node(
'A', [
Node('B', [
Node('C', [
Node('D')
]),
Node('E'),
]),
Node('F'),
Node('G'),
])
In [ ]:
def node_recurse_generator(node):
yield node
for n in node.children:
for rn in node_recurse_generator(n):
yield rn
[node.title for node in node_recurse_generator(tree)]
http://stackoverflow.com/questions/26145678/implementing-a-depth-first-tree-iterator-in-python
In [ ]:
from collections import deque
def node_stack_generator(node):
stack = deque([node]) # tu si uchovavam stav prehladavania kedze nepouzivam call stack v rekurzii
while stack:
# Pop out the first element in the stack
node = stack.popleft()
yield node
# push children onto the front of the stack.
# Note that with a deque.extendleft, the first on in is the last
# one out, so we need to push them in reverse order.
stack.extendleft(reversed(node.children))
[node.title for node in node_stack_generator(tree)]
In [ ]:
def permutations(items):
n = len(items)
if n==0:
yield []
else:
for i in range(len(items)):
for cc in permutations(items[:i]+items[i+1:]):
yield [items[i]]+cc
In [ ]:
for p in permutations('red'):
print(''.join(p))
In [ ]:
for p in permutations("game"):
print(''.join(p) + ", ", end="")
In [ ]:
def fibonacci():
"""Fibonacci numbers generator"""
a, b = 1, 1
while True:
yield a
a, b = b, a + b
print(list(islice(fibonacci(), 5)))
In [ ]:
def firstn(g, n): # generator objekt je parametrom generator funkcie
for i in range(n):
yield next(g)
In [ ]:
list(firstn(fibonacci(), 10))