पायथन में कोई मल्टीलाइन लैम्ब्डा: क्यों नहीं?


335

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

अब, मुझे यकीन है कि गुइडो के पास भाषा में मल्टीलाइन लैम्ब्डा शामिल नहीं करने का एक कारण था, लेकिन जिज्ञासा से बाहर: एक ऐसी स्थिति क्या है जिसमें मल्टीलाइन लैम्ब्डा शामिल है जो अस्पष्ट होगा? क्या मैंने जो सुना है वह सच है, या क्या कोई और कारण है कि पायथन मल्टीलाइन लैम्ब्डा की अनुमति नहीं देता है?


12
tl; dr संस्करण: क्योंकि पायथन {} ब्लॉकों के बिना एक आलसी भाषा है और इसलिए सुसंगत वाक्य रचना को बनाए रखने के लिए इसे अनुमति नहीं दी गई थी।
एंड्रयू

11
इसके अलावा: मैं पूरी तरह से आश्चर्यचकित हूं कि किसी ने भी जवाब में इसका उल्लेख नहीं किया है ... आप पायथन में \ चरित्र के साथ लाइनें समाप्त कर सकते हैं और अगली पंक्ति पर जारी रख सकते हैं ... यह जानकारी थोड़े इस पूरे प्रश्न को बढ़ा देती है ...
एंड्रयू


"वाक्यात्मक डिजाइन"
निकोलस

इसके लिए अभिव्यक्तियों के अंदर बयान देने की आवश्यकता होगी। यदि आप ऐसा करने जा रहे हैं, तो आपको lambdaपहले स्थान पर अभिव्यक्ति की आवश्यकता नहीं है; आप बस defअभिव्यक्ति में बयानों का उपयोग कर सकते हैं ।
चेपनर

जवाबों:


153

निम्नलिखित को देखें:

map(multilambda x:
      y=x+1
      return y
   , [1,2,3])

क्या यह लंबोदर लौट रहा है (y, [1,2,3])(इस प्रकार नक्शे में केवल एक पैरामीटर मिलता है, जिसके परिणामस्वरूप त्रुटि होती है)? या वापस लौटता है y? या यह एक वाक्यविन्यास त्रुटि है, क्योंकि नई लाइन पर अल्पविराम गलत है? अजगर को कैसे पता चलेगा कि आप क्या चाहते हैं?

पार्न्स के भीतर, इंडेंटेशन अजगर के लिए कोई मायने नहीं रखता है, इसलिए आप बहुउद्देशीय रूप से काम नहीं कर सकते।

यह सिर्फ एक सरल है, शायद अधिक उदाहरण हैं।


107
यदि आप एक लंबोदर से एक टपल लौटना चाहते हैं तो वे कोष्ठक के उपयोग को मजबूर कर सकते हैं। IMO, यह हमेशा ऐसी अस्पष्टताओं को रोकने के लिए लागू किया जाना चाहिए था, लेकिन ओह अच्छी तरह से।
म्पेन

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

3
मुझे पसंद है कि कैसे गज़िलियन भाषाएं हैं जो इससे निपटती हैं कोई झल्लाहट नहीं है, लेकिन किसी भी तरह से कुछ गहरे कारण हैं कि अगर यह असंभव नहीं तो बहुत मुश्किल है
निकोलस


कारण है कि मैं लंबोदर का उपयोग नहीं करता हूं, इसलिए पायथन में विकसित किया गया है।
NoName

635

गुइडो वैन रोसुम (पायथन के आविष्कारक) इस सटीक सवाल का जवाब खुद एक पुराने ब्लॉग पोस्ट में देते हैं
मूल रूप से, वह स्वीकार करता है कि यह सैद्धांतिक रूप से संभव है, लेकिन यह कि कोई भी प्रस्तावित समाधान अन-पायथोनिक होगा:

