क्या पायथन में एक समारोह को अग्रेषित करना संभव है?


189

क्या पायथन में एक समारोह को अग्रेषित करना संभव है? मैं cmpघोषित होने से पहले अपने स्वयं के फ़ंक्शन का उपयोग करके एक सूची को सॉर्ट करना चाहता हूं ।

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

मैंने cmp_configsआह्वान के बाद विधि की परिभाषा रखने के लिए अपना कोड व्यवस्थित किया है । यह इस त्रुटि से विफल होता है:

NameError: name 'cmp_configs' is not defined

क्या cmp_configsइसका इस्तेमाल करने से पहले "घोषित" करने का कोई तरीका है ? यह मेरे कोड को साफ कर देगा?

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

इस मामले पर विचार करें जहां आगे की घोषणा करना पायथन में आवश्यक होगा:

def spam():
    if end_condition():
        return end_result()
    else:
        return eggs()

def eggs():
    if end_condition():
        return end_result()
    else:
        return spam()

कहां end_conditionऔर end_resultपहले परिभाषित किया गया है।

क्या कोड को पुनर्गठित करने और हमेशा इनवोकेशन से पहले परिभाषाएँ रखने का एकमात्र समाधान है?

जवाबों:


76

यदि आप इसे उपयोग करने से पहले किसी फ़ंक्शन को परिभाषित नहीं करना चाहते हैं , और इसे बाद में परिभाषित करना असंभव है, तो इसे किसी अन्य मॉड्यूल में परिभाषित करने के बारे में क्या है?

तकनीकी रूप से आप अभी भी इसे पहले परिभाषित करते हैं, लेकिन यह साफ है।

आप निम्नलिखित की तरह एक पुनरावृत्ति बना सकते हैं:

def foo():
    bar()

def bar():
    foo()

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

उपरोक्त कोड में, foo()foo नाम के साथ एक फ़ंक्शन को कॉल नहीं किया जाता है, यह एक फ़ंक्शन को कॉल करता है जो fooउस बिंदु पर नाम से बाध्य होता है जिसे कॉल किया जाता है। fooकहीं और फिर से परिभाषित करना संभव है , और barफिर नए फ़ंक्शन को कॉल करेगा।

आपकी समस्या हल नहीं हो सकती है क्योंकि यह एक वैरिएबल प्राप्त करने के लिए कहने जैसा है जिसे घोषित नहीं किया गया है।


47
संक्षेप में, अगर आपके पास अगर __name__ == '__main__': main () आपकी स्क्रिप्ट में अंतिम पंक्ति के रूप में सब कुछ ठीक हो जाएगा!
फिल्पा पीना

3
@FilipePina मैंने आपकी टिप्पणी को नहीं समझा है - आप कोड की अंतिम पंक्ति को बस के रूप में क्यों नहीं डाल सकते हैं main()?
संजय मनोहर

11
@ संजयमनोहर: इसे अंजाम देने से बचने के लिएimport your_module
jfs

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

2
राइट "अनाम", आप वास्तव में "प्रथम श्रेणी की वस्तुओं" का मतलब है।
डैनियल

118

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

इसलिए कि

foo()

def foo():
    print "Hi!"

टूट जाएगा, लेकिन

def bar():
    foo()

def foo():
    print "Hi!"

bar()

ठीक से काम कर रहा होगा।

सामान्य नियम Pythonयह नहीं है कि फ़ंक्शन को कोड (जैसा कि Pascal) में उच्च परिभाषित किया जाना चाहिए , लेकिन यह कि इसके उपयोग से पहले इसे परिभाषित किया जाना चाहिए।

उम्मीद है की वो मदद करदे।


20
+1 सबसे प्रत्यक्ष उत्तर, कीस्टोन अवधारणा के साथ: पास्कल = उच्च परिभाषित करें, पायथन = पहले परिभाषित करें।
बॉब स्टीन

1
यह सही उत्तर है, यह भी बताता है कि if __name__=="__main__":समाधान क्यों काम करता है।
00prometheus

2
अगर मैं सही तरीके से समझूं, तो इसका मतलब है कि ओपी का स्पैम () और अंडे () का उदाहरण ठीक है जैसा लिखा है। क्या वो सही है?
क्रुबो

1
@krubo हाँ, यह ठीक है जैसा लिखा है
lxop

92

यदि आप निम्नलिखित के माध्यम से अपनी स्क्रिप्ट को किक-स्टार्ट करते हैं:

if __name__=="__main__":
   main()

फिर आपको "आगे की घोषणा" जैसी चीजों के बारे में चिंता करने की ज़रूरत नहीं है। आप देखते हैं, दुभाषिया आपके सभी कार्यों को लोड करने जाएगा और फिर अपना मुख्य () फ़ंक्शन शुरू करेगा। बेशक, सुनिश्चित करें कि आपके पास सभी आयात सही हैं; ;-)

