अधिक बेहतर: लंबोदर फ़ंक्शन या नेस्टेड फ़ंक्शन ( def
)?
एक नियमित कार्य पर एक लैम्ब्डा का उपयोग करने का एक फायदा है: वे एक अभिव्यक्ति में निर्मित होते हैं।
कई कमियां हैं:
- कोई नाम नहीं (बस
'<lambda>'
)
- कोई रोक-टोक नहीं
- कोई टिप्पणी नहीं
- कोई जटिल कथन नहीं
वे दोनों एक ही प्रकार की वस्तु भी हैं। उन कारणों के लिए, मैं आमतौर पर def
लैम्बदास के बजाय कीवर्ड के साथ फ़ंक्शन बनाना पसंद करता हूं ।
पहला बिंदु - वे एक ही प्रकार की वस्तु हैं
एक लंबोदर एक नियमित कार्य के रूप में एक ही प्रकार की वस्तु में परिणाम करता है
>>> l = lambda: 0
>>> type(l)
<class 'function'>
>>> def foo(): return 0
...
>>> type(foo)
<class 'function'>
>>> type(foo) is type(l)
True
चूंकि लंबोदर कार्य हैं, वे प्रथम श्रेणी की वस्तुएं हैं।
लंबोदर और कार्य दोनों:
- एक तर्क के रूप में चारों ओर पारित किया जा सकता है (एक नियमित कार्य के रूप में)
- जब किसी बाहरी फ़ंक्शन के भीतर बनाया जाता है, तो उस बाहरी फ़ंक्शन के स्थानीय लोगों पर एक बंद हो जाता है
लेकिन लैम्ब्डा डिफ़ॉल्ट रूप से, फंक्शन फंक्शन डेफिनेशन सिंटैक्स के माध्यम से मिलने वाली कुछ चीजों को मिस कर रहे हैं।
एक लांबा का __name__
है'<lambda>'
लैम्ब्डा अनाम कार्य हैं, आखिरकार, इसलिए वे अपना नाम नहीं जानते हैं।
>>> l.__name__
'<lambda>'
>>> foo.__name__
'foo'
इस प्रकार लैम्ब्डा को उनके नामस्थान में प्रोग्रामेटिक रूप से नहीं देखा जा सकता है।
यह कुछ चीजों को सीमित करता है। उदाहरण के लिए, foo
क्रमबद्ध कोड के साथ देखा जा सकता है, जबकि l
नहीं:
>>> 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
बस ठीक लग सकते हैं - क्योंकि यह अपना नाम जानता है:
>>> pickle.loads(pickle.dumps(foo))
<function foo at 0x7fbbbee79268>
लैम्ब्डा के पास कोई एनोटेशन नहीं है और न ही डॉकस्ट्रिंग है
असल में, लंबोदर का दस्तावेजीकरण नहीं किया गया है। आइए foo
बेहतर दस्तावेज होने के लिए फिर से लिखें :
def foo() -> int:
"""a nullary function, returns 0 every time"""
return 0
अब, फू में प्रलेखन है:
>>> foo.__annotations__
{'return': <class 'int'>}
>>> help(foo)
Help on function foo in module __main__:
foo() -> int
a nullary function, returns 0 every time
जबकि, हमारे पास लंबोदर को समान जानकारी देने के लिए समान तंत्र नहीं है:
>>> help(l)
Help on function <lambda> in module __main__:
<lambda> lambda (...)
लेकिन हम उन्हें हैक कर सकते हैं:
>>> l.__doc__ = 'nullary -> 0'
>>> l.__annotations__ = {'return': int}
>>> help(l)
Help on function <lambda> in module __main__:
<lambda> lambda ) -> in
nullary -> 0
हालांकि, मदद के आउटपुट को गड़बड़ाने वाली कुछ त्रुटि है, हालांकि।
लैम्ब्डा केवल एक अभिव्यक्ति वापस कर सकते हैं
लैम्ब्डा जटिल बयान नहीं लौटा सकती, केवल अभिव्यक्ति।
>>> lambda: if True: 0
File "<stdin>", line 1
lambda: if True: 0
^
SyntaxError: invalid syntax
अभिव्यक्तियाँ जटिल रूप से जटिल हो सकती हैं, और यदि आप बहुत कठिन प्रयास करते हैं तो आप शायद एक लंबोदर के साथ ही पूरा कर सकते हैं, लेकिन जोड़ा जटिलता स्पष्ट कोड लिखने के लिए एक बाधा है।
हम स्पष्टता और स्थिरता के लिए पायथन का उपयोग करते हैं। लैम्ब्डा का अति प्रयोग उस के खिलाफ काम कर सकता है।
केवल lambdas के लिए ऊपर: एक ही अभिव्यक्ति में बनाया जा सकता है
यह केवल संभव उल्टा है। चूंकि आप एक अभिव्यक्ति के साथ एक लैम्ब्डा बना सकते हैं, आप इसे एक फ़ंक्शन कॉल के अंदर बना सकते हैं।
एक फंक्शन कॉल के अंदर एक फंक्शन बनाना (सस्ती) नाम देखने से बचता है।
हालाँकि, चूंकि पायथन का कड़ाई से मूल्यांकन किया जाता है, इसलिए नाम देखने से बचने के अलावा ऐसा करने के लिए कोई अन्य प्रदर्शन लाभ नहीं है।
एक बहुत ही सरल अभिव्यक्ति के लिए, मैं एक मेमना चुन सकता हूं।
मैं इंटरैक्टिव पाइथन करते समय लैंबडास का उपयोग करने के लिए भी करता हूं, जब कोई भी कई लाइनों से बचने के लिए करेगा। जब मैं किसी रचनाकार से किसी तर्क में पास होना चाहता हूं तो मैं निम्नलिखित प्रकार के कोड प्रारूप का उपयोग करता हूं 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
और अब:
>>> min(timeit.repeat(lambda: return_nullary_lambda(1)))
0.24312214995734394
>>> min(timeit.repeat(lambda: return_nullary_function(1)))
0.24894469301216304
मेरा मानना है कि ऊपर दिए गए मामूली समय के अंतर को नाम देखने के लिए जिम्मेदार ठहराया जा सकता है return_nullary_function
- ध्यान दें कि यह बहुत ही नगण्य है।
निष्कर्ष
लैंबडस अनौपचारिक स्थितियों के लिए अच्छा है जहां आप एक विलक्षण बिंदु बनाने के पक्ष में कोड की पंक्तियों को कम करना चाहते हैं।
अधिक औपचारिक स्थितियों के लिए लैम्ब्डा खराब होते हैं जहां आपको कोड के संपादकों के लिए स्पष्टता की आवश्यकता होती है जो बाद में आएंगे, खासकर उन मामलों में जहां वे गैर-तुच्छ हैं।
हम जानते हैं कि हम अपनी वस्तुओं को अच्छे नाम देने वाले हैं। जब वस्तु नहीं है तो हम ऐसा कैसे कर सकते हैं नाम ?
इन सभी कारणों के लिए, मैं आम तौर पर के def
बजाय के साथ कार्य बनाने के लिए पसंद करते हैं lambda
।
lambda
, लेकिन मैं असहमत हूं कि यह "बहुत दुर्लभ" है, यह महत्वपूर्ण कार्यों के लिएsorted
याitertools.groupby
आदि के लिए आम है , उदाहरण के लिएsorted(['a1', 'b0'], key= lambda x: int(x[1]))