Secara kasar, partial
lakukan sesuatu seperti ini (terlepas dari dukungan kata kunci args, dll.):
def partial(func, *part_args):
def wrapper(*extra_args):
args = list(part_args)
args.extend(extra_args)
return func(*args)
return wrapper
Jadi, dengan menelepon partial(sum2, 4)
Anda membuat fungsi baru (yang bisa dipanggil, tepatnya) yang berperilaku seperti sum2
, tetapi memiliki satu argumen posisi kurang. Argumen yang hilang selalu diganti oleh 4
, sehinggapartial(sum2, 4)(2) == sum2(4, 2)
Adapun mengapa itu diperlukan, ada berbagai kasus. Hanya untuk satu, misalkan Anda harus melewati fungsi di suatu tempat di mana ia diharapkan memiliki 2 argumen:
class EventNotifier(object):
def __init__(self):
self._listeners = []
def add_listener(self, callback):
''' callback should accept two positional arguments, event and params '''
self._listeners.append(callback)
# ...
def notify(self, event, *params):
for f in self._listeners:
f(event, params)
Tetapi fungsi yang sudah Anda miliki membutuhkan akses ke context
objek ketiga untuk melakukan tugasnya:
def log_event(context, event, params):
context.log_event("Something happened %s, %s", event, params)
Jadi, ada beberapa solusi:
Objek khusus:
class Listener(object):
def __init__(self, context):
self._context = context
def __call__(self, event, params):
self._context.log_event("Something happened %s, %s", event, params)
notifier.add_listener(Listener(context))
Lambda:
log_listener = lambda event, params: log_event(context, event, params)
notifier.add_listener(log_listener)
Dengan parsial:
context = get_context() # whatever
notifier.add_listener(partial(log_event, context))
Dari ketiganya, partial
adalah yang terpendek dan tercepat. (Untuk kasus yang lebih kompleks, Anda mungkin menginginkan objek khusus).
extra_args
variabelextra_args
adalah sesuatu yang disahkan oleh penelepon parsial, dalam contoh denganp = partial(func, 1); f(2, 3, 4)
itu(2, 3, 4)
.callback
danmy_callback
parsial sangat berguna.
Misalnya, dalam urutan pemanggilan fungsi 'pipa-baris' (di mana nilai yang dikembalikan dari satu fungsi adalah argumen yang diteruskan ke yang berikutnya).
Kadang-kadang fungsi dalam pipa seperti itu membutuhkan argumen tunggal , tetapi fungsi segera hulu dari itu mengembalikan dua nilai .
Dalam skenario ini,
functools.partial
mungkin memungkinkan Anda untuk menjaga fungsi pipeline fungsi ini.Berikut adalah contoh khusus dan terisolasi: misalkan Anda ingin mengurutkan beberapa data berdasarkan jarak setiap titik data dari beberapa target:
Untuk mengurutkan data ini berdasarkan jarak dari target, apa yang ingin Anda lakukan tentu saja adalah ini:
tetapi Anda tidak bisa - parameter kunci metode sortir hanya menerima fungsi yang mengambil satu argumen.
jadi tulis ulang
euclid_dist
sebagai fungsi yang mengambil parameter tunggal :p_euclid_dist
sekarang menerima satu argumen,jadi sekarang Anda dapat mengurutkan data Anda dengan mengirimkan fungsi parsial untuk argumen kunci metode sortir:
Atau misalnya, salah satu argumen fungsi berubah di loop luar tetapi diperbaiki selama iterasi di loop dalam. Dengan menggunakan parsial, Anda tidak harus meneruskan parameter tambahan selama iterasi loop dalam, karena fungsi yang dimodifikasi (parsial) tidak memerlukannya.
buat fungsi parsial (menggunakan kata kunci arg)
Anda juga dapat membuat fungsi parsial dengan argumen posisi
tetapi ini akan melempar (mis., membuat sebagian dengan argumen kata kunci lalu memanggil menggunakan argumen posisional)
kasus penggunaan lain: menulis kode terdistribusi menggunakan
multiprocessing
pustaka python . Kumpulan proses dibuat menggunakan metode Pool:Pool
memiliki metode peta, tetapi hanya membutuhkan satu iterable, jadi jika Anda harus meneruskan fungsi dengan daftar parameter yang lebih panjang, tentukan kembali fungsi sebagai parsial, untuk memperbaiki semua kecuali satu:sumber
jawaban singkat,
partial
memberikan nilai default ke parameter fungsi yang seharusnya tidak memiliki nilai default.sumber
partial
Partial dapat digunakan untuk membuat fungsi turunan baru yang memiliki beberapa parameter input yang ditugaskan sebelumnya
Untuk melihat beberapa penggunaan parsial di dunia nyata, lihat posting blog yang sangat bagus ini:
http://chriskiehl.com/article/Cleaner-coding-through-partially-applied-functions/
Sebuah sederhana tetapi contoh rapi pemula dari blog, selimut bagaimana seseorang dapat menggunakan
partial
padare.search
untuk membuat kode lebih mudah dibaca.re.search
tanda tangan metode adalah:Dengan menerapkan,
partial
kami dapat membuat beberapa versi ekspresi reguler yangsearch
sesuai dengan persyaratan kami, jadi misalnya:Sekarang
is_spaced_apart
danis_grouped_together
dua fungsi baru yang berasal darire.search
yang memilikipattern
argumen diterapkan (karenapattern
merupakan argumen pertama dalamre.search
metode tanda tangan ini).Tanda tangan dari dua fungsi baru ini (dapat dipanggil) adalah:
Ini adalah bagaimana Anda kemudian dapat menggunakan fungsi parsial ini pada beberapa teks:
Anda dapat merujuk tautan di atas untuk mendapatkan pemahaman yang lebih mendalam tentang subjek, karena mencakup contoh spesifik ini dan banyak lagi ..
sumber
is_spaced_apart = re.compile('[a-zA-Z]\s\=').search
? Jika demikian, apakah ada jaminan bahwapartial
idiom mengkompilasi ekspresi reguler untuk digunakan kembali lebih cepat?Menurut pendapat saya, ini adalah cara untuk menerapkan currying dengan python.
Hasilnya adalah 3 dan 4.
sumber
Juga perlu disebutkan, bahwa ketika fungsi parsial melewati fungsi lain di mana kita ingin "kode keras" beberapa parameter, itu harus menjadi parameter paling kanan
tetapi jika kita melakukan hal yang sama, tetapi mengubah suatu parameter sebagai gantinya
itu akan melempar kesalahan, "TypeError: func () mendapat beberapa nilai untuk argumen 'a'"
sumber
prt=partial(func, 7)
Jawaban ini lebih merupakan contoh kode. Semua jawaban di atas memberikan penjelasan yang baik tentang mengapa seseorang harus menggunakan sebagian. Saya akan memberikan pengamatan saya dan menggunakan kasus tentang parsial.
Output dari kode di atas harus:
Perhatikan bahwa dalam contoh di atas dikembalikan callable baru yang akan mengambil parameter (c) sebagai argumennya. Perhatikan bahwa ini juga argumen terakhir untuk fungsi.
Output dari kode di atas juga:
Perhatikan bahwa * digunakan untuk membongkar argumen non-kata kunci dan callable yang dikembalikan dengan argumen yang dapat diambil sama dengan di atas.
Pengamatan lain adalah: Contoh di bawah ini menunjukkan bahwa sebagian mengembalikan callable yang akan mengambil parameter yang tidak dideklarasikan (a) sebagai argumen.
Output dari kode di atas harus:
Demikian pula,
Cetak kode di atas
Saya harus menggunakannya ketika saya menggunakan
Pool.map_async
metode darimultiprocessing
modul. Anda hanya dapat mengirimkan satu argumen ke fungsi pekerja sehingga saya harus menggunakanpartial
untuk membuat fungsi pekerja saya tampak seperti dapat dipanggil dengan hanya satu argumen input tetapi pada kenyataannya fungsi pekerja saya memiliki beberapa argumen input.sumber