"लेकिन इस पहेली के लिए किसी भी प्रस्तावित समाधान की जटिलता मेरे लिए बहुत अधिक है: इसे इंडेंट-सेंसिटिव और इंडेंट-इनसेन्सिटिव मोड्स के बीच आगे और पीछे स्विच करने में सक्षम होने के लिए पार्सर (या अधिक सटीक, लेक्सर) की आवश्यकता होती है।" पिछले मोड और इंडेंटेशन स्तर पर। तकनीकी रूप से सभी को हल किया जा सकता है (सामान्यीकरण के पहले से ही इंडेंटेशन स्तरों का एक स्टैक है)। लेकिन इसमें से कोई भी मेरी आंत को यह महसूस नहीं करता है कि यह एक विस्तृत रब गोल्डबर्ग गर्भनिरोधक है । "


108
यह शीर्ष उत्तर क्यों नहीं है? यह तकनीकी कारणों के बारे में नहीं है, यह एक डिज़ाइन विकल्प है, जैसा कि आविष्कारक द्वारा स्पष्ट रूप से कहा गया है।
दान अब्रामोव

13
@DanAbramov क्योंकि ओपी शायद वर्षों से लॉग इन नहीं किया था।
प्रो। फालकेन अनुबंध ने

7
जिन लोगों ने
रुब

56
गुइडो का जवाब सिर्फ एक और कारण है कि मैं चाहता हूं कि पायथन ब्लॉक को परिभाषित करने के लिए इंडेंटेशन पर निर्भर न हो।
एलएस

25
मुझे यकीन नहीं है कि मैं एक डिजाइन विकल्प "आंत महसूस" कहूंगा। ;)
इलियट कैमरन 21

54

यह आम तौर पर बहुत बदसूरत है (लेकिन कभी-कभी विकल्प और भी बदसूरत होते हैं), इसलिए एक ब्रेसिज़ अभिव्यक्ति बनाने के लिए है:

lambda: (
    doFoo('abc'),
    doBar(123),
    doBaz())

यह किसी भी असाइनमेंट को स्वीकार नहीं करेगा, लेकिन आपको पहले से डेटा तैयार करना होगा। जिस स्थान पर मुझे यह उपयोगी लगा, वह है PySide आवरण, जहाँ आपको कभी-कभी छोटी कॉलबैक होती हैं। अतिरिक्त सदस्य फ़ंक्शन लिखना और भी अधिक बदसूरत होगा। आम तौर पर आपको इसकी आवश्यकता नहीं होगी।

उदाहरण:

