कौन सा उपयोग करने के लिए अधिक बेहतर है: लैम्ब्डा फ़ंक्शन या नेस्टेड फ़ंक्शंस ('डीफ़')?


101

मैं ज्यादातर लैम्ब्डा कार्यों का उपयोग करता हूं लेकिन कभी-कभी नेस्टेड फ़ंक्शन का उपयोग करता हूं जो समान व्यवहार प्रदान करते हैं।

यहां कुछ तुच्छ उदाहरण हैं जहां वे कार्यात्मक रूप से एक ही कार्य करते हैं यदि या तो किसी अन्य फ़ंक्शन के भीतर पाए गए थे:

लंबोदर समारोह

>>> a = lambda x : 1 + x
>>> a(5)
6

नेस्टेड फंक्शन

>>> def b(x): return 1 + x

>>> b(5)
6

क्या एक के बाद एक का उपयोग करने के फायदे हैं? (प्रदर्शन? पठनीयता? सीमाएँ? संगति?)

क्या इससे भी फर्क पड़ता है? यदि ऐसा नहीं होता है तो वह पायथन सिद्धांत का उल्लंघन करता है:

वहाँ एक होना चाहिए और अधिमानतः यह करने के लिए केवल एक ही स्पष्ट तरीका है

जवाबों:


105

यदि आपको lambdaएक नाम निर्दिष्ट करने की आवश्यकता है , तो defइसके बजाय उपयोग करें । defs एक नियत कार्य के लिए मात्र संश्लिष्ट चीनी हैं, इसलिए परिणाम समान है, और वे बहुत अधिक लचीले और पठनीय हैं।

lambdas का उपयोग एक बार उपयोग करने के लिए किया जा सकता है , ऐसे कार्यों को फेंक दें जिनका कोई नाम नहीं होगा।

हालांकि, यह उपयोग मामला बहुत दुर्लभ है। अनाम फ़ंक्शन ऑब्जेक्ट्स के लिए आपको शायद ही कभी पास होने की आवश्यकता होती है।

बिल्डिन्स map()और filter()फ़ंक्शन ऑब्जेक्ट्स की आवश्यकता होती है, लेकिन सूची समझ और जनरेटर के भाव आम तौर पर उन कार्यों की तुलना में अधिक पठनीय होते हैं और सभी उपयोग के मामलों को कवर कर सकते हैं, लैम्बदास की आवश्यकता के बिना।

उन मामलों के लिए जिन्हें आपको वास्तव में एक छोटी फ़ंक्शन ऑब्जेक्ट की आवश्यकता है, आपको इसके बजाय operatorमॉड्यूल फ़ंक्शन का उपयोग करना चाहिएoperator.addlambda x, y: x + y

यदि आपको अभी भी कुछ lambdaकवर करने की आवश्यकता है , तो आप लिखने पर विचार कर सकते हैं def, बस अधिक पठनीय होने के लिए। यदि फ़ंक्शन operatorमॉड्यूल की तुलना में अधिक जटिल है , तो एdef शायद बेहतर है।

तो, वास्तविक दुनिया के अच्छे lambdaउपयोग के मामले बहुत दुर्लभ हैं।


9
जब उपयोग करने के लिए उत्तर के साथ मैं सहमत हूं lambda, लेकिन मैं असहमत हूं कि यह "बहुत दुर्लभ" है, यह महत्वपूर्ण कार्यों के लिए sortedया itertools.groupbyआदि के लिए आम है , उदाहरण के लिएsorted(['a1', 'b0'], key= lambda x: int(x[1]))
Chris_Rands

30

व्यावहारिक रूप से, मेरे लिए दो अंतर हैं:

पहला इस बारे में है कि वे क्या करते हैं और वे क्या लौटाते हैं:

  • def एक ऐसा कीवर्ड है जो कुछ भी वापस नहीं करता है और स्थानीय नामस्थान में एक 'नाम' बनाता है।

  • लैम्ब्डा एक कीवर्ड है जो एक फंक्शन ऑब्जेक्ट देता है और स्थानीय नेमस्पेस में 'नाम' नहीं बनाता है।

