3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

自習:Learn Functional Python in 10 Minutesの和訳

Last updated at Posted at 2018-09-18

元記事

この文書の意図

関数型プログラミングとPythonの自習として、上記サイトのエントリを翻訳してみる。したがって、私のこのエントリによって発生するいかなるトラブルについても責任を負うものではない。参考にすることを希望する読者は自己責任のもとで行うこと。
恐らく、執筆者はやわらかな雰囲気で書かれておられるので、和文はですます調とする。原文は少々砕けた調子である。今後、砕けた日本語に変更することも視野に入れておこう。

翻訳間違いの指摘などのアドバイスはどんなものであれ嬉しく思います。お返事を保証できません が、全てのアドバイスに対して感謝を感じるものであることを先に述べて、お礼に変えさせていただきます。

本文

執筆者紹介

Brandon Skerritt

著者 ブランドン・スカーリット

I write about obscure computer science topics that are extremely interesting. Follow me to learn more. https://skerritt.tech
Jul 30

私がこのコンピュータサイエンスの中でも難解なトピックスについて執筆したのは、これが非常に面白いものだからです。私のサイトを訪れてください。もっと学ぶことができますよ。

URL > https://skerritt.tech

2018年7月30日

Learn Functional Python in 10 Minutes (関数型Pythonについて10分で学ぼう)

In this article, you’ll learn what the functional paradigm is as well as how to use functional programming in Python.

この記事では、Pythonで関数型プログラミングを行う方法について学び、それと同じ程度に、関数型パラダイム(関数型プログラミングの考え方、方法論)とは何かについて学びます。

You’ll also learn about list comprehensions and other forms of comprehensions.

また、リスト内包やその他のオブジェクトの内包についても学習します。(訳注:内包はPythonの機能で、短いコードでオブジェクトの集合を初期化・定義できます。)

Functional paradigm(関数型パラダイム)

In an imperative paradigm, you get things done by giving the computer a sequence of tasks and then it executes them.

命令型(imperative)パラダイムでは、プログラマはコンピュータに一連のタスクを指示し、そしてそれをコンピュータに実行させて目的を達成します。

(訳注:Imperative(命令型)パラダイムに属する代表的な言語はFORTRAN,COBOL,BASICです。対するのは Declarative(宣言型)パラダイムで、これに属する代表的な言語はHaskell、LISP、Prologです。なお、ImperativeやDeclarativeという語彙は〜programmingとして使われることがあります。これはプログラムの構造や思想に重きをおく場合(paradigm)と、具体的なプログラミング言語の仕様に注目している場合(programming)で区別していると、翻訳者は考えます。)

While executing them, it can change states.

タスクの実行中、コンピュータの内部に保持した各種の状態を変更することが可能です。(訳注:言い換えれば、変数やオブジェクトの保持した値を変更・更新することが可能だということです。)

For example, let’s say you originally set A to 5, then later on you change the value of A.

例えば、最初に変数Aに数値5を代入したとします。その後、変数Aの値をプログラマ、あるいはコンピュータは変更することが可能です。

You have variables in the sense that the value inside the variable varies.

命令型パラダイムに慣れ親しんだプログラマは、変数に収めた値は変更可能であるという認識を持っていることでしょう。
 
In a functional paradigm, you don’t tell the computer what to do but rather you tell it what stuff is.

関数型パラダイムでは、プログラマはコンピュータにする事を指示するのではなく、コンピュータに内容を伝えることになります。

What the greatest common divisor of a number is, what the product from 1 to n is and so on.

ある数の最大公約数を知りたければ、1からnまでの数の積をとるなどという事をします。

Because of this, variables cannot vary.

以下に述べる理由によって、関数型パラダイムでは、変数に納めた値は変更されません。

Once you set a variable, it stays that way forever (note, in purely functional languages they are not called variables).

いったん変数に数値を代入すると、それはずっとそのままです。(メモ:純粋な関数型言語では、それを変数とは呼びません。)

Because of this, functions have no side effects in the functional paradigm.

こう言うわけで、関数型パラダイムにおいて関数は副作用を発生しません。

A side effect is where the function changes something outside of it.

副作用とは、関数がその外部に何らかの変更をする事です。

