В: Почему лямбда и т. Д. Отталкиваются?
A: списочные выражения и выражения генератора обычно считаются хорошим сочетанием мощности и читабельности. Чистый стиль функционального программирования, в котором вы используете map()
, reduce()
и filter()
с функциями (часто lambda
функциями), считается не совсем понятным. Кроме того, в Python добавлены встроенные функции, которые прекрасно справляются со всеми основными видами использования reduce()
.
Предположим, вы хотите подвести итог списка. Вот два способа сделать это.
lst = range(10)
print reduce(lambda x, y: x + y, lst)
print sum(lst)
Зарегистрируйтесь, чтобы решить эту проблему как фанат sum()
, а не фанат reduce()
. Вот еще одна, похожая проблема:
lst = range(10)
print reduce(lambda x, y: bool(x or y), lst)
print any(lst)
Решение any()
не только легче понять, но и намного быстрее; он имеет оценку короткого замыкания, так что он прекратит оценку, как только найдет какое-либо истинное значение. reduce()
должен провернуть весь список. Эта разница в производительности была бы существенной, если бы список составлял миллион элементов, а первый элемент оценивался как истинный. Кстати, any()
был добавлен в Python 2.5; если у вас его нет, вот версия для старых версий Python:
def any(iterable):
for x in iterable:
if x:
return True
return False
Предположим, вы хотите составить список квадратов четных чисел из некоторого списка.
lst = range(10)
print map(lambda x: x**2, filter(lambda x: x % 2 == 0, lst))
print [x**2 for x in lst if x % 2 == 0]
Теперь предположим, что вы хотите сложить этот список квадратов.
lst = range(10)
print sum(map(lambda x: x**2, filter(lambda x: x % 2 == 0, lst)))
# list comprehension version of the above
print sum([x**2 for x in lst if x % 2 == 0])
# generator expression version; note the lack of '[' and ']'
print sum(x**2 for x in lst if x % 2 == 0)
Генераторное выражение на самом деле просто возвращает итеративный объект. sum()
берет итерируемое и извлекает из него значения, одно за другим, суммируя по ходу, пока все значения не будут использованы. Это самый эффективный способ решить эту проблему в Python. Напротив, решение map()
и эквивалентное решение с пониманием списка внутри вызова sum()
должны сначала создать список; этот список затем передается в sum()
, используется один раз и отбрасывается. Время на создание списка и последующее его удаление просто напрасно. (РЕДАКТИРОВАТЬ: и обратите внимание, что версия с map
и filter
должна создавать два списка, один из которых filter
, а другой - map
; из обоих списков отбрасываются.) (РЕДАКТИРОВАТЬ: Но в Python 3.0 и новее, map () и filter () теперь оба «ленивые» и создают итератор вместо списка, поэтому эта точка менее верна, чем раньше. в Python 2.x вы могли использовать itertools.imap () и itertools.ifilter () для отображения и фильтра на основе итераторов. Но я продолжаю предпочитать решения для выражений генератора перед любыми решениями для карт / фильтров.)
Сочетая map()
, filter()
и reduce()
в сочетании с lambda
функциями, вы можете делать много мощных вещей. Но у Python есть идиоматические способы решения одних и тех же проблем, которые одновременно лучше работают и легче читаются и понимаются.