pushButtonShowDialog.clicked.connect(
    lambda: (
    field1.clear(),
    spinBox1.setValue(0),
    diag.show())

2
मेरे मालिक हमारे PyQt आवेदन में ऐसा ही कुछ मांग रहे थे। बहुत बढ़िया!
TheGerm

1
इसके लिए धन्यवाद, मैं भी हमारे PySide UI के लिए कॉलबैक के रूप में कम (लेकिन अभी भी मल्टीलाइन) लैम्ब्डा का उपयोग करने के लिए एक अच्छे तरीके की तलाश में था।
माइकल लियोनार्ड

और अब मैंने देखा है कि यह तुरंत उपयोग करने का सुझाव दिया गया है lambda argऔर setattr(arg, 'attr','value')"कोई असाइनमेंट नहीं ..."। और फिर शॉर्ट-सर्किट मूल्यांकन है andऔर or... यह जावास्क्रिप्ट है जो इसे करता है। आप में जड़ें डूब जाती हैं, जैसे आइवी एक दीवार में। मुझे लगभग उम्मीद है कि मैं एक्समास पर यह भूल गया हूं।
nigel222

काफी चतुर - और काफी पठनीय। अब - उन (गायब ..) असाइनमेंट्स के बारे में ..
javadba

@ nigel222 शर्म क्यों आती है? अजगर भाषा मौलिक रूप से अपंग है - लेकिन यह डेटा विज्ञान के बहुत से उपयोग के लिए किसी भी तरह है । तो हम समायोजन करते हैं। साइड इफेक्ट्स करने के तरीके खोजना (अक्सर पर्याप्त रूप से मुद्रण / लॉगिंग!) और असाइनमेंट (अक्सर केवल मध्यवर्ती संस्करण के लिए पर्याप्त!) को भाषा द्वारा अच्छी तरह से संभाला जाना चाहिए। लेकिन वे भी समर्थित नहीं हैं (कम से कम यदि आप दिशानिर्देशों का पालन करते हैं)PEP
javadba

17

प्रासंगिक लिंक की एक जोड़ी:

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

http://www.unlimitednovelty.com/2009/03/indentation-sensitivity-post-mortem.html

इसके अलावा, यहां पाइथन में रूबी-शैली के ब्लॉकों के लिए एक दिलचस्प प्रस्ताव है, जहां मैं एक प्रतिक्रिया डब्ल्यू / ओ पोस्ट कर रहा हूं, जो वास्तव में इसे नीचे शूटिंग कर रहा है (यह सुनिश्चित नहीं है कि बाद में कोई शूटिंग हुई है, हालांकि):

http://tav.espians.com/ruby-style-blocks-in-python.html


12

[संपादित करें] इस उत्तर को पढ़ें यह बताता है कि मल्टीलाइन लैम्ब्डा कोई चीज क्यों नहीं है।

सीधे शब्दों में कहें, यह unpythonic है। गुइडो वैन रोसुम के ब्लॉग पोस्ट से:

मुझे कोई भी समाधान अस्वीकार्य लगता है जो एक अभिव्यक्ति के बीच में एक इंडेंटेशन-आधारित ब्लॉक एम्बेड करता है। चूँकि मुझे स्टेटमेंट ग्रुपिंग (उदाहरण के लिए ब्रेसिज़ या स्टार्ट / एंड कीवर्ड) के लिए वैकल्पिक वाक्यविन्यास समान रूप से अस्वीकार्य लगता है, इसलिए यह बहुत अधिक बहु-पंक्ति वाले लंबोद्दे को एक अनसुलझी पहेली बना देता है।


10

मुझे आप के लिए एक शानदार लेकिन भयानक हैक पेश करते हैं:

import types

def _obj():
  return lambda: None

def LET(bindings, body, env=None):
  '''Introduce local bindings.
  ex: LET(('a', 1,
           'b', 2),
          lambda o: [o.a, o.b])
  gives: [1, 2]

  Bindings down the chain can depend on
  the ones above them through a lambda.
  ex: LET(('a', 1,
           'b', lambda o: o.a + 1),
          lambda o: o.b)
  gives: 2
  '''
  if len(bindings) == 0:
    return body(env)

  env = env or _obj()
  k, v = bindings[:2]
  if isinstance(v, types.FunctionType):
    v = v(env)

  setattr(env, k, v)
  return LET(bindings[2:], body, env)

अब आप इस LETफॉर्म का उपयोग इस प्रकार कर सकते हैं :

map(lambda x: LET(('y', x + 1,
                   'z', x - 1),
                  lambda o: o.y * o.z),
    [1, 2, 3])

जो देता है: [0, 3, 8]



यह कमाल का है! मुझे लगता है कि मैं इसका उपयोग अगली बार पायथन लिखने में करूँगा। मैं मुख्य रूप से एक लिस्प और जेएस प्रोग्रामर हूं, और मल्टी लाइन लंबा की कमी से दर्द होता है। यह पाने का एक तरीका है।
क्रिस्टोफर डुमास

7

मैं अपनी कुछ परियोजनाओं में इस गंदे हैक का अभ्यास करने का दोषी हूं जो थोड़ा सरल है:

    lambda args...:( expr1, expr2, expr3, ...,
            exprN, returnExpr)[-1]

मुझे आशा है कि आप पायथोनिक रहने का एक तरीका पा सकते हैं, लेकिन यदि आपको इसे निष्पादित करने और ग्लोबल्स को हेरफेर करने की तुलना में कम दर्दनाक करना है।


6

मुझे @ palpha पार्सिंग समस्या से निपटने की कोशिश करें। मैं मल्टीलाइन लैम्डा के आसपास कोष्ठक का उपयोग करूंगा। यदि कोई कोष्ठक नहीं है, तो लंबोदर की परिभाषा लालची है। तो मेमने में

map(lambda x:
      y = x+1
      z = x-1
      y*z,
    [1,2,3]))