इसलिए, यदि आपको किसी फ़ंक्शन ऑब्जेक्ट को कॉल करने की आवश्यकता है, तो अजगर कोड की एक पंक्ति में ऐसा करने का एकमात्र तरीका एक लंबोदर के साथ है। डिफ के साथ कोई समकक्ष नहीं है।

कुछ रूपरेखाओं में यह वास्तव में काफी सामान्य है; उदाहरण के लिए, मैं ट्विस्टेड का उपयोग करता हूं , और इसलिए कुछ ऐसा कर रहा हूं

d.addCallback(lambda result: setattr(self, _someVariable, result))

लैम्बदास के साथ काफी आम है, और अधिक संक्षिप्त है।

दूसरा अंतर यह है कि वास्तविक कार्य को करने की अनुमति क्या है।

  • 'डिफ' से परिभाषित एक फ़ंक्शन में किसी भी अजगर कोड हो सकता है
  • 'लैम्ब्डा' के साथ परिभाषित एक फ़ंक्शन को एक अभिव्यक्ति का मूल्यांकन करना है, और इस तरह प्रिंट, आयात, उठाना, जैसे बयान शामिल नहीं हो सकते ...

उदाहरण के लिए,

def p(x): print x

जबकि उम्मीद के मुताबिक काम करता है

lambda x: print x

एक वाक्य रचना है।

बेशक, वर्कअराउंड हैं - के printसाथ sys.stdout.write, या के importसाथ स्थानापन्न __import__। लेकिन आमतौर पर आप उस मामले में एक समारोह में जाने से बेहतर होते हैं।


22

इस साक्षात्कार में, गुइडो वैन रोसुम का कहना है कि वह चाहता है कि वह अजगर में 'लैम्ब्डा' न आने दे:

" Q. पायथन की किस विशेषता से आप कम से कम प्रसन्न हैं?

कभी-कभी मैं योगदानों को स्वीकार करने में बहुत जल्दी हो गया हूं, और बाद में महसूस किया कि यह एक गलती थी। एक उदाहरण कार्यात्मक प्रोग्रामिंग विशेषताओं में से कुछ होगा, जैसे लैम्ब्डा फ़ंक्शन। लैम्ब्डा। एक ऐसा कीवर्ड है जो आपको एक छोटा अनाम फ़ंक्शन बनाने देता है, बिल्ट-इन फ़ंक्शंस जैसे नक्शा, फ़िल्टर, और अनुक्रम प्रकार से अधिक फ़ंक्शन को कम करने, जैसे कि सूची।

व्यवहार में, यह अच्छी तरह से नहीं निकला। पायथन में केवल दो स्कोप हैं: स्थानीय और वैश्विक। यह लिखने के लंबर कार्यों को दर्दनाक बनाता है, क्योंकि आप अक्सर उस दायरे में चर का उपयोग करना चाहते हैं जहां लंबो को परिभाषित किया गया था, लेकिन आप दो स्कोप के कारण नहीं कर सकते। इस के आसपास एक रास्ता है, लेकिन यह एक कीचड़ के बारे में कुछ है। अक्सर पैंथन में लाम्बा कार्यों के साथ खिलवाड़ करने के बजाय सिर्फ लूप के लिए उपयोग करना बहुत आसान लगता है। मानचित्र और मित्र केवल तभी काम करते हैं जब पहले से ही एक अंतर्निहित कार्य होता है जो आपको चाहिए।

IMHO, Iambdas कभी-कभी सुविधाजनक हो सकता है, लेकिन आमतौर पर पठनीयता की कीमत पर सुविधाजनक होता है। क्या आप मुझे बता सकते हैं कि यह क्या करता है:

str(reduce(lambda x,y:x+y,map(lambda x:x**x,range(1,1001))))[-10:]

मैंने इसे लिखा था, और मुझे यह पता लगाने में एक मिनट लगा। यह प्रोजेक्ट यूलर से है - मैं यह नहीं कहूंगा कि मुझे कौन सी समस्या है क्योंकि मैं स्पॉइलर से नफरत करता हूं, लेकिन यह 0.124 सेकंड में चलता है :)


