parciais são incrivelmente úteis.
Por exemplo, em uma sequência de chamadas de função "alinhadas por canal" (na qual o valor retornado de uma função é o argumento passado para a próxima).
Às vezes, uma função nesse pipeline requer um único argumento , mas a função imediatamente a montante dele retorna dois valores .
Nesse cenário, functools.partial
pode permitir que você mantenha esse pipeline de funções intacto.
Aqui está um exemplo específico e isolado: suponha que você queira classificar alguns dados pela distância de cada ponto de dados de algum destino:
# 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)
Para classificar esses dados por distância do alvo, o que você gostaria de fazer é:
data.sort(key=euclid_dist)
mas você não pode - o parâmetro- chave do método de classificação aceita apenas funções que usam um único argumento.
reescreva euclid_dist
como uma função usando um único parâmetro:
from functools import partial
p_euclid_dist = partial(euclid_dist, target)
p_euclid_dist
agora aceita um único argumento,
>>> p_euclid_dist((3, 3))
1.4142135623730951
então agora você pode classificar seus dados passando a função parcial para o argumento-chave do método de classificação:
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
Ou, por exemplo, um dos argumentos da função muda em um loop externo, mas é corrigido durante a iteração no loop interno. Ao usar um parcial, você não precisa passar o parâmetro adicional durante a iteração do loop interno, porque a função modificada (parcial) não exige isso.
>>> from functools import partial
>>> def fnx(a, b, c):
return a + b + c
>>> fnx(3, 4, 5)
12
crie uma função parcial (usando a palavra-chave arg)
>>> pfnx = partial(fnx, a=12)
>>> pfnx(b=4, c=5)
21
você também pode criar uma função parcial com um argumento posicional
>>> pfnx = partial(fnx, 12)
>>> pfnx(4, 5)
21
mas isso será lançado (por exemplo, criando parcial com argumento de palavra-chave e depois chamando usando argumentos posicionais)
>>> 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'
outro caso de uso: escrever código distribuído usando a multiprocessing
biblioteca do python . Um conjunto de processos é criado usando o método Pool:
>>> import multiprocessing as MP
>>> # create a process pool:
>>> ppool = MP.Pool()
Pool
possui um método de mapa, mas são necessárias apenas uma iterável; portanto, se você precisar transmitir uma função com uma lista de parâmetros mais longa, redefina a função como parcial, para corrigir todos, exceto um:
>>> ppool.map(pfnx, [4, 6, 7, 8])
extra_args
variável