पायथन मल्टी-लाइन लैम्ब्डा की अनुमति क्यों नहीं देता है?


50

क्या कोई ठोस कारण बता सकता है कि BDFL पाइथन लैंबडास को सिंगल लाइन बनाने का विकल्प क्यों चुनता है?

यह अच्छा है:

lambda x: x**x

इसके परिणामस्वरूप त्रुटि होती है:

lambda x:
    x**x

मैं समझता हूं कि लंबोदर मल्टी-लाइन बनाने से सामान्य इंडेंटेशन नियमों को किसी भी तरह "परेशान" किया जा सकता है और इसके लिए और अपवाद जोड़ने की आवश्यकता होगी, लेकिन क्या यह लाभ के लायक नहीं है?

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


3
यह देखते हुए कि आप ठोस कारणों पर ध्यान देते हैं कि गुइडो मल्टी-एक्सप्रेशन लैंबडास की अनुमति क्यों नहीं देता है और फिर उन्हें खारिज कर देता है, मुझे लगता है कि आप एक वास्तविक उत्तर के बजाय सत्यापन की मांग कर रहे हैं।
जेसन बेकर

3
सात पात्रों को बचाने के अलावा, यह किसी से बेहतर कैसे है def? अब इसमें ठीक वैसी ही संरचना है।
detly

जवाबों:


42

Guido van van Rossum ने खुद इसका उत्तर दिया:

लेकिन ऐसे समाधानों में अक्सर "पायथोनिकिटी" का अभाव होता है - जो कि एक अच्छे पायथन फीचर के मायावी लक्षण हैं। पाइथोनिकिटी को एक कठिन बाधा के रूप में व्यक्त करना असंभव है। यहां तक ​​कि पायथन का ज़ेन भी Pythonicity के एक साधारण परीक्षण में अनुवाद नहीं करता है ...

ऊपर दिए गए उदाहरण में, प्रस्तावित समाधान के अकिलीज एड़ी को ढूंढना आसान है: दोहरे बृहदान्त्र, जबकि वाक्यात्मक रूप से अस्पष्ट ("पहेली बाधाओं में से एक"), पूरी तरह से मनमाना है और पायथन में कुछ और जैसा नहीं है ...

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

http://www.artima.com/weblogs/viewpost.jsp?thread=147358

मूल रूप से, वह कहते हैं कि हालांकि एक समाधान संभव है, यह अजगर कैसे है के साथ अनुरूप नहीं है।


2
+1 थ्रेड लिंक के लिए धन्यवाद - लेकिन मैं अभी भी मल्टी-लाइन लैंबडास की सराहना करूंगा - वे अमूल्य हैं - जावास्क्रिप्ट को देखें, PHP ने उन्हें भी शामिल किया है।
treecoder

2
@greengit आप केवल एक नेस्टेड डीईटी का उपयोग कर सकते हैं। यह अनाम कार्यों के समान नहीं है, लेकिन वे काफी करीब हैं।

2
नेस्टेड डीएएस तर्क के रूप में कार्य करते समय मदद नहीं करते हैं - यही कारण है कि नंबर एक कारण है कि मैं मल्टी-लाइन लैम्ब्ड्स को पसंद करूंगा
treecoder

1
@greengit - मुझे लगता है कि यहाँ अपनी टिप्पणी पोस्ट करने की तुलना में GvR के साथ इसे लेना बेहतर है।
जेसन बेकर

9
@greengit: आप जानते हैं कि आप फ़ंक्शन को किसी अन्य फ़ंक्शन के तर्क के रूप में पास कर सकते हैं? आप इसे इनलाइन नहीं लिख सकते हैं, लेकिन कोई प्रोग्रामिंग तकनीक नहीं है जो आपके लिए उपलब्ध नहीं है।
btilly

24

अजगर में मल्टी लाइन लैम्ब्डा करना पूरी तरह से ठीक है: देखें

>>> f = lambda x: (
...   x**x)
>>> f
<function <lambda> at 0x7f95d8f85488>
>>> f(3)
27