20
ध्यान दें कि साक्षात्कार पुराना है, और पायथन लंबे समय से नेस्टेड स्कोप है, जो तर्क देता है कि वह लंबोदर के खिलाफ देता है जो अब प्रासंगिक नहीं है। मुझे यकीन है कि वह अभी भी लंबोदर से पछतावा करता है, लेकिन पाइथन 3.0 में इसे हटाने के लिए पर्याप्त नहीं है।
थॉमस वाउटर्स

10
वास्तव में आपका उदाहरण वन-लाइनर्स के खिलाफ एक तर्क होना चाहिए, न कि लंबदा। इसके अलावा, आपको लैम्बडा के साथ कम करने के बजाय बिल्ट-इन सम फ़ंक्शन का उपयोग करना चाहिए: str (योग (लैम्ब्डा x: x ** x, रेंज (1001)))] [: - 10]
ट्रिप्टिक

2
@ThomasWouters: मैं समझता हूं कि lambda3.0 में हटाया नहीं जाना एक निकट की बात थी, और यह कि गुइडो इसे रखने के लिए नहीं लड़ रहा था।
एथन फुरमान

11

N = 1000 के लिए यहाँ एक लम्बडा बनाम एक फ़ंक्शन को कॉल करने के कुछ समय है:

In [11]: def f(a, b):
             return a * b

In [12]: g = lambda x, y: x * y

In [13]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    f(a, b)
   ....:
100 loops, best of 3: 285 ms per loop

In [14]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    g(a, b)
   ....:
100 loops, best of 3: 298 ms per loop

In [15]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    (lambda x, y: x * y)(a, b)
   ....:
100 loops, best of 3: 462 ms per loop

3
यह देखना दिलचस्प है कि लैम्ब्डा और परिभाषित संस्करण लगभग बराबर हैं। अंतिम परीक्षण में अधिक समय लगा क्योंकि अजगर को शायद हर बार उस लैम्बडा फ़ंक्शन को परिभाषित करने वाले स्थान को आवंटित करने की आवश्यकता होती थी।
hlin117

मुझे लगता है कि यह समझ में आता है क्योंकि परिभाषा स्थानीय चर (जो परिवर्तित हो सकती है) का संदर्भ दे सकती है ... हालांकि इस मामले में जहां यह पसंद नहीं करता है, यहां पर cpython एक बेहतर काम कर सकता है।
एंडी हेडन

Dis.dis का उपयोग करें; आपका (lambda x, y: x * y) फंक्शन हर लूप बनाता है। यदि आप लम्बडा को लूप से पहले बनाते हैं (उर्फ f = लैंबडा x, y: x * y), फ़ंक्शन को कॉल करने के लिए बायटेकोड आपके पिछले उदाहरण में g / f जैसा ही होगा, इसलिए लैम्बडा का प्रदर्शन समान है एक समारोह के रूप में। तो लैम्ब्डा या डिफ के रूप में कोई प्रभाव नहीं अगर आप इसे एक ही उपयोग करते हैं। उलटा करें, लूप के भीतर f () फ़ंक्शन घोषित करें, फिर इसे कॉल करें ...
tito

@tito का मानना ​​है कि ठीक यही समय 3 उदाहरणों को प्रदर्शित करता है ...
एंडी हेडन

@tito ओह, आप लूप में फ़ंक्शन को परिभाषित कर रहे हैं, निश्चित रूप से, लेकिन मैं तर्क दूंगा कि यह एक असामान्य पैटर्न है। यकीन नहीं होता कि इसके लिए उस टिप्पणी की जरूरत क्यों पड़ी ...
एंडी हेडन

7

प्रदर्शन:

के साथ एक समारोह बनाने के साथ इसे बनाने की तुलना lambdaमें थोड़ा तेज है def। अंतर defस्थानीय लोगों की तालिका में नाम प्रविष्टि बनाने के कारण है । परिणामी फ़ंक्शन में एक ही निष्पादन की गति है।


पठनीयता:

अधिकांश पायथन उपयोगकर्ताओं के लिए लैम्ब्डा फ़ंक्शन कुछ कम पठनीय हैं, लेकिन कुछ परिस्थितियों में बहुत अधिक संक्षिप्त भी हैं। गैर-कार्यात्मक से कार्यात्मक दिनचर्या का उपयोग करने से परिवर्तित करने पर विचार करें:

