पायथन में नेस्टेड फंक्शन


86

हम पायथन कोड के साथ इस तरह से क्या लाभ या निहितार्थ प्राप्त कर सकते हैं:

class some_class(parent_class):
    def doOp(self, x, y):
        def add(x, y):
            return x + y
        return add(x, y)

मैंने इसे ओपन-सोर्स प्रोजेक्ट में पाया, नेस्टेड फंक्शन के अंदर कुछ उपयोगी, लेकिन इसे कॉल करने के अलावा इसके बाहर बिल्कुल कुछ भी नहीं किया। (वास्तविक कोड यहां पाया जा सकता है ।) कोई इसे इस तरह कोड क्यों दे सकता है? क्या बाहरी, सामान्य फ़ंक्शन के बजाय नेस्टेड फ़ंक्शन के अंदर कोड लिखने के लिए कुछ लाभ या दुष्प्रभाव हैं?


4
क्या यह वास्तविक कोड आपको मिला है, या आपके द्वारा निर्मित एक सरलीकृत उदाहरण है?
मेक

इसका एक सरल उदाहरण है। वास्तविक कोड यहां पाया जा सकता है: bazaar.launchpad.net/%7Eopenerp/openobject-server/trunk/…
ऐली

2
आपका लिंक (जो HEAD की ओर इशारा करता है) अब सटीक नहीं है। कोशिश करें: bazaar.launchpad.net/~openerp/openobject-server/trunk/annotate/…
क्रेग मैकक्वीन

आप सही क्रेग हैं। धन्यवाद।
होसाम ऐली

जवाबों:


113

आम तौर पर आप इसे बंद करने के लिए करते हैं :

def make_adder(x):
    def add(y):
        return x + y
    return add

plus5 = make_adder(5)
print(plus5(12))  # prints 17

इनर फ़ंक्शंस वैरिएबल के दायरे (इस मामले में, स्थानीय वैरिएबल x) से चर तक पहुँच सकते हैं । यदि आप किसी भी चर को एंक्लोजिंग स्कोप से एक्सेस नहीं कर रहे हैं, तो वे वास्तव में एक अलग स्कोप वाले साधारण कार्य हैं।


5
उस के लिए मैं भाग्यांक पसंद करूंगा plus5 = functools.partial(operator.add, 5):। सज्जाकार क्लोजर के लिए एक बेहतर उदाहरण होगा।
जोहान रिट्जेल

4
धन्यवाद, लेकिन जैसा कि आप पोस्ट किए गए स्निपेट में देख सकते हैं, यहां ऐसा नहीं है: नेस्टेड फ़ंक्शन को बस बाहरी फ़ंक्शन में बुलाया जा रहा है।
होसम ऐली

58

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

खिलौना उदाहरण:

import sys

def Foo():
    def e(s):
        sys.stderr.write('ERROR: ')
        sys.stderr.write(s)
        sys.stderr.write('\n')
    e('I regret to inform you')
    e('that a shameful thing has happened.')
    e('Thus, I must issue this desultory message')
    e('across numerous lines.')
Foo()

4
एकमात्र समस्या यह है कि यह कभी-कभी इकाई परीक्षण के लिए कठिन बना सकता है, क्योंकि आप आंतरिक फ़ंक्शन तक नहीं पहुंच सकते हैं।
चैलेंजर 5

1
वो कितनी प्यारी लग रही हैं!
शंकु

1
FWIY @ Challenger5 अगर अंदरूनी कार्य निजी वर्ग के कार्यों के अनुरूप है, तो वे वैसे भी इकाई-परीक्षण नहीं होते हैं। मैंने तरीकों को और अधिक पठनीय बनाने के लिए ऐसा करना शुरू कर दिया है, जबकि परिभाषा को विधि के करीब रखा है।
मिशेल करी

27

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

def helper(feature, resultBuffer):
  resultBuffer.print(feature)
  resultBuffer.printLine()
  resultBuffer.flush()

def save(item, resultBuffer):

  helper(item.description, resultBuffer)
  helper(item.size, resultBuffer)
  helper(item.type, resultBuffer)

निम्नानुसार लिखा जा सकता है, जो यकीनन बेहतर पढ़ता है

def save(item, resultBuffer):

  def helper(feature):
    resultBuffer.print(feature)
    resultBuffer.printLine()
    resultBuffer.flush()

  helper(item.description)
  helper(item.size)
  helper(item.type)

8

मैं उस तरह के कोड के लिए किसी भी अच्छे कारण की छवि नहीं बना सकता।

शायद पुराने संशोधनों में आंतरिक कार्य का एक कारण था, अन्य ऑप्स की तरह।

उदाहरण के लिए, यह थोड़ा और अधिक समझ में आता है:

class some_class(parent_class):
    def doOp(self, op, x, y):
        def add(x, y):
            return x + y
        def sub(x,y):
            return x - y
        return locals()[op](x,y)

some_class().doOp('add', 1,2)

लेकिन तब आंतरिक फ़ंक्शन ("निजी") श्रेणी के तरीकों के बजाय होना चाहिए:

class some_class(object):
    def _add(self, x, y):
        return x + y
    def doOp(self, x, y):
        return self._add(x,y)

हाँ, शायद doOp ने तर्क देने के लिए किस ऑपरेटर का उपयोग करने के लिए एक स्ट्रिंग ली ...
Skilldrick

1
@ArtOfWarfare यह केवल मॉड्यूल का उपयोग करने के लिए पसंद किया जाता है। कक्षाएं राज्य के लिए हैं।
ऐहलके

6

स्थानीय विधियों के पीछे का विचार स्थानीय चर के समान है: बड़े नाम स्थान को प्रदूषित न करें। जाहिर है कि लाभ सीमित हैं क्योंकि अधिकांश भाषाएं सीधे ऐसी कार्यक्षमता प्रदान नहीं करती हैं।


1

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


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