वास्तविक लैम्ब्डा सीमा तथ्य यह है कि लैम्ब्डा एक एकल अभिव्यक्ति होना चाहिए ; यह कीवर्ड (को Python2 की तरह होता है नहीं कर सकते हैं printया return)।

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


1
मल्टी लाइन '\ n' अक्षर के इंसर्ट के बारे में है: डी पायथन में मल्टी स्टेटमेंट लैम्बडा नहीं है । आप वास्तव में उपयोग करना चाहते हैं def। इसके बारे में सोचें: आपको वास्तव में अपने फ़ंक्शन के पैरामीटर के रूप में कॉल करने योग्य चाहिए? और उस फ़ंक्शन के उपयोगकर्ताओं को आपके डिफ़ॉल्ट कॉल करने योग्य पास करने की अनुमति नहीं है ? यदि आप उन्हें नहीं देते हैं तो वे इसे कैसे पारित कर सकते हैं?
वीटो डी टुल्लियो

btw, क्या आप अननोन फंक्शन की अपनी जरूरत का एक उदाहरण प्रदान कर सकते हैं?
वीटो डी टुल्लियो

1
हाँ, मुझे लगता है कि वास्तव में निराशाजनक एक ही अभिव्यक्ति की सीमा है। यह सच है, कि अगर वे बहु-अभिव्यक्ति वाले लम्बडास की अनुमति देते हैं, तो लोग निश्चित रूप से इसका दुरुपयोग करना शुरू कर देंगे, लेकिन दूसरा तरीका बहुत ज्यादा प्रतिबंधक है।
rbaleksandar

10

मुझे पता है कि यह सुपर पुराना है, लेकिन एक संदर्भ के रूप में यहां डाल रहा हूं।

लैम्ब्डा का उपयोग करने का एक विकल्प defएक गैर-पारंपरिक तरीके से उपयोग करना हो सकता है । लक्ष्य defएक फ़ंक्शन को पास करना है, जिसे केवल एक परिस्थिति में किया जा सकता है - एक डेकोरेटर। ध्यान दें कि इस कार्यान्वयन के साथ def resultएक फ़ंक्शन नहीं बनता है, यह परिणाम बनाता है reduce(), जो समाप्त होता है a dict

बेशर्म प्लग : मैं यहाँ बहुत कुछ करता हूँ ।

>>> xs = [('a', 1), ('b', 2), ('a', 3), ('b', 4)]
>>> foldl = lambda xs, initial: lambda f: reduce(f, xs, initial)
>>> @foldl(xs, {})
... def result(acc, (k, v)):
...     acc.setdefault(k, 0)
...     acc[k] += v
...     return acc
...
>>> result
{'a': 4, 'b': 6} 

