パーシャルは信じられないほど便利です。
たとえば、関数呼び出しの「パイプライン」シーケンス(1つの関数からの戻り値が次の関数に渡される引数である)です。
このようなパイプラインの関数には単一の引数が必要な場合がありますが、そのすぐ上流の関数は2つの値を返します。
このシナリオでfunctools.partial
は、この関数パイプラインをそのまま維持できる可能性があります。
次に、特定の孤立した例を示します。いくつかのデータを、ターゲットからの各データポイントの距離で並べ替えるとします。
# create some data
import random as RND
fnx = lambda: RND.randint(0, 10)
data = [ (fnx(), fnx()) for c in range(10) ]
target = (2, 4)
import math
def euclid_dist(v1, v2):
x1, y1 = v1
x2, y2 = v2
return math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
このデータをターゲットからの距離で並べ替えるには、もちろん次のようにします。
data.sort(key=euclid_dist)
しかし、あなたはcan't - ソート方法のキーパラメータのみを取る機能受け入れる単一の引数を。
したがってeuclid_dist
、単一のパラメーターを取る関数として書き直します。
from functools import partial
p_euclid_dist = partial(euclid_dist, target)
p_euclid_dist
現在は単一の引数を受け入れ、
>>> p_euclid_dist((3, 3))
1.4142135623730951
これで、sortメソッドのキー引数の部分関数を渡して、データを並べ替えることができます。
data.sort(key=p_euclid_dist)
# verify that it works:
for p in data:
print(round(p_euclid_dist(p), 3))
1.0
2.236
2.236
3.606
4.243
5.0
5.831
6.325
7.071
8.602
または、たとえば、関数の引数の1つが外部ループで変更されますが、内部ループでの反復中に固定されます。パーシャルを使用することにより、変更された(パーシャル)関数は追加のパラメーターを必要としないため、内部ループの反復中に追加のパラメーターを渡す必要はありません。
>>> from functools import partial
>>> def fnx(a, b, c):
return a + b + c
>>> fnx(3, 4, 5)
12
部分的な関数を作成する(キーワードargを使用)
>>> pfnx = partial(fnx, a=12)
>>> pfnx(b=4, c=5)
21
位置引数を使用して部分関数を作成することもできます
>>> pfnx = partial(fnx, 12)
>>> pfnx(4, 5)
21
しかし、これはスローします(たとえば、キーワード引数で部分を作成してから、位置引数を使用して呼び出します)
>>> pfnx = partial(fnx, a=12)
>>> pfnx(4, 5)
Traceback (most recent call last):
File "<pyshell#80>", line 1, in <module>
pfnx(4, 5)
TypeError: fnx() got multiple values for keyword argument 'a'
別のユースケース:Pythonのmultiprocessing
ライブラリを使用して分散コードを作成する。プロセスのプールは、Poolメソッドを使用して作成されます。
>>> import multiprocessing as MP
>>> # create a process pool:
>>> ppool = MP.Pool()
Pool
にはmapメソッドがありますが、それは単一の反復可能型のみを取るため、より長いパラメーターリストを使用して関数を渡す必要がある場合は、関数をパーシャルとして再定義して、1つを除くすべてを修正します。
>>> ppool.map(pfnx, [4, 6, 7, 8])
extra_args
変数をどこから取得したのか