कोई फ़ंक्शन देता है जो देता है (y*z, [1,2,3])

परंतु

map((lambda x:
      y = x+1
      z = x-1
      y*z)
    ,[1,2,3]))

माध्यम

map(func, [1,2,3])

जहां फंक मल्टीलाइन लैम्ब्डा है जो y * z लौटाता है। क्या वह काम करता है?


1
मैं सोच रहा हूं कि शीर्ष को वापस लौटना चाहिए map(func, [1,2,3])और नीचे वाले को एक त्रुटि होनी चाहिए क्योंकि मानचित्र फ़ंक्शन में पर्याप्त तर्क नहीं हैं। इसके अलावा कोड में कुछ अतिरिक्त कोष्ठक हैं।
सामी बेनचेरी

कि pycharm चल python2.7.13 में छोड़ने यह एक वाक्यविन्यास त्रुटि देता है।
simbo1905 15

अतिरिक्त कोष्ठक
सामी बेनचेरीफ

4

(विषय में रुचि रखने वाले किसी भी व्यक्ति के लिए।)

इस पर विचार करें ("मल्टीलाइन" लंबोदा के भीतर बयानों के रिटर्न मान का उपयोग भी शामिल है, हालांकि यह उल्टी के बिंदु से बदसूरत है; ;-)

>>> def foo(arg):
...     result = arg * 2;
...     print "foo(" + str(arg) + ") called: " + str(result);
...     return result;
...
>>> f = lambda a, b, state=[]: [
...     state.append(foo(a)),
...     state.append(foo(b)),
...     state.append(foo(state[0] + state[1])),
...     state[-1]
... ][-1];
>>> f(1, 2);
foo(1) called: 2
foo(2) called: 4
foo(6) called: 12
12

जब यह दूसरी बार बुलाया जाता है तो यह अलग-अलग मापदंडों के साथ काम नहीं करता है और स्मृति रिसाव का कारण बनता है जब तक कि पहली पंक्ति state.clear()डिफ़ॉल्ट तर्कों के बाद केवल एक बार बनाई जाती है जब फ़ंक्शन बनाया जाता है।
मैथ्यू डी। शोलेफ़ील्ड

1

आप बस स्लैश ( \) का उपयोग कर सकते हैं यदि आपके पास अपने लंबो फ़ंक्शन के लिए कई लाइनें हैं

उदाहरण:

mx = lambda x, y: x if x > y \
     else y
print(mx(30, 20))

Output: 30

प्रश्न 1 से अधिक शाब्दिक रेखा के बजाय 1 से अधिक अभिव्यक्ति का उपयोग करने के साथ ही चिंता करता है।
टॉमस ज़ुबरी

1

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

उदाहरण के रूप में, बहुस्तरीय अभिव्यक्ति (x*2)को फंक्शन के रूप में निकाला जाता है और इसलिए मैं मल्टीलाइन का उपयोग कर सकता हूं:

def multiply(x):
  print('I am other line')
  return x*2

r = map(lambda x : multiply(x), [1, 2, 3, 4])
print(list(r))

https://repl.it/@datracka/python-lambda-function

शायद यह बिल्कुल सवाल का जवाब नहीं देता है कि अगर लैंबडा अभिव्यक्ति में मल्टीलाइन कैसे करना था , लेकिन अगर किसी को यह थ्रेड मिल जाए तो अभिव्यक्ति को डीबग कैसे करें (मेरे जैसे) मुझे लगता है कि इससे मदद मिलेगी