यह सोचने के लिए आओ, मैंने अजगर में "आगे की घोषणा" जैसी कोई बात नहीं सुनी है ... लेकिन फिर, मैं गलत हो सकता हूं; ;-)


14
+1 सबसे व्यावहारिक उत्तर: यदि आप इस कोड को सबसे बाहरी स्रोत फ़ाइल के नीचे रखते हैं, तो आप किसी भी क्रम में परिभाषित करने के लिए स्वतंत्र हैं।
बॉब स्टीन

2
महान टिप; वास्तव में मेरी मदद करता है; के रूप में मैं बहुत अधिक "ऊपर से नीचे" प्रोग्रामिंग बनाम नीचे पसंद करते हैं।
घोस्टकट

10

यदि cmp_configs पर कॉल करना अपनी स्वयं की फ़ंक्शन परिभाषा के अंदर है, तो आपको ठीक होना चाहिए। मैं एक उदाहरण दूंगा।

def a():
  b()  # b() hasn't been defined yet, but that's fine because at this point, we're not
       # actually calling it. We're just defining what should happen when a() is called.

a()  # This call fails, because b() hasn't been defined yet, 
     # and thus trying to run a() fails.

def b():
  print "hi"

a()  # This call succeeds because everything has been defined.

सामान्य तौर पर, अपने कोड को कार्यों के अंदर रखना (जैसे मुख्य ()) आपकी समस्या को हल करेगा; फ़ाइल के अंत में केवल मुख्य कॉल करें।


10

मैं इस धागे को पुनर्जीवित करने के लिए माफी चाहता हूं, लेकिन यहां एक रणनीति पर चर्चा नहीं की गई जो लागू हो सकती है।

प्रतिबिंब का उपयोग करके आगे की घोषणा के लिए कुछ करना संभव है। उदाहरण के लिए, मान लें कि आपके पास एक ऐसा कोड है जो इस तरह दिखता है:

# We want to call a function called 'foo', but it hasn't been defined yet.
function_name = 'foo'
# Calling at this point would produce an error

# Here is the definition
def foo():
    bar()

# Note that at this point the function is defined
    # Time for some reflection...
globals()[function_name]()

तो इस तरह से हमने यह निर्धारित किया है कि वास्तव में परिभाषित होने से पहले हम किस फ़ंक्शन को कॉल करना चाहते हैं, प्रभावी रूप से एक आगे की घोषणा। अजगर में कथन globals()[function_name]()वैसा ही है जैसा foo()कि function_name = 'foo'ऊपर चर्चा किए गए कारणों से है, क्योंकि अजगर को कॉल करने से पहले प्रत्येक फ़ंक्शन को देखना होगा। यदि कोई timeitइन दो बयानों की तुलना करने के लिए मॉड्यूल का उपयोग करता है , तो उनके पास समान कम्प्यूटेशनल लागत है।

बेशक यहाँ उदाहरण बहुत ही बेकार है, लेकिन अगर किसी के पास एक जटिल संरचना होती है जिसे किसी कार्य को निष्पादित करने की आवश्यकता होती है, लेकिन इसे पहले घोषित किया जाना चाहिए (या संरचनात्मक रूप से इसे बाद में होने के लिए बहुत कम अर्थ है), एक बस एक स्ट्रिंग और स्टोर कर सकता है बाद में फ़ंक्शन को कॉल करने का प्रयास करें।


8

अजगर में आगे की घोषणा जैसी कोई बात नहीं है। आपको केवल यह सुनिश्चित करना होगा कि आपके फ़ंक्शन को आवश्यक होने से पहले घोषित किया गया है। ध्यान दें कि फ़ंक्शन निष्पादित होने तक किसी फ़ंक्शन की व्याख्या नहीं की जाती है।

निम्नलिखित उदाहरण पर विचार करें:

def a():
   b() # won't be resolved until a is invoked.

def b(): 
   print "hello"

a() # here b is already defined so this line won't fail.

आप सोच सकते हैं कि एक फ़ंक्शन का एक निकाय केवल एक और स्क्रिप्ट है जिसे फ़ंक्शन को कॉल करने के बाद व्याख्या की जाएगी।


7

नहीं, मुझे विश्वास नहीं है कि पायथन में एक समारोह को आगे बढ़ाने का कोई तरीका है।

कल्पना कीजिए कि आप पायथन दुभाषिया हैं। जब आप लाइन में लग जाते हैं

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