Let’s look at an example of some typical Python code:

典型的なPythonのコード例を見て下さい。

rawside_effects.py
a = 3
def some_func():
    global a
    a = 5

some_func()
print(a)

The output for this code is 5. In the functional paradigm, changing variables is a big no-no and having functions affect things outside of their scope is also a big no-no.

このコードの実行結果は数値の5です。関数型パラダイムでは、変数の値の変更は極力やってはいけない事で、変数や関数などのスコープの外に対して副作用を発生することも、同じくらいに極力やってはいけないことです。

The only thing a function can do is calculate something and return it as a result.

関数が行う事を許される唯一のことは、何かを計算して、その結果を返す事です。

Now you might be thinking: “no variables, no side effects? Why is this good?”.

ここで読者はこう考えるかもしれません。「変数なしで、副作用もなし?それが何か良い事なの?」

Good question, gnarly stranger reading this.

関数型パラダイムについて全く知らない人にとっては、当然の質問です。

If a function is called twice with the same parameters, it’s guaranteed to return the same result.

もし関数が同じパラメータ(引数)で2度呼ばれたら、同じ結果を返すことが保証されています。

If you’ve learnt about mathematical functions, you’ll know to appreciate this benefit.

もしあなたが、数学における関数を学んだことがあれば、この利点がありがたく感じるでしょう。

This is called referential transparency.

この性質は参照透過性と呼ばれます。

Because functions have no side effects, if you are building a program which computes things, you can speed up the program.

関数が副作用を持たない為に、何らかの計算を行うプログラムを作ると、(実行)速度を向上できます。

If the program knows that func(2) equates to 3, we can store this in a table.

もし、プログラム(コンピュータ)が関数func(2)(訳注:関数名がfuncで引数に2を与えた、と言うこと。)が3に等しい事を知ったとする。(関数型パラダイムでは、今後func(2)の値は3から変化しな事を保証されているので)私たちはこの結果をコンピュータの中に表にして持っておくことができる。

This prevents the program from repeatedly running the same function when we already know the answer.

関数型パラダイムのこの性質は、既に答えを知っている(計算済みの)関数を、プログラムが何度も繰り返して実行する事を防ぎます。

Typically, in functional programming, we do not use loops.

一般的に、関数型プログラミングでは、プログラマは繰り返し構文を使いません。
 
We use recursion.

リカージョン、すなわち再帰と言う手法があります。

Recursion is a mathematical concept, usually, it means “feeding into itself”.

再帰 は数学の概念で、通常は「自分自身に入力する」と言う意味です。

With a recursive function, the function repeatedly calls itself as a sub-function.

再帰関数を使うと、その関数は自分自身を副関数(訳注:と言う言葉が一般的ではないと思うので、意訳を試みれば「補助役の関数」か)として繰り返し呼び出します。

Here’s a nice example of a recursive function in Python:

次に示すのが、Pythonで書いた再帰関数の好例です。

rawfactorial_recursive.py
def factorial_recursive(n):
    # Base case: 1! = 1
    if n == 1:
        return 1

    # Recursive case: n! = n * (n-1)!
    else:
        return n * factorial_recursive(n-1)

Some programming languages are also lazy.

プログラミング言語のうちのいくつかは、Pythonと同様にユルいところがあります。

This means that they don’t compute or do anything until the very last second.

と言うのは、それらのプログラミング言語は、必要が生じる直前まで計算も何もしない、という意味です。

If you write some code to perform 2 + 2, a functional program will only calculate that when you actually need to use the resultant.

2+2を計算するコードを書いたとします。関数型のプログラミング言語で記述されたプログラムは、その結果である4を、実際に必要とする時だけに計算します。

We’ll explore laziness in Python soon.

Pythonにおける「ユルさ」を、しばらく後でじっくり見ていきます。

Map(Mapというクラスについて)

To understand map, let’s first look at what iterables are.

Mapについて理解を深める為に、「iterables」(一連のデータで、順に巡ることができる性質)の意味について概観しましょう。

An iterable is anything you can iterate over.

iterableとは、何であれ、一通り順番に巡ることができる事を意味します。

Typically these are lists or arrays, but Python has many different types of iterables.

