partials là vô cùng hữu ích.
Chẳng hạn, trong một chuỗi các lệnh gọi hàm 'được xếp thành ống' (trong đó giá trị được trả về từ một hàm là đối số được truyền cho hàm tiếp theo).
Đôi khi một hàm trong một đường ống như vậy đòi hỏi một đối số duy nhất , nhưng hàm ngay lập tức ngược dòng từ nó trả về hai giá trị .
Trong trường hợp này, functools.partial
có thể cho phép bạn giữ nguyên đường ống chức năng này.
Đây là một ví dụ cụ thể, riêng biệt: giả sử bạn muốn sắp xếp một số dữ liệu theo khoảng cách của từng điểm dữ liệu từ một số mục tiêu:
# 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)
Để sắp xếp dữ liệu này theo khoảng cách từ mục tiêu, tất nhiên những gì bạn muốn làm là:
data.sort(key=euclid_dist)
nhưng bạn không thể - tham số khóa của phương thức sắp xếp chỉ chấp nhận các hàm có một đối số duy nhất .
nên viết lại euclid_dist
như một chức năng tham gia một đơn tham số:
from functools import partial
p_euclid_dist = partial(euclid_dist, target)
p_euclid_dist
bây giờ chấp nhận một đối số duy nhất,
>>> p_euclid_dist((3, 3))
1.4142135623730951
vì vậy bây giờ bạn có thể sắp xếp dữ liệu của mình bằng cách chuyển vào hàm một phần cho đối số khóa của phương thức sắp xếp:
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
Hoặc ví dụ, một trong các đối số của hàm thay đổi trong một vòng lặp bên ngoài nhưng được cố định trong quá trình lặp trong vòng lặp bên trong. Bằng cách sử dụng một phần, bạn không phải truyền tham số bổ sung trong quá trình lặp của vòng lặp bên trong, bởi vì hàm (một phần) đã sửa đổi không yêu cầu nó.
>>> from functools import partial
>>> def fnx(a, b, c):
return a + b + c
>>> fnx(3, 4, 5)
12
tạo một phần chức năng (sử dụng từ khóa arg)
>>> pfnx = partial(fnx, a=12)
>>> pfnx(b=4, c=5)
21
bạn cũng có thể tạo một hàm một phần với một đối số vị trí
>>> pfnx = partial(fnx, 12)
>>> pfnx(4, 5)
21
nhưng điều này sẽ ném (ví dụ: tạo một phần với đối số từ khóa sau đó gọi bằng cách sử dụng đối số vị trí)
>>> 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'
trường hợp sử dụng khác: viết mã phân tán bằng multiprocessing
thư viện của python . Nhóm quy trình được tạo bằng phương thức Pool:
>>> import multiprocessing as MP
>>> # create a process pool:
>>> ppool = MP.Pool()
Pool
có một phương thức bản đồ, nhưng nó chỉ mất một lần lặp duy nhất, vì vậy nếu bạn cần truyền vào một hàm có danh sách tham số dài hơn, hãy xác định lại hàm là một phần, để sửa tất cả trừ một:
>>> ppool.map(pfnx, [4, 6, 7, 8])
extra_args
biến từ đâu