# Using non-functional version.

heading(math.sqrt(v.x * v.x + v.y * v.y), math.atan(v.y / v.x))

# Using lambda with functional version.

fheading(v, lambda v: math.sqrt(v.x * v.x + v.y * v.y), lambda v: math.atan(v.y / v.x))

# Using def with functional version.

def size(v):
    return math.sqrt(v.x * v.x + v.y * v.y)

def direction(v):
    return math.atan(v.y / v.x)

deal_with_headings(v, size, direction)

जैसा कि आप देख सकते हैं, lambdaसंस्करण छोटा और "आसान" इस अर्थ में है कि आपको केवल lambda v:कार्यात्मक संस्करण में बदलने के लिए मूल गैर-कार्यात्मक संस्करण में जोड़ना होगा। यह बहुत अधिक संक्षिप्त है। लेकिन याद रखें, बहुत सारे पायथन उपयोगकर्ता लंबोदर सिंटैक्स द्वारा भ्रमित होंगे, इसलिए आप लंबाई में खो जाते हैं और वास्तविक जटिलता साथी कोडर्स से भ्रम में वापस प्राप्त हो सकती है।


सीमाएं:

  • lambda फ़ंक्शंस का उपयोग केवल एक बार किया जा सकता है, जब तक कि किसी चर नाम को न सौंपा जाए।
  • lambdaचर नामों को सौंपे गए कार्यों का फ़ंक्शंस पर कोई लाभ नहीं है def
  • lambda कार्यों को अचार करना मुश्किल या असंभव हो सकता है।
  • def कार्यों के नाम सावधानी से वर्णनात्मक और अद्वितीय या कम से कम अन्यथा गुंजाइश में अप्रयुक्त होने के लिए चुना जाना चाहिए।

संगति:

पायथन ज्यादातर प्रक्रियात्मक और सरल उद्देश्य शब्दार्थ के पक्ष में कार्यात्मक प्रोग्रामिंग सम्मेलनों से बचता है। lambdaऑपरेटर इस पूर्वाग्रह से सीधे विरोध में खड़ा है। इसके अलावा, पहले से ही प्रचलित विकल्प के रूप में def, lambdaफ़ंक्शन आपके सिंटैक्स में विविधता जोड़ता है। कुछ इस पर विचार करेंगे कि कम सुसंगत।


पहले से मौजूद कार्य:

जैसा कि दूसरों ने नोट किया है, lambdaक्षेत्र में कई उपयोगों को operatorया अन्य मॉड्यूल के सदस्यों द्वारा प्रतिस्थापित किया जा सकता है । उदाहरण के लिए:

do_something(x, y, lambda x, y: x + y)
do_something(x, y, operator.add)

पहले से मौजूद फ़ंक्शन का उपयोग करके कई मामलों में कोड को अधिक पठनीय बनाया जा सकता है।


पायथोनिक सिद्धांत: "एक होना चाहिए - और अधिमानतः केवल एक - स्पष्ट तरीका यह करने के लिए"

यह सत्य सिद्धांत के एकल स्रोत के समान है । दुर्भाग्य से, एकल-स्पष्ट-से-करने के लिए यह सिद्धांत हमेशा एक सच्चे मार्गदर्शक प्रिंसिपल के बजाय पायथन के लिए अधिक महत्वपूर्ण आकांक्षा रहा है। पायथन में बहुत शक्तिशाली सरणी समझ पर विचार करें। वे कार्यात्मक रूप से mapऔर filterकार्यों के समतुल्य हैं :

[e for e in some_array if some_condition(e)]
filter(some_array, some_condition)

lambdaऔर defसमान हैं।

यह एक राय का विषय है, लेकिन मैं कहूंगा कि सामान्य उपयोग के लिए पाइथन भाषा में कुछ भी जो स्पष्ट रूप से कुछ भी नहीं तोड़ता है "पायथोनिक" पर्याप्त है।


7