2
मैं ऐसा क्यों करूँगा और बस नहीं लिखूंगा map(multiply, [1, 2, 3])?
थलथ

0

बदसूरत हैक्स के विषय पर, आप हमेशा execइस तरह के एक बहु समारोह को परिभाषित करने के लिए और नियमित फ़ंक्शन के संयोजन का उपयोग कर सकते हैं :

f = exec('''
def mlambda(x, y):
    d = y - x
    return d * d
''', globals()) or mlambda

आप इसे एक फंक्शन में लपेट सकते हैं जैसे:

def mlambda(signature, *lines):
    exec_vars = {}
    exec('def mlambda' + signature + ':\n' + '\n'.join('\t' + line for line in lines), exec_vars)
    return exec_vars['mlambda']

f = mlambda('(x, y)',
            'd = y - x',
            'return d * d')

0

मैं बस कम करने के साथ एक तानाशाही समझ बनाने की कोशिश करने के लिए थोड़ा खेल रहा था, और इस एक लाइनर हैक के साथ आया:

In [1]: from functools import reduce
In [2]: reduce(lambda d, i: (i[0] < 7 and d.__setitem__(*i[::-1]), d)[-1], [{}, *{1:2, 3:4, 5:6, 7:8}.items()])                                                                                                                                                                 
Out[3]: {2: 1, 4: 3, 6: 5}

मैं तो बस वही करने की कोशिश कर रहा था जो इस जावास्क्रिप्ट तानाशाही समझ में किया गया था: https://stackoverflow.com/a/110340265


0

यहां मल्टी लाइन लैम्ब्डा का अधिक दिलचस्प कार्यान्वयन है। यह संभव नहीं है क्योंकि अजगर संरचना कोड के तरीके के रूप में अजगर का उपयोग कैसे करते हैं।

लेकिन हमारे लिए सौभाग्य से, सरणियों और कोष्ठक का उपयोग करके इंडेंट स्वरूपण को अक्षम किया जा सकता है।

जैसा कि कुछ पहले ही बताया गया है, आप अपना कोड इस तरह लिख सकते हैं:

lambda args: (expr1, expr2,... exprN)

सिद्धांत रूप में, यदि आपको बाएं से दाएं मूल्यांकन करने की गारंटी है तो यह काम करेगा लेकिन आप अभी भी एक अभिव्यक्ति से दूसरे में जाने वाले मूल्यों को खो देते हैं।

इसे प्राप्त करने का एक तरीका जो थोड़ा अधिक क्रिया है वह है

lambda args: [lambda1, lambda2, ..., lambdaN]

जहां प्रत्येक लंबोदर पिछले एक से तर्क प्राप्त करता है।

def let(*funcs):
    def wrap(args):
        result = args                                                                                                                                                                                                                         
        for func in funcs:
            if not isinstance(result, tuple):
                result = (result,)
            result = func(*result)
        return result
    return wrap

यह विधि आपको कुछ ऐसा लिखने देती है जो थोड़ा लिस्प / स्कीम है।

तो आप इस तरह की बातें लिख सकते हैं:

let(lambda x, y: x+y)((1, 2))

अधिक जटिल विधि का उपयोग कर्ण की गणना करने के लिए किया जा सकता है

lst = [(1,2), (2,3)]
result = map(let(
  lambda x, y: (x**2, y**2),
  lambda x, y: (x + y) ** (1/2)
), lst)

यह स्केलर संख्याओं की एक सूची लौटाएगा ताकि इसका उपयोग एक से कई मानों को कम करने के लिए किया जा सके।

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


-3

क्योंकि एक लंबोदर फ़ंक्शन को एक-पंक्तिबद्ध माना जाता है, क्योंकि यह फ़ंक्शन का सबसे सरल रूप है, an entrance, then return


1
नहीं, जो कोई भी घटना-संचालित कार्यक्रम लिखता है, वह आपको बताएगा कि बहुस्तरीय मेमना महत्वपूर्ण है।
अकांक्षा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.