В чем проблема с сокращением ()?

Кажется, в сети идет много жарких дискуссий об изменениях в функции reduce() в python 3.0 и о том, как ее следует удалить. Мне немного трудно понять, почему это так; Я считаю вполне разумным использовать его в самых разных случаях. Если бы презрение было просто субъективным, я не могу себе представить, чтобы такое большое количество людей заботилось об этом.

Что мне не хватает? В чем проблема с сокращением ()?


person jeremy    schedule 08.10.2008    source источник


Ответы (5)


Как говорит Гвидо в своем посте о судьбе reduce() в Python 3000 :

Итак, теперь уменьшите(). На самом деле это то, что я всегда ненавидел больше всего, потому что, за исключением нескольких примеров с + или *, почти каждый раз, когда я вижу вызов функции reduce() с нетривиальным аргументом функции, мне нужно взять ручку и бумагу, чтобы покажите, что на самом деле передается в эту функцию, прежде чем я пойму, что должен делать метод reduce(). Так что, на мой взгляд, применимость reduce() в значительной степени ограничена ассоциативными операторами, а во всех остальных случаях цикл накопления лучше записывать явно.

В статье Functional Programming HOWTO есть отличный пример запутанного reduce:

Быстро, что делает следующий код?

total = reduce(lambda a, b: (0, a[1] + b[1]), items)[1]

Вы можете понять это, но требуется время, чтобы распутать выражение, чтобы понять, что происходит. Использование коротких вложенных операторов def делает ситуацию немного лучше:

def combine (a, b):
    return 0, a[1] + b[1]

total = reduce(combine, items)[1]

Но было бы лучше всего, если бы я просто использовал цикл for:

total = 0
for a, b in items:
    total += b

Или встроенная функция sum() и выражение генератора:

total = sum(b for a,b in items)

Многие варианты использования функции reduce() становятся более понятными, если они написаны как циклы for.

person DzinX    schedule 08.10.2008
comment
В этом случае это может быть еще проще: сумма (b для a, b в пунктах) - person John Millikin; 08.10.2008
comment
Ах, пугающе - теперь, когда я смотрю по ссылке, строка sum() - это непосредственно ваша цитата. Должно быть, просто пропустил это в первый раз. - person John Millikin; 08.10.2008
comment
@Джон Милликин: Ты прав! Я тоже пропустил :) Сейчас добавил, спасибо! - person DzinX; 08.10.2008
comment
Код сокращения не эквивалентен циклу for. Вот эквивалент: total = reduce(lambda total, (a,b): total + b, items, 0) - person Nathan Shively-Sanders; 08.10.2008
comment
@Nathan Sanders: Если вас волнует только результат, они одинаковы. Если вам небезразлична базовая реализация, ваше сокращение по-прежнему отличается от цикла for, так как оно использует еще одну переменную (total). - person DzinX; 08.10.2008
comment
Функция сокращения может запутать цель кода. Следовательно, сокращение должно быть удалено из языка. Конечно, я не знаю, говорит ли кто-нибудь именно это, но это неверно. - person Tony; 15.04.2014
comment
Ясно, но, честно говоря, бросить лямбду в ваш пример равносильно передаче окровавленной рубашки одному парню в полицейской очереди. Я не буду спорить, что поначалу метод reduce() не сбивает с толку, но в functools все происходит с самого начала. Я нахожу functools все более и более полезными по мере того, как учусь их использовать. Теперь, если вам нужны примеры запутанности, посмотрите на itertools(). Я тоже учусь любить их, но первое свидание было тяжелым. :-) - person JS.; 26.04.2014
comment
@DzinX: цикл for использует общую переменную внутри цикла, поэтому справедливо сказать, что она эквивалентна, но в любом случае пример сбивает с толку тех, кто не знает, сокращение, потому что в функции сокращения это похоже на вы добавляете a и b вместе в цикле for, кажется, что вы добавляете b к total и ничего не делаете с a, если бы это можно было сделать так, как сказал Натан-Сандерс или что-то близкое к этому тогда не было бы путаницы. - person freeforall tousez; 20.02.2015
comment
Аргумент: «Давайте переместим reduce», потому что его можно использовать для написания непонятного кода. Что ж, **, + и - тоже. Должны ли мы переместить их в functools ? - person Eric Duminil; 23.04.2017
comment
Отлично. Я не ценю, когда кто-то диктует, что я считаю полезным. Так что я исправлю свой собственный, если он будет удален. - person ; 09.08.2017
comment
Это даже не хороший пример запутанной лямбды; код явно написан, чтобы плохо выглядеть! Должно быть sum(values), может быть reduce(operator.add, values), а values может быть map(operator.itemgetter(1), items). Примечательно отсутствие аргумента о самом reduce. - person Yann Vernier; 28.02.2018
comment
Этот код сокращения выглядит как преднамеренная запутанность. Предполагая, что items представляет собой последовательность пар (кортежей длины 2), лучше записать ее так: reduce(lambda a, b: a[1] + b[1], items). Просто добавьте вторые элементы. - person W. Zhu; 02.10.2020

