partiels sont incroyablement utiles.
Par exemple, dans une séquence d'appels de fonction en "pipe-line" (dans laquelle la valeur retournée d'une fonction est l'argument passé à la suivante).
Parfois, une fonction dans un tel pipeline nécessite un seul argument , mais la fonction immédiatement en amont de celle-ci renvoie deux valeurs .
Dans ce scénario, functools.partial
peut vous permettre de conserver ce pipeline de fonctions intact.
Voici un exemple spécifique et isolé: supposons que vous souhaitiez trier certaines données en fonction de la distance de chaque point de données par rapport à une cible:
# 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)
Pour trier ces données en fonction de la distance de la cible, ce que vous voudriez bien sûr faire est ceci:
data.sort(key=euclid_dist)
mais vous ne pouvez pas - le paramètre clé de la méthode de tri n'accepte que les fonctions qui prennent un seul argument.
alors réécrivez euclid_dist
comme une fonction prenant un seul paramètre:
from functools import partial
p_euclid_dist = partial(euclid_dist, target)
p_euclid_dist
accepte désormais un seul argument,
>>> p_euclid_dist((3, 3))
1.4142135623730951
vous pouvez maintenant trier vos données en passant la fonction partielle pour l'argument clé de la méthode de tri:
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 par exemple, l'un des arguments de la fonction change dans une boucle externe mais est fixé lors de l'itération dans la boucle interne. En utilisant un partiel, vous n'avez pas à passer le paramètre supplémentaire lors de l'itération de la boucle interne, car la fonction modifiée (partielle) n'en a pas besoin.
>>> from functools import partial
>>> def fnx(a, b, c):
return a + b + c
>>> fnx(3, 4, 5)
12
créer une fonction partielle (en utilisant le mot-clé arg)
>>> pfnx = partial(fnx, a=12)
>>> pfnx(b=4, c=5)
21
vous pouvez également créer une fonction partielle avec un argument positionnel
>>> pfnx = partial(fnx, 12)
>>> pfnx(4, 5)
21
mais cela lancera (par exemple, créer un partiel avec un argument mot-clé puis appeler en utilisant des arguments positionnels)
>>> 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'
un autre cas d'utilisation: écrire du code distribué en utilisant la multiprocessing
bibliothèque de python . Un pool de processus est créé à l'aide de la méthode Pool:
>>> import multiprocessing as MP
>>> # create a process pool:
>>> ppool = MP.Pool()
Pool
a une méthode de carte, mais cela ne prend qu'un seul itérable, donc si vous avez besoin de passer une fonction avec une liste de paramètres plus longue, redéfinissez la fonction comme partielle, pour corriger tout sauf un:
>>> ppool.map(pfnx, [4, 6, 7, 8])
extra_args
variable