標準的には、list(リスト)やarray(アレイ、すなわち配列)があります。しかし、Pythonはもっと多くの異なるiterableな型を持っています。

You can even create your own objects which are iterable by implementing magic methods.

プログラマは、おまじないメソッドを実装すれば、巡回可能な独自のオブジェクトを定義することだってできるのです。(訳注:「おまじないメソッド」とは、(恐らく多くの)日本のプログラマにとって共通の業界用語で、意味がわからない、あるいは意味が曖昧だけれども、それをソースコード書いて実行すれば、ある仕事がうまくいく、というメソッドのことです。多くのC言語初心者にとって、ソースコード先頭の#include<stdio.h>が「おまじない」であるのと同じことです。)

A magic method is like an API that helps your objects become more Pythonic.

おまじないメソッドとは、プログラマが独自に作ったオブジェクトを使いやすくし、よりPythonicにする (Pythonらしくカッコよい)APIです。

You need to implement 2 magic methods to make an object an iterable:

あるオブジェクトをiterableにする(巡回可能にする)には、2つのおまじないメソッドを実装する必要があります。

rawcounter.py
class Counter:
    def __init__(self, low, high):
        # set class attributes inside the magic method __init__
        # for "inistalise"
        self.current = low
        self.high = high

    def __iter__(self):
        # first magic method to make this object iterable
        return self

    def __next__(self):
        # second magic method
        if self.current > self.high:
            raise StopIteration
        else:
            self.current += 1
            return self.current - 1

The first magic method, “__iter__” or dunder iter (double underscore iter) returns the iterative object, this is often used at the start of a loop.

最初のおまじないメソッドは"__iter__"です。これは「ダンダー・イテレータ」(あるいは、ダンダー・イター)と読みます。ダンダーは、ダブル・アンダースコアを縮めた名前です。これは、巡回する際に必要なオブジェクトを返します。多くの場合に、繰り返しの先頭で用いられます。

Dunder next returns what the next object is.

ダンダー・ネクストは次に続くオブジェクトを返します。

Let’s go into a quick terminal session and check this out:

次のコードをターミナルからPythonインタプリタに与えて実行して見ましょう。

rawcounter_example.py
for c in Counter(3, 8):
    print(c)

This will print
すると、画面には次のような出力結果が表示されます。

3
4
5
6
7
8

In Python, an iterator is an object which only has an __iter__ magic method.

Pythonでは、iterator(イテレータ)はおまじないメソッド__iter__だけを持つオブジェクトです。

This means that you can access positions in the object, but cannot iterate through the object.

これが意味することは、オブジェクトのあらゆる要素にアクセスできますが、オブジェクトの要素を一通りに巡回することはできないのです。(訳注:???意味不明。どういうことだ?)

Some objects will have the magic method __next__ and not the __iter__ magic method, such as sets (talked about later in this article).

あるオブジェクトはおまじないメソッド__next__を持っており、おまじないメソッド__iter__は持っていません。例えばこの文書で後ほど紹介するsetがそうです。

For this article, we’ll assume everything we touch is an iterable object.

この文書の中で取り扱う全てのオブジェクトは、巡回可能な(iterableな)オブジェクトであると仮定します。

So now we know what an iterable object is, let’s go back to the map function.

iterableなオブジェクトがどんなものかが分かったところで、map関数に話を戻そう。

The map function lets us apply a function to every item in an iterable.

map関数はiterableなオブジェクト全てについて、ある関数を適用できます。(???)

Typically we want to apply a function to every item in a list, but know that it’s possible for most iterables.

標準的には、listに納めた全ての要素に対してある関数を適用したいとき、ほぼ全てのiterableなオブジェクトに対して可能だということを知っておこう。(???)

Map takes 2 inputs, the function to apply and the iterable object.

mapは二つの引数をとります。引数の一つは適用する関数、もう一つはiterableオブジェクトです。

rawmap_example.py
map(function, iterable)

Let’s say we have a list of numbers like so:

こんな数値のリストがあるとします。

[1, 2, 3, 4, 5]

And we want to square every number, we can write code like this:

そして、このリストに含まれる数値を全て2乗したいならば、次のようなコードを書こう。

rawsquare_map.py
x = [1, 2, 3, 4, 5]
def square(num):
    return num*num

print(list(map(square, x)))

Functional functions in Python are lazy.

Pythonにおける関数型の関数はlazyです(あるいはユルいです)。
(訳注:ここでのlazyをどの日本語にするのが適切だろう。具体的には、遅延評価のことを指すのだろう。関数は、実際に関数の戻り値が必要になるまで評価されない、値を返さない、内部の計算をしない、内部のコードを実行しないということを指してlazyと表現している。)

If we didn’t include the “list()” the function would store the definition of the iterable, not the list itself.

もしプログラマが関数"list()"を組み込まなければ、listそれ自身ではなく、iterableの定義がその関数の定義になるでしょう。(???)

We need to explicitly tell Python “turn this into a list” for us to use this.

プログラマはこれを使うために、Pythonに対して「これをリストに組み込みます」と明確に支持する必要があります。

It’s a bit weird to go from non-lazy evaluation to lazy evaluation all of a sudden in Python.

Pythonで、突然にlazyでない評価からlazyな評価に移行することは、少々奇妙に感じるでしょう。(???)

You’ll eventually get used to it if you think more in the functional mindset than an imperative mindset.

命令型プログラミングの思考法よりも関数型プログラミングの考え方を用いる機会を増やすことで、だんだんと慣れていくことでしょう。

Now it’s nice to write a normal function like “square(num)” but it doesn’t look right.

普通の関数として"square(num)"などと書くのがそれらしいと思うでしょう。でも、それは関数型プログラミングとしては正しくありません。

We have to define a whole function just to use it once in a map?

mapのなかで一度だけでも使うためには、関数全体を定義しなければなりません。

Well, we can define a function in map using a lambda (anonymous) function.

lambda(無名)関数を使えば、mapの中で関数を定義できます。

Lambda expressions(lambda表現)

A lambda expression is a one line function.

lambda表現は1行で書く関数です。

Take, for instance, this lambda expression which squares a number given to it:

例えば、次のlambda表現は与えた数字を2乗して返します。

rawlambda_example.py
square = lambda x: x * x

Now let’s run this:
さあ、実行して見ましょう。

>>> square(3)
9

I hear you. “Brandon, where are the arguments? what the heck is this? that doesn’t look anything like a function?”

あなたがこう言うのが聞こえてきそうです。「なあ、Brandon、引数はどこだい?こりゃ一体どう言うことだい?全く関数らしくないじゃないか。

Well, it’s kind of confusing but can be explained.

さて、これは混乱しているようですが、これから説明します。

So we’re assigning something to the variable “square”. this part:

プログラムの次の部分で、変数squareに何かを割り当てています。

rawhalf_a_lambda.py
lambda x:

Tells Python that this is a lambda function, and the input is called x.

このPythonコードは、これがlambda関数であると表現しています。そして、入力にあたるものをxと呼んでいます。

Anything after the colon is what you do with the input, and it automatically returns whatever the resultant of that is.

コロン(:)の後に続くものは何であれ、入力としてプログラムに取り扱われます。そして、その結果がどんなものであれ、自動的に呼び出し側に戻します。

To simplfy our square program into one line we can do:

2乗するプログラムをより単純に、1行のプログラムにするために、次のようなコードを書くことができます。

rawsquare_with_lambda.py
x = [1, 2, 3, 4, 5]
print(list(map(lambda num: num * num, x)))

So in a lambda expression, all the arguments go on the left and the stuff you want to do with them go on the right.

それで、lambda表現の中では、全ての引数は左へ適用されてゆき、適用したい処理は右へ作用していきます。

It gets a little messy, no one can deny that.

この書き方はちょっと汚いと言うか読みにくいのですが、Pythonを使う限りは避けて通れません。

The truth is that there’s a certain pleasure in writing code that only other functional programmers can read.

本当のところ、こんな風にコードを書くことの明確なメリットは、唯一、関数型プログラミングを行うプログラマが読みやすいからだと言うことです。

Also, it’s super cool to take a function and turn it into a one-liner.

それから、関数を1行で書いちゃうなんて、チョーカッコイイってことですよ。

Reduce(畳み込み)

Reduce is a function that turns an iterable into one thing.

reduce(畳み込み)はiterableなオブジェクトを一つにまとめる関数です。

Typically you perform a computation on a list to reduce it down to one number.

標準的には、プログラマがlistの各要素について何らかの計算処理をして、一つの数値に畳み込むと言うことです。

Reduce looks like this:
畳み込みの関数reduceは次のように使います。

rawreduce_syntax.py
reduce(function, list)

We can (and often will) use lambda expressions as the function.

プログラマは、lambda表現を関数として使えます。そしてやがては、その便利さに魅了されて頻繁に使うようになるでしょう。

The product of a list is every single number multiplied together.

listの積とは、listに含まれるそれぞれの数値を掛け合わせたもののことです。

To do this you would program:

それを行うには次のようなコードを書くことになります。

rawproduct.py
product = 1
x = [1, 2, 3, 4]
for num in x:
    product = product * num

But with reduce you can just write:

しかし、reduceを使うとこんなに簡単になります。

reducr.py
from functools import reduce

product = reduce((lambda x, y: x * y),[1, 2, 3, 4])

To get the same product. The code is shorter, and with knowledge of functional programming it is neater.

同じlistの積を計算するために、reduceを使った場合の方がコードが短くなり、関数型プログラミングに関する知識が小さくまとまってわかりやすくなっています。

Filter(フィルタ)

The filter function takes an iterable and filters out all the things you don’t want in that iterable.

filter関数はiterableオブジェクトひとつと、いくつかのfilterを引数にとり、iterableなオブジェクトに納められた要素のうちの不必要な要素を全て除外します。

Normally filter takes a function and a list.

普通のfilterは関数をひとつとlistをひとつ引数に取ります。

It applies the function to each item in the list and if that function returns True, it does nothing.

そのfilterは、関数をlistの要素ひとつひとつに適用し、関数がTrue(真)を返したら何もしません。

If it returns False, it removes that item from the list.

関数がFalse(偽)を返したら、listからその要素を削除します。

The syntax looks like:
文法はこんな具合です。

filter_syntax.py
filter(function, list)

Let’s see a small example, without filter we’ll write:
フィルタを使わずに書くとどうなるか、小さなサンプルを次に示します。

example_without_reduce.py
x = range(-5, 5)
new_list = []

for num in x:
    if num < 0:
        new_list.append(num)

With filter, this becomes:

フィルタを使うと、こんな風になります。

example_with_filter.py
x = range(-5, 5)
all_less_than_zero = list(filter(lambda num: num < 0, x))

Higher order functions(高階関数)

Higher order functions can take functions as parameters and return functions.

高階関数は引数として関数を取ることができます。そして、関数を返します。

A very simple example would look like:

非常に単純な例を示すなら、次のような感じです。

higher_order.py
def summation(nums):
    return sum(nums)

def action(func, numbers):
    return func(numbers)

print(action(summation, [1, 2, 3]))

# Output is 6

Or an even simpler example of the second definition, “return functions”, is:

あるいは「関数を返す」と言う二つ目の定義の、まあそれでも簡単な例はこんな感じです。

return_function.py
def rtnBrandon():
    return "brandon"
def rtnJohn():
    return "john"

def rtnPerson():
    age = int(input("What's your age?"))

    if age == 21:
        return rtnBrandon()
    else:
        return rtnJohn()

You know earlier how I said that pure functional programming languages didn’t have variables?

この記事の最初の方で、純粋な関数型プログラミング言語は変数を持たないと書いたことを覚えていますよね。

Well, higher order functions are what makes this easier.

で、高階関数はそのことを簡単に実現してくれるんです。

You don’t need to store a variable anywhere if all you’re doing is passing data through a long tunnel of functions.

コードのどの部分であっても、変数に値を入れる必要はなく、単に関数から関数へと長いトンネルをくぐらせるようにデータを通していくだけなのです。

All functions in Python are first class objects.

Pythonの全ての関数は、第1級クラスのオブジェクトです。(訳注:第1級クラスとは****と言うことです。)

A first class object is defined as having one or more of these features:

第1級クラスのオブジェクトは、ひとつ以上の以下に示す機能を持っているものとして定義されます。

  • Created at runtime(実行時に生成される)
  • Assigned tro a variable or element in a data structure()
  • Passed as an argument to a function(関数の引数として渡される)
  • Returned as the result of a function(関数の戻り値となる)

So all functions in Python are first class and can be used as a higher order function.

こう言う訳で、Pythonの全ての関数は第1級であり、高階関数として使われることができます。

Partial application

Partial application (also called closures) is a bit weird, but are super cool.

部分的な適用、あるいはクロージャ(closures)はちょっと奇妙です。でも、チョーカッコいいです。

You can call a function without supplying all the arguments it requires.

ある関数が必要とする全ての引数を、完全に与えなくても、その関数を呼び出して使うことができます。

Let’s see this in an example.

例を見ながら説明しましょう。

We want to create a function which takes 2 arguments, a base and an exponent, and returns base to the power of the exponent, like so:

二つの引数を持つ関数を作りたいとします。それは基数と指数で、関数の戻り値は、基数を指数で乗じたものです。コードは次のようになります。

partial_application.py
def power(base, exponent):
  return base ** exponent

Now we want to have a dedicated square function, to work out the square of a number using the power function:

さあ、指数関数を使って数値の2乗を計算するために、2乗専用の関数が欲しいとします。

square.py
def square(base):
  return power(base, 2)

This works, but what if we want a cube function? or a function to the power of 4?

このコードはちゃんと動きます。でも、3乗の関数がほしくなったら?あるいは4乗のがほしくなったら?

Can we keep on writing them forever? Well, you could. But programmers are lazy.

そうやってずっと、必要な関数を書き続けられるでしょうか。まあ、出来るでしょう。でも、プログラマって奴は怠惰なんです。

If you repeat the same thing over and over again, it’s a sign that there is a much quicker way to speed things up and that will allow you to not repeat things.

もし、なんども繰り返し同じことをしているならば、自分に繰り返しをさせないで、よりはやく仕事を片付ける方法があることを示す兆候です。

We can use partial applications here.

部分適用をここで使えます。

Let’s see an example of the square function using a partial application:

部分適用を使った2乗の関数の例を見てください。

partial_app.py
from functools import partial

square = partial(power, exponent=2)
print(square(2))

# output is 4

Isn’t that cool! We can call functions which require 2 arguments, using only 1 argument by telling Python what the second argument is.

これ、イカすでしょう!Pythonに二つ目の引数を示すことで、引数を一つだけ与えて、二つの引数を必要とする関数を呼んでいます。

We can also use a loop, to generate a power function that works from cubed all the way up to powers of 1000.

繰り返し構文を使うことで、3乗でも1000乗だってもべき乗を行う関数を作ることができます。

partial_app2.py
from functools import partial

powers = []
for x in range(2, 1001):
  powers.append(partial(power, exponent = x))

print(powers[0](3))
# output is 9

Functional programming isn’t Pythonic(関数型プログラミングはPythonicじゃない)

(訳注:Pythonicとは、Pythonの特徴を生かしたコードである、Pythonらしく上手に書かれたコードである、と言うような意味です)

You might have noticed, but a lot of the things we want to do in functional programming revolve around lists.

既にお気付きのことと思いますが、この文書にあるような、著者らが関数型プログラミングを使ってしたいことは、listを中心にして展開しています。

Other than the reduce function & partial application, all the functions you have seen generate lists.

reduce関数や部分的な適用を除いて、ここで紹介した全ての関数はlistを生成します。

Guido (the inventor of Python) dislikes functional stuff in Python because Python already has its own way to generate lists.

Python開発の父であるGuidoは、Pythonにおける関数型的なことが嫌いでした。それはPython自身が既に、listを生成する方法を独自に持っているからです。

If you write “import this” into a Python IDLE session, you’ll get:

Pythonの対話型インタフェイスであるIDLEを起動して、"import this"とキーボードを叩けば、次のような文章が表示されるでしょう。

>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren’t special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one — and preferably only one — obvious way to do it.
Although that way may not be obvious at first unless you’re Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it’s a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea — let’s do more of those!

Python哲学、Tim Peters 著
(訳注:Zenを哲学と訳したが、近くて遠い。ZenはPhirosophyではない。哲学のように学問として確立していないが、実践的に有効な、これまでに普及しているプログラミング哲学とはちょっと違う思想、と言いたいのだろう。)

This is the Zen of Python.

これはPythonのZenである。

It’s a poem about what something being Pythonic means.

これは、Pythonicであると言うことの意味する何かを語るための詩である。

The part we want to relate to here is:

このエントリに関連するのは次の部分です。

There should be one — and preferably only one — obvious way to do it.

ひとつの、できればたったひとつの、ことを成すための最善の方法があるべきだ。

In Python, map & filter can do the same things as a list comprehension (discussed next) can do.

Pythonでは、mapとfilterが、リスト内包(次に説明する)と同じことができる。 

This breaks one of the rules of the Zen of Python, so these parts of functional programming aren’t seen as ‘pythonic’.

これはPythonの哲学のルールのひとつを破ってしまう。関数型プログラミングのそれらの部分は’pythonic’(Pythonのプログラムとしてイケている)らしく見えない。

Another talking point is Lambda.

もうひとつのポイントはLambda(ラムダ)だ。

In Python, a lambda function is a normal function.

Pythonでは、lambda関数は普通の関数である。

Lambda is syntactic sugar.

Lambdaはシンタックス・シュガーである。
(訳注:シンタックス・シュガーとは、糖衣構文と意訳される。複雑になりがちなコードを読みやすく理解しやすくなるように工夫した構文、プログラミング言語の文法のこと。別の書き方もできるが、そうした方がより読みやすく理解しやすい別の書き方。)

Both of these are equivalent:

次に示す二つのコードは等価である。

lambda_and_function.py
foo = lambda a: 2

def foo(a):
  return 2

A regular function can do everything a lambda function can, but it doesn’t work the other way around.

普通の関数は、lambda関数にできることは全てできます。しかし逆は成り立ちません。

A lambda function cannot do everything that a regular function can do.

lambda関数は、普通の関数ができることを全てできるわけではありません。

This was a short argument about why functional programming doesn’t fit into the whole Python ecosystem very well.

この文書は関数型プログラミングがPythonのエコシステム全体にしっくりと来ないことに関する短い考察です。

You may have noticed I mentioned list comprehensions earlier, we’ll discuss them now.

著者が早い段階からリスト内包に言及していたことにお気づきでしょう。それをこれから行います。

List comprehensions(リスト内包)

Earlier, I mentioned that anything you could do with map or filter, you could do with a list comprehension.

この文書の前半で、著者はmapやfilterでできることについて言及しました。

This is the part where we’ll learn about them.

これはこれから学ぼうとしていることの一部です。

A list comprehension is a way to generate lists in Python.

リスト内包はPythonにおいてリストを生成する方法のひとつです。

The syntax is:

文法は次の通りです。

rawcomprehension.py
[function for item in iterable]

So let’s square every number in a list, as an example:

では、リストに含まれる全ての数値を2乗する、次のサンプルコードを実行して見ましょう。

rawsquare_list_comp.py
print([x * x for x in [1, 2, 3, 4]])

Okay, so we can see how we can apply a function to every item in a list.

よーし!これでリストに入っている全ての要素に関数を適用する方法を確認できました。

How do we go around applying a filter? Well, look at this code from earlier:

filterを適用する方法についての色々がわかりましたか?では、次のサンプルコードを先頭からじっくり見てください。

rawlist_comp_filter.py
x = range(-5, 5)

all_less_than_zero = list(filter(lambda num: num < 0, x))
print(all_less_than_zero)

We can convert this into a list comprehension like so:

上のコードを、次のようにリスト内包に書き換えることができます。

rawlist_comp_reduce2.py
x = range(-5, 5)

all_less_than_zero = [num for num in x if num < 0]

List comprehensions support if statements like this.

リスト内包の中でif構文をこのように使うことができます。

You no longer need to apply a million functions to something to get what you want.

読者はもはや、必要な結果を得るために、数多の関数を適用する必要がありません。

In fact, if you’re trying to make some kind of list chances are that it’ll look cleaner and easier using a list comprehension.

実際、もし何らかのlist chancesを作ろうとする時、リスト内包を使ったコードは綺麗で簡単に見えます。(この1行、何ともわからん。chances areをどう訳す)

What if we want to square every number below 0 in a list?

リストに含まれる、0より小さい数を全て2乗したいならばどうでしょう。

Well, with lambda, map and filter you’ll write:

さて、lambda、map、そしてfilterを使えばこんな風に書けます。 

functional_square_0.py
x = range(-5, 5)

all_less_than_zero = list(map(lambda num: num * num, list(filter(lambda num: num < 0, x))))

So that’s seems really long and slightly complicated.

それで、上の書き方はとっても長ったらしいし、ちょっと複雑にも感じます。

With a list comprehension it’s just:

リスト内包を使えば、こんなに簡単に。

square_0.py
x = range(-5, 5)

all_less_than_zero = [num * num for num in x if num < 0]

A list comprehension is only good for, well, lists.

リスト内包はlistに対して”のみ”、有効です。

Map and filter work on any iterable, so what’s up with that?

あるiterableに対してmapやfilterを使ったら、何かいいことがあるでしょうか?

Well, you can use any comprehension for any iterable object you encounter.

えっと、何についての内包であれiterableなオブジェクトにたいしてなら使えます。

Other comprehensions(別の内包)

You can create a comprehension of any iterable

どのiterableなオブジェクトについても内包を作ることができます。

Any iterable can be generated using a comprehension.

どのiterableなオブジェクトでも、内包を用いて生成できます。

Since Python 2.7, you can even generate a dictionary (hashmap).

Pythonバージョン2.7から、dictionary(hashmap)であっても生成できるようになりました。

If it’s an iterable, it can be generated.

もし、iterableなオブジェクトの要素が一つであっても、生成できます。

Let’s look at one last example of sets.

最後に、setに関するサンプルコードを見てみましょう。

If you don’t know what a set is, check out this other article I wrote.

setクラスについて知らないならば、私の書いた別の記事を確認してください。

The TLDR is:

私の記事が長くて読んでいられない、って方には、次のまとめを読んでもらいましょうか。

  • Sets are lists of elements, no element is repeated twice in that list
  • setクラスは複数の要素を収めたリストの集合で、そのリストの中には重複する要素がありません。
  • The order in sets do not matter.
  • setの中では要素に順番はありません。
set_comprehension.py
# taken from page 87, chapter 3 of Fluent Python by Luciano Ramalho

>>> from unicodedata import name
>>> {chr(i) for i in range(32, 256) if 'SIGN' in name(chr(i), '')}
{'×', '¥', '°', '£', '©', '#', '¬', '%', 'µ', '>', '¤', '±', '', '§', '<', '=', '®', '$', '÷', '¢', '+'}

You may notice that sets have the same curly braces as dictionaries.

setはdictionaryクラスと同じようにカーリー・ブレース({ })で書かれることにお気づきでしょう。

Python is really smart.

Pythonは本当に賢い言語です。

It’ll know whether you’re writing a dictionary comprehension or a set comprehension based on whether you provide the extra value for the dictionary or not.

Pythonはプログラマが書いているコードが、dictionary内包なのか、set内包なのか認識します。たとえ、プログラマがコードに対して、それがdictionaryなのか違うのか、余分な情報を与えなくてもです。

If you want to learn more about comprehensions, check out this visual guide.

もし、内包についてより詳しく学びたいならば、次のリンクで示したビジュアルガイド(視覚的にわかりやすく記述された記事です)を読んでください。

If you want to learn more about comprehensions & generators, check out this article.

読者が内包とジェネレータについてより詳しく学びたいならば、次の記事を読んでください。

Conclusion(まとめ)

Functional programming is beautiful and pure.

関数型プログラミングは美しくて素朴です。

Functional code can be clean, but it can also be messy.

関数型で書かれたコードはバグが入りにくいのですが、読みにくくなりやすいです。

Some hardcore Python programmers dislike the functional paradigm in Python.

バリバリのPythonプログラマの中には、Pythonに組み込まれた関数型の思想を嫌う人もいます。

You should use what you want to use, use the best tool for the job.

あなたには、自分の頭で判断して、使いたいと思うものを使い、そして今取り組んでいる仕事に対して最も適した道具を選んでください、とお勧めします。

3
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?