Pythonの作成者であるGuido van Rossumは、関数型プログラミングがあまり好きではありません。このことは周知の事実です。
Guido:「私は現実世界でのコードの読みやすさと有用性を重視しています。map()とfilter()が適切な場合もいくつかありますが、他のケースではPythonのリスト内包表記があるのです。わたしがreduce()を嫌いになったのは、それを使うとほとんど常に「(a)sum()を実装するのにしか使われていない」「(b)読み取り不可能なコードになってしまう」ということからです。
だからビルトインのsum()を追加し、reduce()を組み込み関数からfuntoolsで提供するものに降格しました。(ここは、私があまり気にしないもののゴミ捨て場です:-)。」
以下は、Guidoがreduce()関数が主にsum()の代替として使われていると主張しているケースです。
- from functools import reduce
- print(reduce(lambda x, y: x + y, range(1, 6)))
- # 15
reduce関数は2つの引数を取ります。一つは「2つの引数を取り1つの値を返す関数」と、二つ目はiterableです。そして次に、iterableからの2つの値を次々と取り出し、1つの値になるまで関数を繰り返し適用します。これを学習するために、よければ 私のreduce関数についてのブログチュートリアルを読んでみてください (読むための所用時間5分)。
この関数は便利に見えますが、ほとんどの人は実際に魅力的なユースケースを見つけることができません。
しかしながら、同じことをビルトイン関数sum()で簡単に行うことができます。
- print(sum(range(1,6)))
- # 15
これが、Guidoがreduce()関数をPython 3から削除しようとした理由です(Python 2では、reduce関数は組み込み関数でした)。 ここにGuidoがreduce(とlambdaとmap()とfilter()に反対する)彼の議論を説明した有名な記事があります。
この記事を徹底的に研究してください。すべてのPythonの専門家はこの記事の議論について知っています。
Guidoの lambdaとmap()、
filter()、reduce()に反対する議論
Guidoはこの記事で、これらの関数型プログラミング要素をPython言語に含めることに反対するいくつかの具体的な議論をしています。
[議論1]フィルタリングはリスト内包表記の方が適切です。
フィルター関数の例を次に示します。
- customers = ["Alice", "Bob", "Frank", "Ann"]
- a = filter(lambda x: x[0] == "A", customers)
- print(list(a))
- # ['Alice', 'Ann']
文字"A"から始まらないすべての顧客を取り除きます。しかし、これは次のステートメントで簡単に実現できます。
- a = [ x for x in customers if x[0] == "A" ]
- print(a)
- # ['Alice', 'Ann']
リスト内包表記はわずかに短いだけでなく、より高速でもありますし、lambda
関数を別に定義する必要がありません
リスト内包表記を改めて理解したい場合は、ブログでこの包括的なチュートリアルについてお気軽にお読みください。
[議論2] map()関数はリスト内包表記で置き換えることができます
map()
関数の例を次に示します。
- customers = ["Alice", "Bob", "Frank", "Ann"]
- lst1 = map(lambda x: x[0], customers)
- print(list(lst1))
- # ['A', 'B', 'F', 'A']
map()関数の最初の引数は(lambda)関数であり、2番目の引数はiterableです。最初の引数は、iterableの各要素をどのように変換(map、対応付け)するかを定義します。
ただし、これはリストの内包表記を使用することでよりよく達成できます(こちらもより効率的でもあります)。
- lst2 = [ x[0] for x in customers ]
- print(lst2)
- # ['A', 'B', 'F', 'A']
この解決策は読みやすく、文字数が少なく、効率的です。リスト内包表記を使用すべき状況なのは考えるまでもありません。
[議論3] filter()とmap()とreduce()がないなら、lambdaを持っている必要もなくなる
lambda関数は、コールバック関数を指定するために時々使用されます(たとえばユーザーインターフェースTkinterdで)。ただし、その場合でも、コールバック関数は明示的に定義できます(ほとんどの場合、そうする必要もあります)。
ならば、これらの機能を学ぶべきでしょうか
しかし、上記のとおりだとしても、これらの機能を知っておくべきであることには変わりません!
lambda関数は便利です(必須ではない。あなたはすべての関数をdef
キーワードを使って定義できます。これが多くの場合(私の意見としては)可読性を損なうとしても)。
多くの人々、特に関数型プログラミングから来た人々はそれらを使い続けるでしょう。英語に含まれる多くの単語を批判することもできるでしょうが、人々がそれらを使用している限り、それは何の役にも立ちません。より良いコミュニケーションをとるために、これらの言葉を学ぶ必要があります。
この元になった私のブログ記事:Guidoの記事「Python 3000のFate of Reduce()」について