частичные случаи невероятно полезны.
Например, в «конвейерной» последовательности вызовов функций (в которой возвращаемое значение из одной функции является аргументом, передаваемым следующей).
Иногда функция в таком конвейере требует одного аргумента , но функция сразу после нее возвращает два значения .
В этом случае 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)
но вы не можете - ключевой параметр метода сортировки принимает только функции, которые принимают один аргумент.
поэтому переписать euclid_dist
как функцию, принимающую единственный параметр:
from functools import partial
p_euclid_dist = partial(euclid_dist, target)
p_euclid_dist
теперь принимает один аргумент,
>>> p_euclid_dist((3, 3))
1.4142135623730951
так что теперь вы можете отсортировать данные, передав частичную функцию для ключевого аргумента метода сортировки:
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
Или, например, один из аргументов функции изменяется во внешнем цикле, но фиксируется во время итерации во внутреннем цикле. При использовании частичного вам не нужно передавать дополнительный параметр во время итерации внутреннего цикла, потому что модифицированная (частичная) функция этого не требует.
>>> 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'
Другой вариант использования: написание распределенного кода с использованием multiprocessing
библиотеки Python . Пул процессов создается с помощью метода Pool:
>>> import multiprocessing as MP
>>> # create a process pool:
>>> ppool = MP.Pool()
Pool
имеет метод map, но он принимает только одну итерацию, поэтому, если вам нужно передать функцию с более длинным списком параметров, переопределите функцию как частичную, чтобы исправить все, кроме одного:
>>> ppool.map(pfnx, [4, 6, 7, 8])
extra_args