9.8. Function Generators¶
9.8.1. Range¶
It is not a generator
optional
start
, inclusive, default:0
required
stop
, exclusive,optional
step
, default:1
range()
syntax:
range([start], <stop>, [step])
>>> range(0,3)
range(0, 3)
>>> list(range(0,3))
[0, 1, 2]
>>> tuple(range(0,3))
(0, 1, 2)
>>> set(range(0,3))
{0, 1, 2}
>>> list(range(4,11,2))
[4, 6, 8, 10]
9.8.2. Enumerate¶
enumerate(*iterables)
>>> months = ['January', 'February', 'March']
>>> result = enumerate(months)
>>>
>>> next(result)
(0, 'January')
>>> next(result)
(1, 'February')
>>> next(result)
(2, 'March')
>>> next(result)
Traceback (most recent call last):
StopIteration
>>> months = ['January', 'February', 'March']
>>> result = enumerate(months)
>>>
>>> list(result)
[(0, 'January'), (1, 'February'), (2, 'March')]
>>> months = ['January', 'February', 'March']
>>> result = enumerate(months)
>>>
>>> dict(result)
{0: 'January', 1: 'February', 2: 'March'}
>>> months = ['January', 'February', 'March']
>>> result = enumerate(months, start=1)
>>>
>>> dict(result)
{1: 'January', 2: 'February', 3: 'March'}
>>> months = ['January', 'February', 'March']
>>> result = {f'{i:02}':month for i,month in enumerate(months, start=1)}
>>>
>>> print(result)
{'01': 'January', '02': 'February', '03': 'March'}
>>> months = ['January', 'February', 'March']
>>>
>>> for i, month in enumerate(months, start=1):
... print(f'{i} -> {month}')
1 -> January
2 -> February
3 -> March
9.8.3. Zip¶
zip(*iterables)
>>> firstnames = ['Mark', 'Melissa', 'Alex']
>>> lastnames = ['Watney', 'Lewis', 'Vogel']
>>> result = zip(firstnames, lastnames)
>>>
>>> next(result)
('Mark', 'Watney')
>>> next(result)
('Melissa', 'Lewis')
>>> next(result)
('Alex', 'Vogel')
>>> next(result)
Traceback (most recent call last):
StopIteration
>>> firstnames = ['Mark', 'Melissa', 'Alex']
>>> lastnames = ['Watney', 'Lewis', 'Vogel']
>>> result = zip(firstnames, lastnames)
>>>
>>> list(result)
[('Mark', 'Watney'), ('Melissa', 'Lewis'), ('Alex', 'Vogel')]
>>> firstnames = ['Mark', 'Melissa', 'Alex']
>>> lastnames = ['Watney', 'Lewis', 'Vogel']
>>> result = zip(firstnames, lastnames)
>>>
>>> dict(result)
{'Mark': 'Watney', 'Melissa': 'Lewis', 'Alex': 'Vogel'}
>>> roles = ['botanist', 'commander', 'chemist']
>>> names = ['Mark Watney', 'Melissa Lewis', 'Alex Vogel']
>>> dict(zip(roles, names)) # doctest: +NORMALIZE_WHITESPACE
{'botanist': 'Mark Watney',
'commander': 'Melissa Lewis',
'chemist': 'Alex Vogel'}
zip()
adjusts to the shortest:
>>> firstnames = ['Mark', 'Melissa']
>>> lastnames = ['Watney', 'Lewis', 'Vogel']
>>> result = zip(firstnames, lastnames)
>>>
>>> list(result)
[('Mark', 'Watney'), ('Melissa', 'Lewis')]
>>> roles = ['botanist', 'commander', 'chemist']
>>> firstnames = ['Mark', 'Melissa', 'Alex']
>>> lastnames = ['Watney', 'Lewis', 'Vogel']
>>> result = zip(roles, firstnames, lastnames)
>>>
>>> next(result)
('botanist', 'Mark', 'Watney')
>>> next(result)
('commander', 'Melissa', 'Lewis')
>>> next(result)
('chemist', 'Alex', 'Vogel')
>>> next(result)
Traceback (most recent call last):
StopIteration
>>> roles = ['botanist', 'commander', 'chemist']
>>> names = ['Mark Watney', 'Melissa Lewis', 'Alex Vogel']
>>>
>>> for role, name in zip(roles, names):
... print(f'{role} -> {name}')
botanist -> Mark Watney
commander -> Melissa Lewis
chemist -> Alex Vogel
9.8.4. Map¶
map(callable, *iterables)
>>> data = [1, 2, 3]
>>> result = map(float, data)
>>>
>>> next(result)
1.0
>>> next(result)
2.0
>>> next(result)
3.0
>>> next(result)
Traceback (most recent call last):
StopIteration
>>> data = [1, 2, 3]
>>> result = map(float, data)
>>>
>>> list(result)
[1.0, 2.0, 3.0]
>>> data = [1, 2, 3]
>>> result = map(float, data)
>>>
>>> tuple(map(float, data))
(1.0, 2.0, 3.0)
>>> data = [1, 2, 3]
>>> result = map(float, data)
>>>
>>> set(map(float, data))
{1.0, 2.0, 3.0}
>>> DATA = [1, 2, 3]
>>>
>>> result = (float(x) for x in DATA)
>>> list(result)
[1.0, 2.0, 3.0]
>>> DATA = [1.1, 2.2, 3.3]
>>> result = map(round, DATA)
>>> list(result)
[1, 2, 3]
>>> def square(x):
... return x ** 2
...
>>> data = [1, 2, 3]
>>> result = map(square, data)
>>>
>>> list(result)
[1, 4, 9]
9.8.5. Filter¶
filter(callable, *iterables)
>>> def even(x):
... return x % 2 == 0
>>>
>>>
>>> data = [1, 2, 3, 4, 5, 6]
>>> result = filter(even, data)
>>>
>>> next(result)
2
>>> next(result)
4
>>> next(result)
6
>>> next(result)
Traceback (most recent call last):
StopIteration
>>> def even(x):
... return x % 2 == 0
>>>
>>>
>>> data = [1, 2, 3, 4, 5, 6]
>>> result = filter(even, data)
>>>
>>> list(result)
[2, 4, 6]
9.8.6. Functools¶
functools.reduce(callable, iterable[, initializer])
>>> 1 + 2
3
>>> 1 + 2 + 3 + 4
10
>>> from functools import reduce
>>>
>>>
>>> def add(x, y):
... return x + y
>>>
>>>
>>> reduce(add, [1, 2])
3
>>> reduce(add, [1, 2, 3, 4])
10
9.8.7. Itertools¶
Learn more at https://docs.python.org/3/library/itertools.html
More information in Itertools
itertools.count(start=0, step=1)
itertools.cycle(iterable)
itertools.repeat(object[, times])
itertools.accumulate(iterable[, func, *, initial=None])
itertools.chain(*iterables)
itertools.compress(data, selectors)
itertools.islice(iterable, start, stop[, step])
itertools.starmap(function, iterable)
itertools.product(*iterables, repeat=1)
itertools.permutations(iterable, r=None)
itertools.combinations(iterable, r)
itertools.combinations_with_replacement(iterable, r)
itertools.groupby(iterable, key=None)
9.8.8. Use Cases¶
>>> def increment(x):
... return x + 1
>>>
>>>
>>> data = [1, 2, 3, 4]
>>> result = map(increment, data)
>>>
>>> list(result)
[2, 3, 4, 5]
>>> PL = {'ą': 'a', 'ć': 'c', 'ę': 'e',
... 'ł': 'l', 'ń': 'n', 'ó': 'o',
... 'ś': 's', 'ż': 'z', 'ź': 'z'}
>>>
>>> def translate(letter):
... return PL.get(letter, letter)
>>>
>>>
>>> text = 'zażółć gęślą jaźń'
>>> result = map(translate, text)
>>> ''.join(result)
'zazolc gesla jazn'
>>> people = [
... {'age': 21, 'name': 'Jan Twardowski'},
... {'age': 25, 'name': 'Mark Watney'},
... {'age': 18, 'name': 'Melissa Lewis'}]
>>>
>>>
>>> def adult(person):
... return person['age'] >= 21
>>>
>>>
>>> result = filter(adult, people)
>>> list(result) # doctest: +NORMALIZE_WHITESPACE
[{'age': 21, 'name': 'Jan Twardowski'},
{'age': 25, 'name': 'Mark Watney'}]
>>> people = [
... {'is_astronaut': False, 'name': 'Jan Twardowski'},
... {'is_astronaut': True, 'name': 'Mark Watney'},
... {'is_astronaut': True, 'name': 'Melissa Lewis'}]
>>>
>>>
>>> def astronaut(person):
... return person['is_astronaut']
>>>
>>>
>>> result = filter(astronaut, people)
>>> list(result) # doctest: +NORMALIZE_WHITESPACE
[{'is_astronaut': True, 'name': 'Mark Watney'},
{'is_astronaut': True, 'name': 'Melissa Lewis'}]
>>> astronauts = ['Mark Watney', 'Melissa Lewis']
>>>
>>> people = ['Jan Twardowski', 'Mark Watney',
... 'Melissa Lewis', 'Jimenez']
>>>
>>>
>>> def is_astronaut(person):
... return person in astronauts
>>>
>>>
>>> result = filter(is_astronaut, people)
>>> list(result)
['Mark Watney', 'Melissa Lewis']
>>> import sys
>>>
>>> # doctest: +SKIP
... print(sum(map(int, sys.stdin)))
$ cat ~/.profile |grep addnum
alias addnum='python -c"import sys; print(sum(map(int, sys.stdin)))"'
9.8.9. Assignments¶
"""
* Assignment: Function Generator Chain
* Complexity: easy
* Lines of code: 9 lines
* Time: 13 min
English:
1. Use generator expression to create `numbers`
2. In generator use `range()` to get numbers from 1 to 33 (inclusive) divisible by 3
3. Use `filter()` to get odd numbers from `numbers`
4. Use `map()` to cube all numbers in `numbers`
5. Create `result: float` with arithmetic mean of `numbers`
6. Do not use `lambda` expressions
7. Compare result with "Tests" section (see below)
Polish:
1. Użyj wyrażenia generatorowego do stworzenia `numbers`
2. W generatorze użyj `range()` aby otrzymać liczby od 1 do 33 (włącznie) podzielne przez 3
3. Użyj `filter()` aby otrzymać liczby nieparzyste z `numbers`
4. Użyj `map()` aby podnieść wszystkie liczby w `numbers` do sześcianu
5. Stwórz `result: float` ze średnią arytmetyczną z `numbers`
6. Nie używaj wyrażeń lambda
7. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Hints:
* type cast to `list()` before calculating mean to expand generator
* `mean = sum(...) / len(...)`
* TypeError: object of type 'map' has no len()
* ZeroDivisionError: division by zero
Tests:
>>> from inspect import isfunction
>>> isfunction(odd)
True
>>> isfunction(cube)
True
>>> type(result) is float
True
>>> result
11502.0
"""