【Python】partial関数の使い方の基本 ~関数の部分適用~

Python で partial 関数を使って関数の部分適用をする方法を解説します。
partial 関数で関数の部分適用をする
partial 関数は、関数と引数の値を受け取ることで関数の部分適用をすることができる関数です。partial 関数は、functools モジュールに含まれています。
このように引数に関数を受け取る関数は高階関数と言います。高階関数は、関数を操作するための強力なツールであり、関数の部分適用は、関数型プログラミング言語でも重要な概念です。
Python はマルチパラダイムの言語と言われているため、厳密ではありませんが関数型のプログラミングスタイルもサポートしており、partial 関数が利用できます。
本記事では、partial 関数を用いて関数の部分適用をする方法の基本を紹介します。
関数の部分適用とは
関数の部分適用は、数学やプログラミングにおいて重要な概念です。部分適用は、ある関数に対して一部の引数を固定して新しい関数を作る手続きを言います。これにより関数をより柔軟に再利用したり、複雑な操作をシンプルに表現することができます。
例として、以下のような数学の関数を考えます。
\begin{eqnarray}
f(x, y) = x^{y}
\end{eqnarray}
この関数は $x$ を $y$ 乗する関数で、Python でも組み込みの関数として pow(x, y) として計算することができます。ここで、$y=2$ と固定して新しい関数を作ることを考え、新しい関数を $g(x)$ とおくと以下のようになります。
\begin{eqnarray}
g(x) = f(x, 2) = x^{2}
\end{eqnarray}
このように元の関数 $f(x, y)$ の一部の引数を固定して新しい関数 $g(x)$ を作成するのが部分適用の基本的な考え方です。
このような部分適用を実装する際に partial 関数を使用できます。以降で、具体的な partial 関数の使い方を説明します。
partial 関数の基本的な使い方
partial 関数の基本的な構文は以下のようになります。
from functools import partial partial_func = partial(関数, 引数=値)
partial 関数は、functools モジュール内にあるためインポートが必要です。
partial 関数は、対象の関数と固定したい引数とその値を指定します。返却値は、引数を指定した値で固定した関数であり、以降の処理で関数として使用できます。
基本的な使い方
部分適用の説明で使用した $f(x, y) = x^{y}$ で $y$ を固定する例をつかって、partial 関数の使い方を見ていきましょう。
from functools import partial # pow(base, exp)においてexp=2に固定する pow2 = partial(pow, exp=2) # 4 ** 2 = 16 print(pow2(4)) # 5 ** 2 = 25 print(pow2(5)) # pow(base, exp)においてexp=3に固定する pow3 = partial(pow, exp=3) # 4 ** 3 = 64 print(pow3(4)) # 5 ** 3 = 125 print(pow3(5))
【実行結果】 16 25 64 125
関数として、Python の組み込みである pow(base, exp) を使用しています。
partial 関数の呼び出しでは「pow2 = partial(pow, exp=2)」というように関数 pow と固定する exp 引数の値を指定しています。ここでポイントは、関数を渡す際に () がないことです。関数は pow(4, 2) のように () で引数を指定すると関数を実行することを意味しますが、() がない場合は関数そのものを表します。partial 関数は、受け取った pow を関数の内部処理で使用します。
返却値の pow2 は、そのものが引数exp=2に固定した pow 関数となっています。そのため、pow2(4) は「$4^2=16$」、pow2(5) は「$5^2=25$」となります。
partial 関数の便利なところは 3 乗の関数を作ろうと思ったら「pow3 = partial(pow, exp=3)」と簡単に作れることです。この場合は、pow3(4) は「$4^3=64$」、pow3(5) は「$5^3=125$」となります。
今回は、組み込み関数の pow を例にしましたが独自に作った関数でも同様のことがができます。このように partial 関数で、関数の部分適用を簡単に実現できます。
部分適用とクロージャ
部分適用と似た概念としてクロージャがあります。部分適用とクロージャは、関数の振る舞いを変更するための技術としてよく聞きますが、それぞれ異なるコンセプトです。
クロージャは、関数の外部スコープの変数を参照し、その変数の値を保持する関数のことを言います。例えば、外部の関数スコープで定義された変数を内部の関数で使用する場合は、内部関数はクロージャとして振舞うことになります。
一方で、部分適用は関数のいくつかの引数を固定し、新しい関数を生成する手法のことを指します。この新しい関数は固定されていない引数のみ受け取って動作します。
クロージャの場合は、以下のようなコード例となります。
def make_pow(factor):
# my_powという内部関数は、外部関数のfactor引数を参照する
def my_pow(x):
return x ** factor
return my_pow
pow2 = make_pow(2)
# 4 ** 2 = 16
print(pow2(4))
# 5 ** 2 = 25
print(pow2(5))【実行結果】 16 25
上記例では、make_pow 関数の中に内部関数として my_pow という関数を作成しています。この時、内部関数である my_pow 関数は外部関数の factor 引数を参照しており、make_pow 関数は戻り値として、factor を保持する my_pow 関数を返却します。
partial を使用した部分適用と上記例で示したクロージャは同じような動作をすることが分かりますが、実装方法や背後にある概念が異なっています。
部分適用は関数の引数の一部を固定することを主な目的とする一方で、クロージャは外部関数の変数を内部関数が参照・保持する機能を持っています。
まとめ
Python で partial 関数を使って関数の部分適用をする方法を解説しました。
partial 関数は、関数と固定する引数の値を受け取ることで関数の部分適用をすることができる関数です。partial 関数は、functools モジュールに含まれています。
この記事では、partial 関数を使って関数の部分適用をする例を紹介しました。partial 関数は、関数をより柔軟に再利用したり、複雑な操作をシンプルに表現したりする際に非常に便利な関数のため、使い方を理解しておくようにしましょう。
上記で紹介しているソースコードについては GitHub にて公開しています。参考にしていただければと思います。