ध्यान दें कि मल्टी-स्टेटमेंट लैम्ब्डा किया जा सकता है, लेकिन केवल वास्तव में, वास्तव में बदसूरत कोड के साथ। हालांकि, जो दिलचस्प है वह यह है कि इस कार्यान्वयन के साथ कैसे काम करता है ( nameचर के कई उपयोग पर ध्यान दें और चर का छायांकन करें message

>>> from __future__ import print_function
>>> bind = lambda x, f=(lambda x: x): f(x)
>>> main = lambda: bind(
...     print('Enter your name.'), lambda _: bind(
...     raw_input('> '), lambda name: bind(
...     'Hello {}!'.format(name), lambda message: bind(
...     print(message), lambda _: bind(
...     'Bye {}!'.format(name), lambda message: bind(
...     print(message)
... ))))))
>>> main()
Enter your name.
> foo
Hello foo!
Bye foo!


जावास्क्रिप्ट बीटीडब्ल्यू में मोनाड्स को तत्कालीन या भविष्य / वादे या कॉलबैक भी कहा जाता है।
aoeu256

3

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

मैं अपने ब्लॉग पर ऐसा करने के लिए कुछ तरीके कवर करता हूं

उदाहरण के लिए, पायथन क्रम में एक टुपल के तत्वों का मूल्यांकन करने की गारंटी देता है, इसलिए हम ,एक अनिवार्यता की तरह उपयोग कर सकते हैं ;। हम कई कथनों को बदल सकते हैं, जैसे print, भाव के साथ, जैसे sys.stdout.write

इसलिए निम्नलिखित समतुल्य हैं:

def print_in_tag_def(tag, text):
    print "<" + tag + ">"
    print text
    print "</" + tag + ">"

import sys
print_ = sys.stdout.write
print_in_tag_lambda = lambda tag, text: (print_("<" + tag + ">"),
                                         print_(text),
                                         print_("</" + tag + ">"),
                                         None)[-1]

ध्यान दें कि मैंने Noneअंत में जोड़ा है , और इसका उपयोग करके निकाला है [-1]; यह स्पष्ट रूप से रिटर्न मूल्य निर्धारित करता है। हमें ऐसा करने की जरूरत नहीं है, लेकिन इसके बिना हमें एक फंकी (None, None, None)रिटर्न वैल्यू मिलेगी , जिसकी हम परवाह नहीं कर सकते हैं।

तो हम IO क्रियाओं को अनुक्रमित कर सकते हैं। स्थानीय चर के बारे में क्या?

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

def stateful_def():
    foo = 10
    bar = foo * foo
    foo = 2
    return foo + bar

stateful_lambda = (lambda state: lambda *_: (state.setdefault('foo', 10),
                                             state.setdefault('bar', state.get('foo') * state.get('foo')),
                                             state.pop('foo'),
                                             state.setdefault('foo', 2),
                                             state.get('foo') + state.get('bar'))[-1])({})

इसमें कुछ प्रयोग किए जा रहे हैं stateful_lambda:

  • *_तर्क हमारे लैम्ब्डा लेने के लिए अनुमति देता है किसी भी तर्क की संख्या। चूंकि यह शून्य तर्क की अनुमति देता है , हम कॉलिंग कन्वेंशन को पुनर्प्राप्त करते हैं stateful_def
    • एक तर्क _को कॉल करना एक सम्मेलन है जो कहता है कि "मैं इस चर का उपयोग नहीं करने जा रहा हूं"
  • हमारे पास एक ("रैपर") फ़ंक्शन है जो दूसरे को लौटाता है ("मुख्य") फ़ंक्शन: lambda state: lambda *_: ...
    • शाब्दिक गुंजाइश के लिए धन्यवाद , पहले फ़ंक्शन का तर्क दूसरे फ़ंक्शन के लिए गुंजाइश होगा
    • कुछ तर्कों को स्वीकार करना और बाकी को बाद में स्वीकार करने के लिए किसी अन्य फ़ंक्शन को वापस करना क्यूरिंग के रूप में जाना जाता है
  • हम तुरंत "रैपर" फ़ंक्शन को कॉल करते हैं, इसे खाली शब्दकोश देते हुए: (lambda state: ...)({})
    • यह हमें एक असाइनमेंट स्टेटमेंट (उदाहरण के लिए ) का उपयोग किए बिना stateएक मान को एक वैरिएबल प्रदान करने की अनुमति देता है {}state = {}
  • हम कुंजी और मान stateको चर नाम और बाउंड मान के रूप में मानते हैं
    • यह तुरंत-लंबोदा के उपयोग की तुलना में कम बोझिल है
    • यह हमें चर के मूल्यों को बदलने की अनुमति देता है
    • हम के state.setdefault(a, b)बजाय a = bऔर के state.get(a)बजाय का उपयोग करेंa
  • हम पहले की तरह हमारे साइड-इफेक्ट्स को एक साथ करने के लिए एक टपल का उपयोग करते हैं
  • हम [-1]अंतिम मूल्य निकालने के लिए उपयोग करते हैं, जो एक returnबयान की तरह काम करता है

बेशक यह बहुत बोझिल है, लेकिन हम सहायक कार्यों के साथ एक अच्छा एपीआई बना सकते हैं:

# Keeps arguments and values close together for immediately-called functions
callWith = lambda x, f: f(x)

# Returns the `get` and `setdefault` methods of a new dictionary
mkEnv = lambda *_: callWith({},
                            lambda d: (d.get,
                                       lambda k, v: (d.pop(k), d.setdefault(k, v))))

# A helper for providing a function with a fresh `get` and `setdefault`
inEnv = lambda f: callWith(mkEnv(), f)

# Delays the execution of a function
delay = lambda f x: lambda *_: f(x)

# Uses `get` and `set`(default) to mutate values
stateful_lambda = delay(inEnv, lambda get, set: (set('foo', 10),
                                                 set('bar', get('foo') * get('foo')),
                                                 set('foo', 2),
                                                 get('foo') + get('bar'))[-1])

क्या आप मजाक कर रहे हैं, यह एक बुरे सपने की तरह लग रहा है
अलेक्जेंडर मिल्स

1
@AlexanderMills हेह, यह एक वास्तविक दुनिया उदाहरण के रूप में नहीं किया गया था, उन चीजों को दिखाने के लिए जो खराब है , यह दिखाने के लिए पायरोस्पेड के लैम्ब्डा-इन-लाम्बदास-इन-लैम्बदास दृष्टिकोण का खंडन है । वास्तव में, इसे अभी और सरल बनाया जा सकता है कि हमारे पास python.org/dev/peps/pep-0572
वारबो

1

हालांकि मैं योगदान दे सकता था, एक लाइन ब्रेकर का उपयोग करें:

x = lambda x,y: x-y if x<y \ 
                     else y-x if y<x \
                     else 0

बहुत अच्छी बात यह मत भूलो कि अजगर ऑनलाइनर लिखने में सक्षम है, उदाहरण के लिए:

a=b=0; c=b+a; d = a+b**2 #etc etc

और लैम्ब्डा बहुत शक्तिशाली है, लेकिन यह 1 पूरे फ़ंक्शन के प्रतिस्थापन के लिए नहीं है, मेरा मतलब है कि आप इसे हैक कर सकते हैं जैसे (ऊपर सहयोगी से उधार लेना):

makeTag = lambda tagName: "<{}>".format(tagName)
closeTag = lambda tagName: makeTag("/"+str(tagName))
openTag = lambda tagName: makeTag(tagName)
writeHMTLline = lambda tag,content: ""+opetTag(tag)+str(content)+closeTag(tag)

लेकिन क्या आप वाकई ऐसा करना चाहते हैं? यह ज्यादातर कुछ समय के बाद अपठनीय होता है, यह रस्सी की शुरुआत की तरह होता है जिसकी शुरुआत अनवैलिड एंड से होती है। बिना रस्सी के

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

chrDev2 = lambda INT: chr(INT) if isinstance(INT,int) and INT%2==0 else INT
someStringList = map( chrDev2, range(30) )
>>> ['\x00', 1, '\x02', 3, '\x04', 5, '\x06', 7, '\x08', 9, '\n', 11, '\x0c', 13, '\x0e', 15, '\x10', 17, '\x12', 19, '\x14', 21, '\x16', 23, '\x18', 25, '\x1a', 27, '\x1c', 29]

आप इसे जटिल कार्य (या अधिक और कई लंबोदा) को अलग करने और इसे एक और मेमने के अंदर डालकर फंक्शन एक्सप्रेशन फंक्शन के रूप में उपयोग कर सकते हैं:

def someAnon(*args): return sum(list(args))
defAnon = lambda list: [ x*someAnon(*list) for x in list]

लेकिन पायथन के पास एक और तरीके से फंक्शन एक्सर्साइज़ सपोर्ट है: -लेट्स का कहना है कि आपके पास कुछ फंक्शन है superAwesomeFunctionऔर वह फंक्शन कुछ सुपर कमाल का सामान कर सकता है, आप इसे वेरिएबल न कहकर असाइन कर सकते हैं, जैसे:

SAF = superAwesomeFunction # there is no () at the end, 

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

आप कंसोल importedModule.__file__(वास्तविक उदाहरण import os;os.__file__) में प्रवेश करके आयातित मॉड्यूल का स्थान पा सकते हैं , और बस उस निर्देशिका का पालन करें जिसे importModule.py नाम की फ़ाइल में दर्ज करें और इसे संपादक में खोलें और पाएं कि आप अपने स्वयं के "ज्ञान" को अधिकतम कैसे कर सकते हैं।

मुझे उम्मीद है कि इससे आपको और शायद अन्य सहयोगियों को परेशानी होगी।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.