Я вижу то, что походит на большинство разработчиков Python на StackOverflow, подтверждающем использование кратких функциональных инструментов как лямбды, карты, фильтры, и т.д., в то время как другие говорят, что их код является более четким и более удобным в сопровождении, не используя их. Каково Ваше предпочтение?
Кроме того, если Вы - несгибаемый функциональный программист или хардкор в OO, что другие определенные практики программирования Вы используете это, Вы думаете, являются лучшими для Вашего стиля?
Заранее спасибо за Ваши мнения!
Я в основном использую Python в объектно-ориентированном и процедурном стилях. На самом деле Python не особенно хорошо подходит для функционального программирования.
Многие люди думают, что пишут функциональный код на Python, используя множество lambda
, map
, filter
и reduce
, но это слишком упрощенно. Отличительной особенностью функционального программирования является отсутствие состояния или побочных эффектов. Важными элементами функционального стиля являются чистые функции, рекурсивные алгоритмы и функции первого класса.
Вот мои мысли о функциональном программировании и Python:
Чистые функции - это здорово. Я делаю все возможное, чтобы мои функции на уровне модулей были чистыми.
Программирование на основе классов может быть чистым. Если вы хотите получить эквивалент чистых функций, используя классы Python (что иногда, но не всегда, то, что вы хотите),
Не пытайтесь полностью избежать состояния. В Python это не совсем разумная стратегия. Например, используйте some_list.append(foo)
, а не new_list = some_list + [foo]
, первый из которых более идиоматичен и эффективен. (Действительно, тонна "функциональных" решений, которые я вижу в Python, алгоритмически неоптимальны по сравнению с такими же простыми или более простыми решениями, которые не являются функциональными или являются такими же функциональными, но не используют функционально выглядящие инструменты.)
Изучите лучшие уроки функционального программирования, например, изменчивое состояние опасно. Спросите себя, действительно ли я хочу изменить этот X или мне нужен новый X?
Одно действительно распространенное место, где это возникает, - обработка списка. Я бы использовал
foo = [bar(item.baz()) for item in foo]
а не
for index, _ in enumerate(foo):
foo[index] = bar(foo[index].baz())
и тому подобное. Это позволяет избежать ошибок, когда один и тот же объект списка хранится в другом месте и не должен быть изменен. (Если он должен быть изменен, то велика вероятность ошибки проектирования. Мутирование некоторого списка, на который вы ссылались в нескольких местах, - не лучший способ обмена состоянием.)
Не используйте map
и друзей без необходимости. В этом нет ничего более функционального.
map
/filter
- не более функциональны, чем понимания списков. Понимание списков было заимствовано из Haskell, чисто функционального языка. map
и особенно filter
могут быть сложнее для понимания, чем списковые понимания. Я бы никогда не использовал map
или filter
с лямбдой, но мог бы, если бы у меня была уже существующая функция; я использую map
довольно часто. itertools.imap
/ifilter
по сравнению с выражениями-генераторами. (Эти вещи в некоторой степени ленивы, что мы можем позаимствовать у функционального мира.)map
и filter
для побочных эффектов. Я часто вижу это в map
, который делает сложный для понимания код, ненужные списки и явно не является функциональным (несмотря на то, что люди думают, что он должен быть таковым из-за map
.) Просто используйте цикл for. reduce
сбивает с толку, за исключением очень простых случаев. В Python есть циклы for, и нет ничего плохого в их использовании. Не используйте рекурсивные алгоритмы. Это одна из частей функционального программирования, которую Python просто плохо поддерживает. CPython (и, думаю, все другие Python) не поддерживает оптимизацию хвостовых вызовов. Вместо этого используйте итерацию.
Используйте лямбду
только при определении функций на лету. Анонимные функции не лучше именованных функций, последние часто более надежны, удобны в сопровождении и документированы.
Python имеет лишь незначительные возможности функционального программирования, поэтому я удивлюсь, если многие люди будут использовать его специально для этого. Например, не существует стандартного способа композиции функций, а reduce()
стандартной библиотеки был устаревшим в пользу явных циклов.
Также я не думаю, что map()
или filter()
обычно одобряются. Напротив, обычно предпочтение отдается списковым пониманиям.
Я выбираю Python, когда берусь за задачу, которая хорошо согласуется с объектно-ориентированным решением. Python предоставляет только ограниченные возможности программирования в функциональной манере по сравнению с полнофункциональными языками.
Если мне действительно нужно функциональное программирование, я использую Lisp.
Большинство ответов на StackOverflow - это короткие и лаконичные ответы, а функциональные аспекты python упрощают написание таких ответов.
Объектно-ориентированные функции Python просто не нужны в ответах из 10-20 строк, поэтому вы не часто видите их здесь.
Я использую функции языка, которые позволяют выполнять работу с помощью максимально короткого и чистого кода. Если это означает, что мне нужно смешать два, что я делаю довольно часто, то это то, что нужно сделать.
Я являюсь приверженцем ООП и функционального программирования, и эти стили очень хорошо работают вместе, в основном потому, что они полностью ортогональны. Существует множество объектно-ориентированных, функциональных языков, и Python - один из них.
Итак, в принципе, декомпозиция приложения на классы очень полезна при проектировании системы. Когда вы делаете фактическую реализацию, FP помогает написать правильный код.
Также я считаю очень обидным, что вы подразумеваете, что функциональное программирование означает просто "использовать складки везде". Это, вероятно, самое большое и самое худшее заблуждение о FP. На эту тему уже много написано, поэтому я просто скажу, что самое замечательное в FP - это идея объединять простые (,правильные и многократно используемые) функции в новые, все более и более сложные функции. Таким образом, довольно трудно написать "почти правильный" код - либо он делает именно то, что вы хотите, либо полностью ломается.
FP в Python в основном вращается вокруг написания генераторов и их родственников (list comprehensions) и вещей из модуля itertools
. Явные вызовы map/filter/reduce просто не нужны.