Lebih disukai: fungsi lambda atau fungsi bersarang ( def
)?
Ada satu keuntungan menggunakan lambda dibandingkan fungsi reguler: fungsi tersebut dibuat dalam ekspresi.
Ada beberapa kekurangan:
- tidak ada nama (hanya
'<lambda>'
)
- tidak ada dokumen
- tidak ada penjelasan
- tidak ada pernyataan yang rumit
Keduanya juga merupakan jenis objek yang sama. Untuk alasan tersebut, saya biasanya lebih suka membuat fungsi dengan def
kata kunci daripada dengan lambda.
Poin pertama - mereka adalah tipe objek yang sama
Sebuah lambda menghasilkan tipe objek yang sama dengan fungsi biasa
>>> l = lambda: 0
>>> type(l)
<class 'function'>
>>> def foo(): return 0
...
>>> type(foo)
<class 'function'>
>>> type(foo) is type(l)
True
Karena lambda adalah fungsi, mereka adalah objek kelas satu.
Baik lambda dan fungsi:
- dapat diedarkan sebagai argumen (sama seperti fungsi biasa)
- ketika dibuat dalam fungsi luar menjadi penutupan atas lokal fungsi luar itu
Tetapi lambda, secara default, kehilangan beberapa hal yang didapat fungsi melalui sintaks definisi fungsi penuh.
Lamba __name__
adalah'<lambda>'
Lambda adalah fungsi anonim, jadi mereka tidak tahu namanya sendiri.
>>> l.__name__
'<lambda>'
>>> foo.__name__
'foo'
Jadi lambda's tidak dapat dicari secara terprogram di namespace mereka.
Ini membatasi hal-hal tertentu. Misalnya, foo
dapat dicari dengan kode serial, sementara l
tidak bisa:
>>> import pickle
>>> pickle.loads(pickle.dumps(l))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <function <lambda> at 0x7fbbc0464e18>:
attribute lookup <lambda> on __main__ failed
Kita dapat mencari dengan foo
baik - karena mengetahui namanya sendiri:
>>> pickle.loads(pickle.dumps(foo))
<function foo at 0x7fbbbee79268>
Lambdas tidak memiliki anotasi dan tidak ada docstring
Pada dasarnya, lambda tidak didokumentasikan. Mari menulis ulang foo
agar terdokumentasi lebih baik:
def foo() -> int:
"""a nullary function, returns 0 every time"""
return 0
Sekarang, foo memiliki dokumentasi:
>>> foo.__annotations__
{'return': <class 'int'>}
>>> help(foo)
Help on function foo in module __main__:
foo() -> int
a nullary function, returns 0 every time
Padahal, kami tidak memiliki mekanisme yang sama untuk memberikan informasi yang sama ke lambda:
>>> help(l)
Help on function <lambda> in module __main__:
<lambda> lambda (...)
Tapi kita bisa meretasnya:
>>> l.__doc__ = 'nullary -> 0'
>>> l.__annotations__ = {'return': int}
>>> help(l)
Help on function <lambda> in module __main__:
<lambda> lambda ) -> in
nullary -> 0
Tapi mungkin ada beberapa kesalahan yang mengacaukan hasil bantuan.
Lambdas hanya bisa mengembalikan ekspresi
Lambdas tidak bisa mengembalikan pernyataan kompleks, hanya ekspresi.
>>> lambda: if True: 0
File "<stdin>", line 1
lambda: if True: 0
^
SyntaxError: invalid syntax
Ekspresi memang bisa jadi agak rumit, dan jika Anda berusaha sangat keras, Anda mungkin dapat mencapai hal yang sama dengan lambda, tetapi kerumitan yang ditambahkan lebih merugikan penulisan kode yang jelas.
Kami menggunakan Python untuk kejelasan dan pemeliharaan. Penggunaan lambda yang berlebihan bisa melawan itu.
Satu- satunya keuntungan lambda: bisa dibuat dalam satu ekspresi
Ini adalah satu-satunya kemungkinan kenaikan. Karena Anda dapat membuat lambda dengan ekspresi, Anda dapat membuatnya di dalam pemanggilan fungsi.
Membuat fungsi di dalam panggilan fungsi menghindari pencarian nama (murah) versus yang dibuat di tempat lain.
Namun, karena Python dievaluasi secara ketat, tidak ada perolehan performa lain selain menghindari pencarian nama.
Untuk ekspresi yang sangat sederhana, saya mungkin memilih lambda.
Saya juga cenderung menggunakan lambda saat melakukan Python interaktif, untuk menghindari banyak baris saat seseorang melakukannya. Saya menggunakan jenis format kode berikut ketika saya ingin meneruskan argumen ke konstruktor saat memanggil timeit.repeat
:
import timeit
def return_nullary_lambda(return_value=0):
return lambda: return_value
def return_nullary_function(return_value=0):
def nullary_fn():
return return_value
return nullary_fn
Dan sekarang:
>>> min(timeit.repeat(lambda: return_nullary_lambda(1)))
0.24312214995734394
>>> min(timeit.repeat(lambda: return_nullary_function(1)))
0.24894469301216304
Saya percaya sedikit perbedaan waktu di atas dapat dikaitkan dengan pencarian nama di return_nullary_function
- perhatikan bahwa itu sangat dapat diabaikan.
Kesimpulan
Lambda bagus untuk situasi informal di mana Anda ingin meminimalkan baris kode untuk membuat titik tunggal.
Lambda buruk untuk situasi yang lebih formal di mana Anda memerlukan kejelasan untuk editor kode yang akan datang nanti, terutama dalam kasus di mana mereka tidak sepele.
Kami tahu kami harus memberikan nama yang baik pada objek kami. Bagaimana kita bisa melakukannya jika objek tidak memiliki nama?
Untuk semua alasan ini, saya biasanya lebih suka membuat fungsi dengan def
daripada dengan lambda
.
lambda
, tapi saya tidak setuju bahwa ini "sangat jarang", ini umum untuk fungsi tombolsorted
atauitertools.groupby
dll., Misalnyasorted(['a1', 'b0'], key= lambda x: int(x[1]))