6. Элементы функционального программирования. Списковые выражения.
Элементы функционального программирования
Лябмда-функции
- Функции без имени - анонимные функции.
- В Python ограничены одним выражением и предназначены для использования в простых сценариях.
- Общее правило: если нужно что-то сложнее простого понятного выражения в лямбда-функции - сделать обычную именованную функцию.
- Возвращаемое значение - результат единственного выражения в теле.
- Ключевое слово return не нужно.
print (lambda: 3)() print (lambda line, number: {line: number})("counter", 100500)
3 {'counter': 100500}
Замыкания
- Вложенные функции могут захватывать контекст внешних функций.
- Переменные из внешнего контекста read-only.
- Можно обойти в Python 2.x с помощью костыля - созданием контейнера.
- Но лучше избегать подобного использования.
- При попытке записи - проблема, т.к. не удаётся записать значение.
# closure example def make_adder(initial): return lambda elem: initial + elem adder = make_adder(100500) print [adder(val) for val in xrange(10)]
[100500, 100501, 100502, 100503, 100504, 100505, 100506, 100507, 100508, 100509]
Некоторые функции высшего порядка
- map() - преобразовать коллекцию 1 к 1 функцией (количество аргументов - количество переданных коллекций).
- reduce() - свёртка коллекции бинарной функцией.
- filter() - фильтрация коллекции с помощью унарной функции-предиката.
- Сейчас в большинстве случаев вместо этих функций принято использовать list comprehensions.
Код
# map elems = range(1, 10) print elems print map(lambda value: 2 ** value, elems)
[1, 2, 3, 4, 5, 6, 7, 8, 9] [2, 4, 8, 16, 32, 64, 128, 256, 512]
# reduce elems = range(1, 10) print elems print reduce(lambda first, second: first + second, elems, -5)
[1, 2, 3, 4, 5, 6, 7, 8, 9] 40
accum [1, 2, 3, 4, 5, 6, 7, 8, 9] accum = f(accum, 1) accum = f(accum, 2) a = f(accum, 3) accum = -5 for elem in elems: accum = accum + elem
# filter elems = range(1, 10) print elems print filter(lambda value: value % 2 == 0, elems)
[1, 2, 3, 4, 5, 6, 7, 8, 9] [2, 4, 6, 8]
List comprehensions
- Списковые включения (выражения) - pythonic способ построения списков с помощью выражений особого вида.
- Осторожнее с читабельностью: иногда вместо сложного выражения лучше просто написать два обычных цикла
Код
print [elem for elem in xrange(10)] print [elem for elem in xrange(10) if elem % 2 == 0]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 2, 4, 6, 8]
# may be too complex print [(elem, inner_elem) for elem in xrange(4) for inner_elem in xrange(100, 104) if elem % 2 != 0]
[(1, 100), (1, 101), (1, 102), (1, 103), (3, 100), (3, 101), (3, 102), (3, 103)]
# may be more readable version without list comprehension in such case elems = [] for elem in xrange(4): for inner_elem in xrange(100, 104): if elem % 2 != 0: elems.append((elem, inner_elem)) print elems
[(1, 100), (1, 101), (1, 102), (1, 103), (3, 100), (3, 101), (3, 102), (3, 103)]
# nested list comprehensions print [[(row, col) for col in xrange(3)] for row in xrange(4)]
[[(0, 0), (0, 1), (0, 2)], [(1, 0), (1, 1), (1, 2)], [(2, 0), (2, 1), (2, 2)], [(3, 0), (3, 1), (3, 2)]]
# list comprehensions and dict counters = {"a": 1, "c": 2, "f": 100500, "z": 3} print counters print [(key, value) for key, value in counters.iteritems()]
{'a': 1, 'c': 2, 'z': 3, 'f': 100500} [('a', 1), ('c', 2), ('z', 3), ('f', 100500)]