Daha çok tercih edilen: lambda işlevleri mi yoksa yuvalanmış işlevler ( def
) mi?
Normal bir işleve göre bir lambda kullanmanın bir avantajı vardır: bir ifadede yaratılırlar.
Birkaç dezavantaj var:
- isim yok (sadece
'<lambda>'
)
- belge yok
- ek açıklama yok
- karmaşık ifade yok
Ayrıca ikisi de aynı tür nesnedir. Bu nedenlerden dolayı, genellikle def
lambdas yerine anahtar kelimeyle işlevler oluşturmayı tercih ederim .
İlk nokta - bunlar aynı tür nesneler
Bir lambda, normal bir işlevle aynı türde nesne ile sonuçlanır
>>> l = lambda: 0
>>> type(l)
<class 'function'>
>>> def foo(): return 0
...
>>> type(foo)
<class 'function'>
>>> type(foo) is type(l)
True
Lambdalar işlev olduklarından birinci sınıf nesnelerdir.
Hem lambdalar hem de işlevler:
- bir argüman olarak aktarılabilir (normal bir fonksiyonla aynı)
- bir dış işlev içinde oluşturulduğunda, bu dış işlevlerin yerelleri üzerinde bir kapanış haline gelir
Ancak lambdalar, varsayılan olarak, işlevlerin tam işlev tanımı sözdizimi yoluyla elde ettiği bazı şeyleri kaçırır.
Bir Lamba adlı __name__
is'<lambda>'
Sonuçta Lambdalar anonim işlevlerdir, bu nedenle kendi adlarını bilmiyorlar.
>>> l.__name__
'<lambda>'
>>> foo.__name__
'foo'
Böylece, lambda'lar ad alanlarında programlı olarak aranamaz.
Bu, belirli şeyleri sınırlar. Örneğin, foo
serileştirilmiş kodla aranabilir, ancak şunlar l
yapılamaz:
>>> 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
foo
Gayet iyi arayabiliriz - çünkü kendi adını biliyor:
>>> pickle.loads(pickle.dumps(foo))
<function foo at 0x7fbbbee79268>
Lambdaların ek açıklaması ve belge dizesi yoktur
Temel olarak, lambdalar belgelenmemiştir. foo
Daha iyi belgelenmek için yeniden yazalım :
def foo() -> int:
"""a nullary function, returns 0 every time"""
return 0
Şimdi, foo'nun belgeleri var:
>>> foo.__annotations__
{'return': <class 'int'>}
>>> help(foo)
Help on function foo in module __main__:
foo() -> int
a nullary function, returns 0 every time
Oysa aynı bilgiyi lambdalara vermek için aynı mekanizmaya sahip değiliz:
>>> help(l)
Help on function <lambda> in module __main__:
<lambda> lambda (...)
Ama onları hackleyebiliriz:
>>> l.__doc__ = 'nullary -> 0'
>>> l.__annotations__ = {'return': int}
>>> help(l)
Help on function <lambda> in module __main__:
<lambda> lambda ) -> in
nullary -> 0
Ancak muhtemelen yardımın çıktısını bozan bazı hatalar vardır.
Lambdas yalnızca bir ifade döndürebilir
Lambdas karmaşık ifadeler döndüremez, yalnızca ifadeler.
>>> lambda: if True: 0
File "<stdin>", line 1
lambda: if True: 0
^
SyntaxError: invalid syntax
İfadeler kuşkusuz oldukça karmaşık olabilir ve çok çabalarsanız, muhtemelen aynısını bir lambda ile de başarabilirsiniz, ancak eklenen karmaşıklık, açık kod yazmaya daha çok zarar verir.
Netlik ve sürdürülebilirlik için Python kullanıyoruz. Lambdaların aşırı kullanımı buna karşı çalışabilir.
Sadece lambdas için baş: Tek bir ifadede oluşturulabilir
Bu mümkün olan tek olumlu yöndür. İfade ile bir lambda yaratabildiğiniz için, onu bir fonksiyon çağrısı içinde yaratabilirsiniz.
Bir işlev çağrısı içinde bir işlev oluşturmak, başka bir yerde oluşturulan ad aramasına karşı (ucuz) ad aramasını önler.
Bununla birlikte, Python katı bir şekilde değerlendirildiğinden, bunu yapmanın ad aramasından kaçınmanın dışında başka bir performans kazanımı yoktur.
Çok basit bir ifade için bir lambda seçebilirim.
Ayrıca etkileşimli Python yaparken, biri yapacağı zaman birden fazla satırdan kaçınmak için lambdas kullanma eğilimindeyim. Çağırırken bir yapıcıya bir bağımsız değişken geçirmek istediğimde aşağıdaki kod biçimini kullanıyorum 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
Ve şimdi:
>>> min(timeit.repeat(lambda: return_nullary_lambda(1)))
0.24312214995734394
>>> min(timeit.repeat(lambda: return_nullary_function(1)))
0.24894469301216304
Yukarıdaki küçük zaman farkının, isim aramasına atfedilebileceğine inanıyorum return_nullary_function
- çok önemsiz olduğunu unutmayın .
Sonuç
Lambdalar, tek bir noktaya değinmek için kod satırlarını en aza indirmek istediğiniz gayri resmi durumlar için iyidir.
Lambdalar, özellikle önemsiz olmadıkları durumlarda, daha sonra gelecek olan kod editörleri için açıklığa ihtiyaç duyduğunuz daha resmi durumlar için kötüdür.
Nesnelerimize güzel isimler vermemiz gerektiğini biliyoruz. Nesne sahip olduğunda nasıl bunu yapabilirler hiçbir ad?
Tüm bu nedenlerden dolayı genellikle with def
yerine ile işlevler oluşturmayı tercih ediyorum lambda
.
lambda
, ama bu "çok nadir" olduğunu katılmıyorum, bu anahtar fonksiyonları için yaygındırsorted
yaitertools.groupby
vs. meselasorted(['a1', 'b0'], key= lambda x: int(x[1]))