11.6. Function Generator-Like¶
It is not a generator
Generator-like objects
range(start, stop, step)
reversed(iterable)
enumerate(iterable, start=0)
zip(*iterable, strict=False)
map(func, iterable)
filter(func, iterable)
next(iterable)
iter(iterable)
11.6.1. Range¶
range([start], <stop>, [step])
optional
start
, inclusive, default:0
required
stop
, exclusiveoptional
step
, default:1
range()
syntax:
>>> 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]
11.6.2. Reversed¶
reversed()
- Return a reverse iterator over the values of the given sequence
>>> data = (1, 2, 3)
>>> list(reversed(data))
[3, 2, 1]
11.6.3. Enumerate¶
enumerate(*iterables)
>>> 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'}
11.6.4. Zip¶
zip(*iterables)
>>> firstnames = ['Mark', 'Melissa', 'Rick']
>>> lastnames = ['Watney', 'Lewis', 'Martinez']
>>>
>>> list(zip(firstnames, lastnames))
[('Mark', 'Watney'), ('Melissa', 'Lewis'), ('Rick', 'Martinez')]
>>> firstnames = ['Mark', 'Melissa', 'Rick']
>>> lastnames = ['Watney', 'Lewis', 'Martinez']
>>>
>>> dict(zip(firstnames, lastnames))
{'Mark': 'Watney', 'Melissa': 'Lewis', 'Rick': 'Martinez'}
>>> roles = ['botanist', 'commander', 'pilot']
>>> names = ['Mark Watney', 'Melissa Lewis', 'Rick Martinez']
>>>
>>> dict(zip(roles, names))
{'botanist': 'Mark Watney',
'commander': 'Melissa Lewis',
'pilot': 'Rick Martinez'}
zip()
adjusts to the shortest:
>>> firstnames = ['Mark', 'Melissa']
>>> lastnames = ['Watney', 'Lewis', 'Martinez']
>>>
>>> list(zip(firstnames, lastnames))
[('Mark', 'Watney'), ('Melissa', 'Lewis')]
Three-way:
>>> roles = ['botanist', 'commander', 'pilot']
>>> firstnames = ['Mark', 'Melissa', 'Rick']
>>> lastnames = ['Watney', 'Lewis', 'Martinez']
>>>
>>> result = zip(roles, firstnames, lastnames)
>>>
>>>
>>> next(result)
('botanist', 'Mark', 'Watney')
>>>
>>> next(result)
('commander', 'Melissa', 'Lewis')
>>>
>>> next(result)
('pilot', 'Rick', 'Martinez')
>>>
>>> next(result)
Traceback (most recent call last):
StopIteration
11.6.5. Map¶
Apply function to all elements of data
map(callable, *iterables)
>>> def square(x):
... return x ** 2
>>> data = [1, 2, 3]
>>> result = map(square, data)
>>> list(result)
[1, 4, 9]
11.6.6. Filter¶
filter(callable, *iterables)
>>> def even(x):
... return x % 2 == 0
>>> data = [0, 1, 2, 3, 4]
>>> result = filter(even, data)
>>> list (result)
[0, 2, 4]
11.6.7. Next¶
Range:
>>> result = range(0,5)
>>>
>>> next(result)
Traceback (most recent call last):
TypeError: 'range' object is not an iterator
Zip two-way:
>>> firstnames = ['Mark', 'Melissa', 'Rick']
>>> lastnames = ['Watney', 'Lewis', 'Martinez']
>>>
>>> result = zip(firstnames, lastnames)
>>>
>>>
>>> next(result)
('Mark', 'Watney')
>>>
>>> next(result)
('Melissa', 'Lewis')
>>>
>>> next(result)
('Rick', 'Martinez')
>>>
>>> next(result)
Traceback (most recent call last):
StopIteration
Enumerate:
>>> 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
Zip n-way:
>>> roles = ['botanist', 'commander', 'pilot']
>>> firstnames = ['Mark', 'Melissa', 'Rick']
>>> lastnames = ['Watney', 'Lewis', 'Martinez']
>>>
>>> result = zip(roles, firstnames, lastnames)
>>>
>>>
>>> next(result)
('botanist', 'Mark', 'Watney')
>>>
>>> next(result)
('commander', 'Melissa', 'Lewis')
>>>
>>> next(result)
('pilot', 'Rick', 'Martinez')
>>>
>>> next(result)
Traceback (most recent call last):
StopIteration
Map:
>>> def square(x):
... return x ** 2
>>>
>>> data = [1, 2, 3]
>>> result = map(square, data)
>>>
>>>
>>> next(result)
1
>>>
>>> next(result)
4
>>>
>>> next(result)
9
>>> next(result)
Traceback (most recent call last):
StopIteration
Filter:
>>> def even(x):
... return x % 2 == 0
>>>
>>> data = [0, 1, 2, 3, 4]
>>> result = filter(even, data)
>>>
>>>
>>> next(result)
0
>>>
>>> next(result)
2
>>>
>>> next(result)
4
>>> next(result)
Traceback (most recent call last):
StopIteration
11.6.8. Iter¶
Range:
>>> for i in range(0,3):
... print(i)
0
1
2
Enumerate:
>>> months = ['January', 'February', 'March']
>>>
>>> for i, month in enumerate(months, start=1):
... print(f'{i=}, {month=}')
i=1, month='January'
i=2, month='February'
i=3, month='March'
Zip:
>>> roles = ['botanist', 'commander', 'pilot']
>>> names = ['Mark Watney', 'Melissa Lewis', 'Rick Martinez']
>>>
>>> for role, name in zip(roles, names):
... print(f'{role=}, {name=}')
role='botanist', name='Mark Watney'
role='commander', name='Melissa Lewis'
role='pilot', name='Rick Martinez'
11.6.9. Generator Chain¶
Function composition
>>> def square(x):
... return x ** 2
>>>
>>> def even(x):
... return x % 2 == 0
>>>
>>>
>>> result = range(0,10)
>>> result = map(square, result)
>>> result = filter(even, result)
>>>
>>> for value in result:
... print(value)
... if value > 3:
... break
0
4
>>>
>>> next(result)
16
>>>
>>> list(result)
[36, 64]
11.6.10. 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)
11.6.11. Use Case - 0x01¶
>>> def increment(x):
... return x + 1
>>>
>>>
>>> data = [1, 2, 3, 4]
>>> result = map(increment, data)
>>>
>>> list(result)
[2, 3, 4, 5]
11.6.12. Use Case - 0x02¶
>>> def square(x):
... return x ** 2
>>>
>>>
>>> data = [1, 2, 3]
>>> result = map(square, data)
>>>
>>> list(result)
[1, 4, 9]
11.6.13. Use Case - 0x03¶
>>> 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'
11.6.14. Use Case - 0x04¶
>>> people = [
... {'age': 21, 'name': 'Mark Watney'},
... {'age': 25, 'name': 'Melissa Lewis'},
... {'age': 18, 'name': 'Rick Martinez'}]
>>>
>>>
>>> def adult(person):
... return person['age'] >= 21
>>>
>>>
>>> result = filter(adult, people)
>>>
>>> list(result)
[{'age': 21, 'name': 'Mark Watney'},
{'age': 25, 'name': 'Melissa Lewis'}]
11.6.15. Use Case - 0x05¶
>>> people = [
... {'is_astronaut': False, 'name': 'Mark Watney'},
... {'is_astronaut': True, 'name': 'Melissa Lewis'},
... {'is_astronaut': True, 'name': 'Rick Martinez'}]
>>>
>>>
>>> def astronaut(person):
... return person['is_astronaut']
>>>
>>>
>>> result = filter(astronaut, people)
>>>
>>> list(result)
[{'is_astronaut': True, 'name': 'Melissa Lewis'},
{'is_astronaut': True, 'name': 'Rick Martinez'}]
11.6.16. Use Case - 0x06¶
Sum stdin (standard input):
>>> import sys
>>>
>>>
... print(sum(map(int, sys.stdin)))
$ cat ~/.profile |grep addnum
alias addnum='python -c"import sys; print(sum(map(int, sys.stdin)))"'
11.6.17. Assignments¶
"""
* Assignment: Function Generator Map
* Required: yes
* Complexity: easy
* Lines of code: 3 lines
* Time: 3 min
English:
1. Define function `cube()`:
a. takes one argument
b. returns its argument cubed (raised to the power of 3)
2. Use `map()` to apply function `cube()` to DATA
3. Define `result: list[int]` with evaluated result
4. Run doctests - all must succeed
Polish:
1. Zdefiniuj funckję `cube()`:
a. przyjmuje jeden argument
b. zwraca argument podniesiony do sześcianu (do 3 potęgi)
2. Użyj `map()` zaaplikować funkcję `cube()` do DATA
3. Zdefiniuj `result: list[int]` z ewaluaownym wynikiem
4. Uruchom doctesty - wszystkie muszą się powieść
Hints:
* map()
* list()
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import isfunction
>>> assert isfunction(cube), \
'Object `cube` must be a function'
>>> assert result is not Ellipsis, \
'Assign result to variable: `result`'
>>> assert type(result) is list, \
'Variable `result` has invalid type, should be list'
>>> assert all(type(x) is int for x in result), \
'All rows in `result` should be int'
>>> result
[0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
"""
DATA = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Returns its argument cubed (raised to the power of 3)
# type: Callable[[int], int]
def cube():
...
# Cube numbers in DATA
# type: list[float]
result = ...
"""
* Assignment: Function Generator Filter
* Required: yes
* Complexity: easy
* Lines of code: 3 lines
* Time: 3 min
English:
1. Define function `odd()`:
a. takes one argument
b. returns True if argument is odd
c. returns False if argument is even
2. Use `filter()` to apply function `odd()` to DATA
3. Define `result: list[int]` with evaluated result
4. Run doctests - all must succeed
Polish:
1. Zdefiniuj funckję `odd()`:
a. przyjmuje jeden argument
b. zwraca True jeżeli argument jest nieparzysty
c. zwraca False jeżeli argument jest parzysty
2. Użyj `filter()` zaaplikować funkcję `odd()` do DATA
3. Zdefiniuj `result: list[int]` z ewaluaownym wynikiem
4. Uruchom doctesty - wszystkie muszą się powieść
Hints:
* filter()
* list()
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import isfunction
>>> assert isfunction(odd), \
'Object `odd` must be a function'
>>> assert result is not Ellipsis, \
'Assign result to variable: `result`'
>>> assert type(result) is list, \
'Variable `result` has invalid type, should be list'
>>> assert all(type(x) is int for x in result), \
'All rows in `result` should be int'
>>> result
[1, 3, 5, 7, 9]
"""
DATA = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Returns its argument cubed (raised to the power of 3)
# type: Callable[[int], int]
def odd():
...
# Cube numbers in DATA
# type: list[float]
result = ...
"""
* Assignment: Function Generator Chain
* Required: yes
* Complexity: easy
* Lines of code: 4 lines
* Time: 3 min
English:
1. Use `range()` to get numbers:
a. from 0 (inclusive)
b. to 10 (exclusive)
2. Redefine `result` with odd numbers from `result`
3. Redefine `result` with cubed numbers from `result`
4. Redefine `result` with evaluated `result`
5. Run doctests - all must succeed
Polish:
1. Użyj `range()` aby otrzymać liczby:
a. od 0 (włącznie)
b. do 10 (rozłącznie)
2. Przedefiniuj `result` z nieparzystymi liczbami z `result`
3. Przedefiniuj `result` z podniesionymi do sześcianiu liczbami z `result`
4. Przedefiniuj `result` z ewaluaownym `result`
5. Uruchom doctesty - wszystkie muszą się powieść
Hints:
* range()
* map()
* filter()
* list()
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import isfunction
>>> assert isfunction(odd), \
'Object `odd` must be a function'
>>> assert isfunction(cube), \
'Object `cube` must be a function'
>>> assert result is not Ellipsis, \
'Assign result to variable: `result`'
>>> assert type(result) is list, \
'Variable `result` has invalid type, should be list'
>>> assert all(type(x) is int for x in result), \
'All rows in `result` should be int'
>>> result
[1, 27, 125, 343, 729]
"""
def odd(x):
return x % 2
def cube(x):
return x ** 3
# Range from 0 to 10 (exclusive)
# type: Iterator[int]
result = ...
# Filter odd numbers
# type: Iterator[int]
result = ...
# Cube result
# type: Iterator[int]
result = ...
# Get list of results
# type: list[int]
result = ...
"""
* Assignment: Function Generator Chain
* Required: yes
* Complexity: easy
* Lines of code: 2 lines
* Time: 3 min
English:
1. Define `result: float` with arithmetic mean of `DATA`
2. Note, that all the time you are working on a data stream
3. Run doctests - all must succeed
Polish:
1. Zdefiniuj `result: float` ze średnią arytmetyczną z `DATA`
2. Zwróć uwagę, że cały czas pracujesz na strumieniu danych
3. Uruchom doctesty - wszystkie muszą się powieść
Hints:
* type cast to `list()` to expand generator before calculating mean
* `mean = sum(...) / len(...)`
* TypeError: object of type 'map' has no len()
* ZeroDivisionError: division by zero
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import isfunction
>>> assert isfunction(odd), \
'Object `odd` must be a function'
>>> assert isfunction(cube), \
'Object `cube` must be a function'
>>> assert result is not Ellipsis, \
'Assign result to variable: `result`'
>>> assert type(result) is float, \
'Variable `result` has invalid type, should be float'
>>> result
245.0
"""
def odd(x):
return x % 2
def cube(x):
return x ** 3
DATA = range(0, 10)
DATA = filter(odd, DATA)
DATA = map(cube, DATA)
# Calculate mean of DATA
# type: float
result = ...