reduce() не удаляется — он просто перемещается в модуль functools. Гвидо рассуждает так: за исключением тривиальных случаев, таких как суммирование, код, написанный с использованием reduce(), обычно более понятен, если написан как цикл накопления.

person John Millikin    schedule 08.10.2008
comment
Гы, ужасные рассуждения :( - person TraumaPony; 08.10.2008
comment
Это? Большая часть философии Python заключается в написании ясного и очевидного кода. Типичный вызов функции reduce() обычно требует, чтобы я взял карандаш и нарисовал график того, с чем вызывается функция. - person John Millikin; 08.10.2008
comment
Если вы не можете показать мне значительное увеличение производительности (по крайней мере, в 2 раза), я в любой день возьму ясность и очевидность за компактность выражения. - person Kevin Little; 08.10.2008

Люди беспокоятся, что это поощряет запутанный стиль программирования, делая то, что можно сделать с помощью более четких методов.

Я не против уменьшить себя, я также иногда нахожу это полезным инструментом.

person Eli Bendersky    schedule 08.10.2008

Основная причина существования редукции заключается в том, чтобы избежать написания явных циклов for с аккумуляторами. Несмотря на то, что в Python есть некоторые возможности для поддержки функционального стиля, это не поощряется. Если вам нравится «настоящий», а не «питоновский» функциональный стиль — используйте вместо этого современный Lisp (Clojure?) или Haskell.

person Terminus    schedule 16.05.2017
comment
Это все равно, что говорить американцам китайского происхождения возвращаться в Китай, если им не нравится, как с ними обращаются здесь, в США. Мы все здесь, чтобы сделать широко используемый язык лучше. Не нужно просить людей использовать другой язык. В большинстве случаев они не могут из-за таких ограничений, как доступность пакетов. - person episodeyang; 14.05.2021

Использование сокращения для вычисления значения многочлена методом Хорнера является одновременно компактным и выразительным.

Вычислите значение полинома в x. a представляет собой массив коэффициентов для многочлена

def poynomialValue(a,x):
   return reduce(lambda value, coef: value*x + coef, a)
person user1153980    schedule 08.12.2020
comment
На самом деле это не попытка ответить на вопрос ОП. Почему reduce проблема? Ответ: Вот пример использования reduce. - person ShadowRanger; 08.12.2020
comment
Это не дает ответа на вопрос. Чтобы подвергнуть критике или запросить разъяснения у автора, оставьте комментарий под его публикацией. – Из обзора - person Arya McCarthy; 08.12.2020
comment
Мощный языковой инструмент всегда можно использовать для краткости, но без ясности. Я хотел привести пример, в котором для компактного выражения алгоритма можно использовать сокращение. Обратите внимание, что это пример оператора, который не является ассоциативным. - person user1153980; 10.12.2020