या तो आप जानते हैं कि cmp_configs क्या है या आप नहीं करते हैं। आगे बढ़ने के लिए, आपको cmp_configs जानना होगा। इससे कोई फर्क नहीं पड़ता कि क्या पुनरावृत्ति है।


9
अच्छी तरह से यह है अगर आपके कोड पर केवल एक ही कर रहा है। कुछ संकलक (और मुझे लगता है कि व्याख्या में अजगर) दो पास करते हैं, ताकि इन चीजों का पता लगाया जा सके। फॉरवर्ड-डिक्लेरेशन या कम से कम किसी तरह की स्कॉप्ड डिस्कवरी वास्तव में अच्छी होगी।
मार्क Lakewood

7

कभी-कभी एक एल्गोरिथ्म शीर्ष-डाउन को समझना सबसे आसान है, समग्र संरचना से शुरू होता है और विवरण में नीचे ड्रिलिंग होता है।

आप आगे की घोषणाओं के बिना ऐसा कर सकते हैं:

def main():
  make_omelet()
  eat()

def make_omelet():
  break_eggs()
  whisk()
  fry()

def break_eggs():
  for egg in carton:
    break(egg)

# ...

main()

4
# declare a fake function (prototype) with no body
def foo(): pass

def bar():
    # use the prototype however you see fit
    print(foo(), "world!")

# define the actual function (overwriting the prototype)
def foo():
    return "Hello,"

bar()

आउटपुट:

Hello, world!

3

आप पायथन में एक समारोह को अग्रेषित नहीं कर सकते। यदि आपके पास फ़ंक्शंस को परिभाषित करने से पहले लॉजिक एग्जीक्यूटिंग है, तो आपको शायद एक समस्या है। if __name__ == '__main__'अपनी स्क्रिप्ट के अंत में अपनी कार्रवाई रखें (यदि आप गैर-तुच्छ हैं तो "मुख्य" नाम से एक फ़ंक्शन निष्पादित करके और आपका कोड अधिक मॉड्यूलर होगा और आप कभी भी ज़रूरत पड़ने पर इसे मॉड्यूल के रूप में उपयोग कर पाएंगे सेवा।

इसके अलावा, एक जनरेटर एक्सप्रेस (यानी, print "\n".join(str(bla) for bla in sorted(mylist, cmp=cmp_configs))) के साथ उस सूची की समझ को बदलें

इसके अलावा, उपयोग न करें cmp, जो पदावनत है। keyकम-से-कम फ़ंक्शन का उपयोग करें और प्रदान करें ।


मैं कम-से-कम फ़ंक्शन कैसे प्रदान कर सकता हूं?
नाथन फ़ेलमैन

Cmp_configs के बजाय, आप एक फ़ंक्शन को परिभाषित करेंगे जो दो तर्क लेता है और सही है अगर पहला दूसरे से कम है और अन्यथा गलत है।
माइक ग्राहम

C- जैसी पृष्ठभूमि से आने वाले हम में से, फ़ंक्शंस परिभाषित होने से पहले तर्क निष्पादित करने के बारे में कुछ भी अनुचित नहीं है। सोचो: "मल्टी-पास कंपाइलर"। कभी-कभी नई भाषाओं के अनुकूल होने में थोड़ा समय लगता है :)
ल्यूक एच

3

फ़ाइल को ही आयात करें। फ़ाइल को मान लेना test.py कहा जाता है:

import test

if __name__=='__main__':
    test.func()
else:
    def func():
        print('Func worked')

1

"बस मेरे कोड को पुनर्गठित करें ताकि मुझे यह समस्या न हो।" सही बात। करने में आसान। हमेशा काम करता है।

आप हमेशा संदर्भ से पहले फ़ंक्शन प्रदान कर सकते हैं।

"हालांकि, ऐसे मामले हैं जब यह संभव नहीं है, उदाहरण के लिए जब पुनरावर्तन के कुछ रूपों को लागू किया जाता है"

देख नहीं सकते कि यह कैसे दूर से भी संभव है। कृपया उस स्थान का उदाहरण प्रदान करें जहाँ आप उपयोग करने से पहले फ़ंक्शन को परिभाषित नहीं कर सकते हैं।


मेरी ऐसी स्थिति है। मैं फ़ंक्शन डेकोरेटर में प्रकारों को पारित करने की कोशिश कर रहा हूं, और प्रकारों को मॉड्यूल के नीचे परिभाषित किया गया है। मैं आपत्तिजनक प्रकारों को आगे नहीं बढ़ा सकता, क्योंकि यह वंशानुक्रम श्रृंखला को तोड़ देगा।
जो

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

0

अब एक मिनट रुकिए। जब आपका मॉड्यूल आपके उदाहरण में प्रिंट स्टेटमेंट तक पहुंचता है, तो cmp_configsपरिभाषित होने से पहले , वास्तव में ऐसा क्या है जो आप इसे करने की उम्मीद करते हैं?