अधिक बेहतर: लंबोदर फ़ंक्शन या नेस्टेड फ़ंक्शन ( 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


6

मैं नोस्कोलो की सलाह से सहमत हूं: यदि आपको फ़ंक्शन को एक नाम देने की आवश्यकता है, तो उपयोग करें def। मैं lambdaउन मामलों के लिए कार्य करता हूं जहां मैं सिर्फ दूसरे फ़ंक्शन के लिए कोड का एक संक्षिप्त स्निपेट पास कर रहा हूं, जैसे:

a = [ (1,2), (3,4), (5,6) ]
b = map( lambda x: x[0]+x[1], a )

3
मैप / लैम्ब्डा के अधिकांश संयोजनों में, आप इसे एक सूची समझ या अधिक उपयुक्त फ़ंक्शन के साथ बदल सकते हैं। उदाहरण के लिए, "नक्शा (राशि, ए)" या "[x [0] + x [1] में x के लिए एक]"
जॉन मिलिकिन

हाँ यह सच है। कभी-कभी मैं मानचित्र () को पसंद करता हूं। यह ज्यादातर इन-लाइन फ़ंक्शन का उपयोग करने का केवल एक आकस्मिक उदाहरण था।
डैन लेन्स्की

बिल्कुल ... अधिकांश उदाहरणों से वंचित हैं, क्योंकि यह उपयोग करने के लिए अप्राकृतिक है और अधिकांश मामलों में व्यावहारिक बेहतर तरीके हैं।
nosklo

5

अन्य उत्तरों से सहमत होते हुए, कभी-कभी यह अधिक पठनीय होता है। यहां एक उदाहरण है जहां lambdaकाम आता है, एक उपयोग के मामले में मैं एक एन आयामी का सामना कर रहा हूं defaultdict
यहाँ एक उदाहरण है:

from collections import defaultdict
d = defaultdict(lambda: defaultdict(list))
d['Foo']['Bar'].append(something)

मुझे defदूसरे आयाम के लिए बनाने की तुलना में यह अधिक पठनीय लगता है । उच्च आयामों के लिए यह और भी महत्वपूर्ण है।


from functools import partial; defaultdict(partial(defaultdict, list))। यदि आप इसे एक से अधिक बार उपयोग करना चाहते हैं, तो एक नाम को आंशिक असाइन करें। लेकिन, यदि आप रखने के इस संरचना का सामना पर, इसका मतलब है आप सूखी नहीं हैं। इसे एक उपयोगिता पुस्तकालय में शामिल करें। आप अन्य कन्फ़र्मूल (या लूप या रिकर्सन) का उपयोग करके एक मनमाना एन-आयामी डिफ़ॉल्ट निर्णय बनाने के लिए इस निर्माण का उपयोग कर सकते हैं।
डायलनयॉन्ग

3

लैम्ब्डा का प्राथमिक उपयोग हमेशा सरल कॉलबैक कार्यों के लिए किया गया है, और नक्शे के लिए, कम करने, फ़िल्टर करने के लिए, जिसके लिए एक तर्क के रूप में एक फ़ंक्शन की आवश्यकता होती है। यदि मानक हो तो सूची की समझ के साथ, और जोड़े जाने की अनुमति है:

x = [f for f in range(1, 40) if f % 2]

दैनिक उपयोग में लैम्बडा के उपयोग के लिए एक वास्तविक मामले की कल्पना करना कठिन है। नतीजतन, मैं कहूंगा, लंबोदर से बचें और नेस्टेड फ़ंक्शन बनाएं।


3

लैम्ब्डा की एक महत्वपूर्ण सीमा यह है कि उनमें अभिव्यक्ति के अलावा कुछ भी नहीं हो सकता है। यह लांबा अभिव्यक्ति के लिए तुच्छ साइड इफेक्ट के अलावा कुछ भी उत्पादन करने के लिए लगभग असंभव है, क्योंकि यह कहीं भी def'एड फंक्शन' के रूप में समृद्ध शरीर के पास नहीं हो सकता है।

कहा जा रहा है कि, Lua ने गुमनाम कार्यों के व्यापक उपयोग की ओर मेरी प्रोग्रामिंग शैली को प्रभावित किया, और मैंने उनके साथ अपना कोड लिट किया। उसके ऊपर, मैं मानचित्र के बारे में सोचने / अमूर्त ऑपरेटरों के रूप में कम करने के बारे में सोचता हूं, मैं सूची समझ या जनरेटर पर विचार नहीं करता, लगभग जैसा कि अगर मैं उन ऑपरेटरों का उपयोग करके स्पष्ट रूप से एक कार्यान्वयन निर्णय का विमोचन कर रहा हूं।

संपादित करें: यह एक बहुत पुराना सवाल है, और इस मामले पर मेरी राय कुछ हद तक बदल गई है।

सबसे पहले, मैं lambdaएक चर को अभिव्यक्ति देने के खिलाफ दृढ़ता से पक्षपाती हूं ; जैसे कि अजगर के लिए एक विशेष वाक्यविन्यास है (संकेत, def)। इसके अलावा, लैम्ब्डा के लिए कई उपयोग, यहां तक ​​कि जब उन्हें एक नाम नहीं मिलता है, तो पूर्वनिर्धारित (और अधिक कुशल) कार्यान्वयन होते हैं। उदाहरण के लिए, प्रश्न में उदाहरण सिर्फ संक्षिप्त किया जा सकता है (1).__add__में एक लपेट की आवश्यकता के बिना, lambdaया def। कई अन्य सामान्य उपयोग operator, itertoolsऔर functoolsमॉड्यूल के कुछ संयोजन से संतुष्ट हो सकते हैं ।


1
(1).__add__- कॉलिंग डंडर तरीके सीधे नहीं होने चाहिए। lambdaप्रत्येक डायरेक्ट डंडर कॉल के लिए एक हजार एस।
एथन फुरमान

1
@ ईथनफर्मन: मेरे अनुभव में, प्रकृति की कॉलें (1).__add__कुछ असामान्य हैं, लेकिन मैं "चाहिए" के करीब कहीं भी नहीं जाऊंगा। एक शक के बिना, मुझे लगता है कि पूर्व को बहुत अधिक पठनीय होना चाहिए lambda x: 1 + x। अगर हमारे पास हैस्केल्स स्लाइस नोटेशन के लिए कुछ अधिक है, तो (1+)यह बहुत अच्छा होगा, लेकिन हमें उस चीज़ के साथ शब्दार्थ करना होगा , जो डंडर विधि का नाम है।
एकलकरण

2
  • गणना का समय।
  • बिना नाम का कार्य।
  • एक फ़ंक्शन और कई कार्यक्षमता का उपयोग करने के लिए।

एक सरल उदाहरण मानते हुए,

# CREATE ONE FUNCTION AND USE IT TO PERFORM MANY OPERATIONS ON SAME TYPE OF DATA STRUCTURE.
def variousUse(a,b=lambda x:x[0]):
    return [b(i) for i in a]

dummyList = [(0,1,2,3),(4,5,6,7),(78,45,23,43)]
variousUse(dummyList)                           # extract first element
variousUse(dummyList,lambda x:[x[0],x[2],x[3]]) # extract specific indexed element
variousUse(dummyList,lambda x:x[0]+x[2])        # add specific elements
variousUse(dummyList,lambda x:x[0]*x[2])        # multiply specific elements

1

यदि आप लैम्बडा को स्थानीय दायरे में एक चर को सौंपने जा रहे हैं, तो आप डिफ का उपयोग कर सकते हैं क्योंकि यह अधिक पठनीय है और भविष्य में इसे और अधिक आसानी से विस्तारित किया जा सकता है:

fun = lambda a, b: a ** b # a pointless use of lambda
map(fun, someList)

या

def fun(a, b): return a ** b # more readable
map(fun, someList)

दोनों from operator import pow;map(pow, someList)और (a**b for a,b in someList)भी पठनीय हैं।
इनक्यू

1

लैंबडास के लिए एक उपयोग मैंने पाया है ... डिबग संदेशों में है।

चूँकि लैम्ब्डा का आलसी मूल्यांकन किया जा सकता है, इसलिए आपके पास इस तरह का कोड हो सकता है:

log.debug(lambda: "this is my message: %r" % (some_data,))

संभवतः महंगे के बजाय:

log.debug("this is my message: %r" % (some_data,))

डिबग कॉल वर्तमान लॉगिंग स्तर के कारण आउटपुट का उत्पादन नहीं करता है, भले ही प्रारूप स्ट्रिंग संसाधित करता है।

बेशक यह काम करने के लिए जैसा कि उपयोग में लॉगिंग मॉड्यूल को वर्णित किया गया है, उसे मेमने को "आलसी मापदंडों" के रूप में समर्थन करना चाहिए (जैसा कि मेरा लॉगिंग मॉड्यूल करता है)।

मांग सामग्री मूल्य निर्माण पर आलसी मूल्यांकन के किसी अन्य मामले में भी यही विचार लागू किया जा सकता है।

उदाहरण के लिए यह कस्टम टर्नरी ऑपरेटर:

def mif(condition, when_true, when_false):
    if condition:
         return when_true()
    else:
         return when_false()

mif(a < b, lambda: a + a, lambda: b + b)

के बजाय:

def mif(condition, when_true, when_false):
    if condition:
         return when_true
    else:
         return when_false

mif(a < b, a + a, b + b)

लैम्ब्डा के साथ केवल स्थिति द्वारा चयनित अभिव्यक्ति का मूल्यांकन किया जाएगा, लैम्बदास के बिना दोनों का मूल्यांकन किया जाएगा।

बेशक आप लांबडा के बजाय केवल कार्यों का उपयोग कर सकते हैं, लेकिन छोटी अभिव्यक्तियों के लिए लम्बदास (ग) लीनर हैं।


1
एनबी में loggingपहले से ही आलसी स्वरूपण है: log.debug("this is my message: %r", some_data)केवल तभी प्रारूप होगा जब / यदि संदेश का अनुरोध किया जाता है।
14

डिबग आउटपुट उत्पन्न नहीं होने की स्थिति में @ j0,000ue लैंबडा विधि सब कुछ का मूल्यांकन करता है, यदि आप दिखाते हैं some_dataकि यह एक महंगी अभिव्यक्ति या फ़ंक्शन / विधि कॉल हो सकती है।
ग्लूशेटर

0

मैं nosklo से सहमत हूँ। वैसे, यहां तक ​​कि एक बार उपयोग के साथ , फ़ंक्शन को फेंक दें , अधिकांश समय आप बस ऑपरेटर मॉड्यूल से कुछ का उपयोग करना चाहते हैं।

ईजी:

आपके पास इस हस्ताक्षर के साथ एक फ़ंक्शन है: myFunction (डेटा, कॉलबैक फ़ंक्शन)।

आप एक फ़ंक्शन पास करना चाहते हैं जो 2 तत्वों को जोड़ते हैं।

लंबोदर का उपयोग करना:

myFunction(data, (lambda x, y : x + y))

पायथोनिक तरीका:

import operator
myFunction(data, operator.add)

या बेशक यह एक सरल उदाहरण है, लेकिन ऑपरेटर मॉड्यूल प्रदान करता है सामान की एक बहुत कुछ है, सूची और तानाशाह के लिए आइटम बसने / पाने वालों सहित। बहुत कूल।


-1

एक बड़ा अंतर यह है कि आप defफ़ंक्शन इनलाइन का उपयोग नहीं कर सकते हैं , जो मेरी राय में lambdaफ़ंक्शन के लिए सबसे सुविधाजनक उपयोग मामला है । उदाहरण के लिए जब वस्तुओं की सूची छाँटते हैं:

my_list.sort(key=lambda o: o.x)

इसलिए मैं इस प्रकार के तुच्छ कार्यों के लिए लंबोदा के उपयोग को रखने का सुझाव दूंगा, जो वास्तव में फ़ंक्शन का नामकरण करके प्रदान किए गए स्वचालित प्रलेखन से भी लाभ नहीं लेते हैं।


-2

लैम्बडा नए कार्यों को उत्पन्न करने के लिए उपयोगी है:

>>> def somefunc(x): return lambda y: x+y
>>> f = somefunc(10)
>>> f(2)
12
>>> f(4)
14
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.