9. Itertools a funkce vracející iterátory
Lambda výraz
Slouží k vytváření krátkých anonymních funkcí (funkce bez identifikátoru - názvu). Tělo funkce je syntakticky omezeno na jeden výraz a mohou být použity všude, kde je vyžadována funkce. Sémanticky se jedná o syntaktický cukr pro klasickou funkci.
1
2
3
4
5
6
7
8
9
10
11
def apply_operation(operation, a, b):
return operation(a, b)
def my_sum(a, b):
return a + b
assert apply_operation(my_sum, 2, 3) == 5
assert apply_operation(lambda a, b: a + b, 2, 3) == 5
1
2
3
4
5
6
7
8
# anonymní funkce pro součet dvou čísel
lambda a, b: a + b
# Out[1]: <function __main__.<lambda>(a, b)>
(lambda a, b: a + b)(1, 2)
# Out[2]: 3
Hezkým příkladem je použití v parametru key
u funkce sorted
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# seznam obsahující čísla
sorted([4, 2, 3, 1, 4])
# seznam obsahující n-tice
sorted([(1, "Lukáš Novák", 10),
(4, "Albert Billa", 1),
(0, "Pepa Los", 30)])
# Out[0]: [(0, 'Pepa Los', 30), (1, 'Lukáš Novák', 10), (4, 'Albert Billa', 1)]
# seřazeno dle posledního prvku
sorted([(1, "Lukáš Novák", 10),
(4, "Albert Billa", 1),
(0, "Pepa Los", 30)], key=lambda x: x[2])
# Out[1]: [(4, 'Albert Billa', 1), (1, 'Lukáš Novák', 10), (0, 'Pepa Los', 30)]
Funkce any
a all
Vrací True
v případě že je některý prvek/jsou všechny prvky iterable vyhodnoceny na pravdu. Pokud je iterable prázdná, vrací False
.
1
2
3
any([[], [1, 2, 3], [1]])
all([[], [1, 2, 3], [1]])
Funkce map
Vrací iterátor (pozor nikoli sekvenci), který aplikuje funkci na každý prvek předaného iterable. Tyto výsledky jsou pomoci yield
vráceny.
1
map(lambda x: x ** 2, [1, 2, 3, 4])
Funkce map
může přijímat libovolný počet iterable, v takovém případě však musí aplikovaná funkce přijímat stejný počet argumentů jako je počet iterable.
1
2
3
4
5
import operator
# operator.mul přijímá 2 argumenty
map(operator.mul, [1, 2, 3, 4], [2, 3, 4, 5])
Funkce filter
Vrací iterátor (pozor nikoli sekvenci) vytvořený z prvků iterable pro které se funkce vyhodnotí na pravdu. Pokud je funkce rovna None
jsou z iterable tímto způsobem odstraněny všechny prvky vyhodnocené na nepravdu.
1
2
3
filter(None, [[], [1, 2, 3], [1]])
filter(lambda x: x % 3, range(20))
Funkce filter(function, iterable)
je ekvivalentní generátorovému výrazu:
1
2
3
4
5
# pokud je function rovno None
(item for item in iterable if function(item))
# jinak
(item for item in iterable if item)
Modul itertools
Modul implementující sadu užitečných iterátorů. Tyto iterátory preferujeme nad vlastní implementací z důvodu rychlosti a paměťové úspornosti.
itertools.starmap
Vytvoří iterátor, který vyhodnocuje předanou funkci s argumenty získanými z iterable. Narozdíl od klasického map
přijímá jeden iterable, ten však může obsahovat n-tice (v případě funkce přijímající n
argumentů). Sémanticky podobné použítí *
při volání funkce.
1
2
3
4
5
6
import itertools
import operator
# operator.mul přijímá 2 argumenty
itertools.starmap(operator.mul, [[1, 2], [2, 3], [3, 4], [4, 5]])
itertools.filterfalse
Pracuje podobně jako filter
, výsledný iterátor však produkuje prvky pro které je funkce nepravda.
1
2
3
4
5
6
import itertools
itertools.filterfalse(None, [[], [1, 2, 3], [1]])
itertools.filterfalse(lambda x: x % 3, range(20))
Ostatní iterátory
Celkový výčet iterátorů dostupných v balíčku itertools
je dostupný zde.
List comprehension vs map
/filter
Funkci map
/filter
je vhodné nahrazovat list comprehension, můžeme dosáhnout vyššího výkonu. Jedná se však o konstantní overhead volání funkce.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import timeit
# 10
print(timeit.timeit("list(map(lambda x: x * x, range(10)))", number=10000))
# 0.016546586997719714
print(timeit.timeit("[x * x for x in range(10)]", number=10000))
# 0.008891337001841748
# 10000
print(timeit.timeit("list(map(lambda x: x * x, range(10000)))", number=10000))
# 7.573531197998818
print(timeit.timeit("[x * x for x in range(10000)]", number=10000))
# 5.103068967000581
# 100000
print(timeit.timeit("list(map(lambda x: x * x, range(100000)))", number=10000))
# 96.5402136729972
print(timeit.timeit("[x * x for x in range(100000)]", number=10000))
# 63.06499578600051
Úkoly
Nevíte si rady? Přečtěte si “Jak pracovat s Github Classroom?”.
Při řešení úloh nepoužívejte pokročilejší funkcionalitu jazyka která nebyla ještě představena! Takové úkoly budou vráceny na přepracování bez ohledu na jejich funkčnost.
Skupina Mikula
- L09E01: Matrix rows mask [Náhled], [Příjmout úkol]
- L09E02: Password generator [Náhled], [Příjmout úkol]
Skupina Petržela
- L09E01: Matrix rows even numbers [Náhled], [Příjmout úkol]
- L09E02: Password generator [Náhled], [Příjmout úkol]