यदि प्रिंट का उपयोग करके किसी प्रश्न की आपकी पोस्टिंग वास्तव में कुछ इस तरह का प्रतिनिधित्व करने की कोशिश कर रही है:

fn = lambda mylist:"\n".join([str(bla)
                         for bla in sorted(mylist, cmp = cmp_configs)])

तब cmp_configsइस कथन को निष्पादित करने से पहले परिभाषित करने की कोई आवश्यकता नहीं है , बस बाद में इसे कोड में परिभाषित करें और सब ठीक हो जाएगा।

अब यदि आप cmp_configsलंबोदर के तर्क के डिफ़ॉल्ट मान के रूप में संदर्भित करने का प्रयास कर रहे हैं , तो यह एक अलग कहानी है:

fn = lambda mylist,cmp_configs=cmp_configs : \
    "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

अब आपको cmp_configsइस लाइन तक पहुँचने से पहले एक वैरिएबल को परिभाषित करने की आवश्यकता है ।

[संपादित करें - यह अगला भाग सही नहीं निकला, क्योंकि फ़ंक्शन के संकलित होने पर डिफ़ॉल्ट तर्क मान असाइन किया जाएगा, और उस मूल्य का उपयोग तब भी किया जाएगा जब आप बाद में cmp_configs का मान बदल देते हैं।]

सौभाग्य से, पायथन इतना टाइप-एडजस्ट हो रहा है, यह परवाह नहीं करता कि आप क्या परिभाषित करते हैं cmp_configs, इसलिए आप इस कथन के साथ प्रस्तावना कर सकते हैं:

cmp_configs = None

और कंपाइलर खुश हो जाएगा। बस cmp_configsआपको कभी भी आह्वान करने से पहले वास्तविक घोषित करना सुनिश्चित करें fn


-1

एक तरीका हैंडलर फंक्शन बनाना है। हैंडलर को जल्दी परिभाषित करें, और हैंडलर को उन सभी तरीकों से नीचे रखें, जिन्हें आपको कॉल करने की आवश्यकता है।

फिर जब आप अपने कार्यों को कॉल करने के लिए हैंडलर विधि लागू करते हैं, तो वे हमेशा उपलब्ध रहेंगे।

हैंडलर एक तर्क ले सकता है nameOfMethodToCall। यदि सही विधि को कॉल करने के लिए कथनों का एक समूह उपयोग करता है।

इससे आपकी समस्या हल हो जाएगी।

def foo():
    print("foo")
    #take input
    nextAction=input('What would you like to do next?:')
    return nextAction

def bar():
    print("bar")
    nextAction=input('What would you like to do next?:')
    return nextAction

def handler(action):
    if(action=="foo"):
        nextAction = foo()
    elif(action=="bar"):
        nextAction = bar()
    else:
        print("You entered invalid input, defaulting to bar")
        nextAction = "bar"
    return nextAction

nextAction=input('What would you like to do next?:')

while 1:
    nextAction = handler(nextAction)

यह बहुत ही बेकार लगता है। अजगर को इस तरह के सामान को अपने आप संभालना चाहिए।
नाथन फ़ेलमैन

स्वीकृत उत्तर को पुनः पढ़ें। पायथन को फ़ंक्शन को तब तक परिभाषित करने की आवश्यकता नहीं है जब तक आप इसे कॉल नहीं करते हैं, न कि केवल परिभाषा में इसका उपयोग करें।
ताकसवेल

-3

हां, हम इसकी जांच कर सकते हैं।

इनपुट

print_lyrics() 
def print_lyrics():

    print("I'm a lumberjack, and I'm okay.")
    print("I sleep all night and I work all day.")

def repeat_lyrics():
    print_lyrics()
    print_lyrics()
repeat_lyrics()

उत्पादन

I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.

जैसा कि बीजे होमर ने उपरोक्त टिप्पणियों पर उल्लेख किया है, पायथन में एक सामान्य नियम यह नहीं है कि फ़ंक्शन को कोड में उच्चतर (पास्कल में) के रूप में परिभाषित किया जाना चाहिए, लेकिन यह कि इसके उपयोग से पहले इसे परिभाषित किया जाना चाहिए।

उम्मीद है की वो मदद करदे।


2
print_lyrics()परिभाषित होने से पहले लाइन 1 में (उपयोग) नहीं कहा जाता है? मैंने इस कोड को कॉपी किया और इसे चलाने की कोशिश की, और यह मुझे NameError: name 'print_lyrics' is not definedलाइन 1 पर त्रुटि देता है । क्या आप इसे समझा सकते हैं?
बग्स बग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.