मैं पायथन कोड के गतिशील मूल्यांकन को देख रहा हूं , और यह फ़ंक्शन eval()और compile()फ़ंक्शन और execकथन पर आ रहा है।
क्या कोई कृपया evalऔर के बीच अंतर की व्याख्या कर सकता है exec, और कैसे compile()फिट के विभिन्न तरीके ?
मैं पायथन कोड के गतिशील मूल्यांकन को देख रहा हूं , और यह फ़ंक्शन eval()और compile()फ़ंक्शन और execकथन पर आ रहा है।
क्या कोई कृपया evalऔर के बीच अंतर की व्याख्या कर सकता है exec, और कैसे compile()फिट के विभिन्न तरीके ?
जवाबों:
मूल रूप से, evalकरने के लिए प्रयोग किया जाता है eval uate एक भी गतिशील रूप से उत्पन्न अजगर अभिव्यक्ति, और execकरने के लिए प्रयोग किया जाता है कार्यकारी उटे गतिशील केवल अपने साइड इफेक्ट के लिए अजगर कोड उत्पन्न।
evalऔर execये दो अंतर हैं:
evalकेवल एक ही अभिव्यक्ति को स्वीकार करता है , execएक कोड ब्लॉक ले सकता है जिसमें पायथन कथन हैं: लूप्स try: except:, classऔर फ़ंक्शन / विधि definitions और इतने पर।
पाइथन में एक अभिव्यक्ति वह है जो आप एक चर असाइनमेंट में मान के रूप में ले सकते हैं:
a_variable = (anything you can put within these parentheses is an expression)eval दिए गए अभिव्यक्ति के मूल्य को लौटाता है , जबकि execइसके कोड से वापसी मूल्य को अनदेखा करता है, और हमेशा रिटर्न करता है None(पायथन 2 में यह एक बयान है और इसे अभिव्यक्ति के रूप में उपयोग नहीं किया जा सकता है, इसलिए यह वास्तव में कुछ भी वापस नहीं करता है)।
1.0 - 2.7 संस्करणों में, execएक बयान था, क्योंकि सीपीथॉन execको फ़ंक्शन के अंदर उपयोग किए जाने वाले कार्यों के लिए एक अलग तरह की कोड ऑब्जेक्ट का उत्पादन करने की आवश्यकता थी ।
पायथन 3 में, execएक फ़ंक्शन है; इसका उपयोग फ़ंक्शन के संकलित बायटेकोड पर कोई प्रभाव नहीं पड़ता है जहां इसका उपयोग किया जाता है।
इस प्रकार मूल रूप से:
>>> a = 5
>>> eval('37 + a') # it is an expression
42
>>> exec('37 + a') # it is an expression statement; value is ignored (None is returned)
>>> exec('a = 47') # modify a global variable as a side effect
>>> a
47
>>> eval('a = 47') # you cannot evaluate a statement
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
a = 47
^
SyntaxError: invalid syntax
compileमें 'exec'मोड एक बाईटकोड में बयान के किसी भी संख्या को संकलित करता है कि परोक्ष हमेशा रिटर्न None, जबकि में 'eval'मोड यह एक संकलित एकल बाईटकोड में अभिव्यक्ति है कि रिटर्न कि अभिव्यक्ति के मूल्य।
>>> eval(compile('42', '<string>', 'exec')) # code returns None
>>> eval(compile('42', '<string>', 'eval')) # code returns 42
42
>>> exec(compile('42', '<string>', 'eval')) # code returns 42,
>>> # but ignored by exec
में 'eval'(और इस प्रकार के साथ मोड evalसमारोह अगर एक स्ट्रिंग में पारित हो जाता है), compileएक अपवाद है, तो स्रोत कोड बयान या एक ही अभिव्यक्ति से परे कुछ और होता है को जन्म देती है:
>>> compile('for i in range(3): print(i)', '<string>', 'eval')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print(i)
^
SyntaxError: invalid syntax
वास्तव में " बयान केवल एक ही अभिव्यक्ति को स्वीकार करता है" केवल तब लागू होता है जब एक स्ट्रिंग (जिसमें पायथन स्रोत कोड होता है ) पारित हो जाता है eval। तब यह आंतरिक रूप से बायटेकोड पर संकलित होता है compile(source, '<string>', 'eval')यह वह जगह है जहां अंतर वास्तव में आता है।
एक तो codeवस्तु (जो अजगर शामिल बाईटकोड ) में भेजा जाता है execया eval, वे समान रूप से व्यवहार , तथ्य यह है कि के लिए छोड़कर execवापसी मान पर ध्यान नहीं देता है, अभी भी लौटने Noneहमेशा। तो यह संभव evalहै कि किसी चीज को निष्पादित करने के लिए इसका उपयोग किया जाए, यदि आप compileइसे स्ट्रिंग के रूप में पारित करने के बजाय इसे बाइटकोड में डी करते हैं:
>>> eval(compile('if 1: print("Hello")', '<string>', 'exec'))
Hello
>>>
समस्याओं के बिना काम करता है, भले ही संकलित कोड में कथन हों। यह अभी भी लौटाता है None, क्योंकि यह उस कोड ऑब्जेक्ट का रिटर्न वैल्यू है जो से लौटा है compile।
में 'eval'(और इस प्रकार के साथ मोड evalसमारोह अगर एक स्ट्रिंग में पारित हो जाता है), compileएक अपवाद है, तो स्रोत कोड बयान या एक ही अभिव्यक्ति से परे कुछ और होता है को जन्म देती है:
>>> compile('for i in range(3): print(i)', '<string>'. 'eval')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print(i)
^
SyntaxError: invalid syntax
exec तथा evalexecसमारोह (जो था अजगर 2 में एक बयान ) एक डायनामिक रूप से तैयार बयान या कार्यक्रम को क्रियान्वित करने के लिए प्रयोग किया जाता है:
>>> program = '''
for i in range(3):
print("Python is cool")
'''
>>> exec(program)
Python is cool
Python is cool
Python is cool
>>>
evalसमारोह एक के लिए एक ही करता है एक अभिव्यक्ति , और अभिव्यक्ति का मान देता है:
>>> a = 2
>>> my_calculation = '42 * a'
>>> result = eval(my_calculation)
>>> result
84
execऔर evalदोनों को स्वीकार कार्यक्रम / अभिव्यक्ति एक के रूप में या तो चलाने के लिए किया जा str, unicodeया bytesऑब्जेक्ट वाला स्रोत कोड, या एक के रूप में codeवस्तु जो अजगर बाईटकोड में शामिल है।
यदि str/ a / unicode/ bytesयुक्त स्रोत कोड पास किया गया था exec, तो यह इसके साथ समान व्यवहार करता है:
exec(compile(source, '<string>', 'exec'))
और evalइसी तरह के बराबर व्यवहार करता है:
eval(compile(source, '<string>', 'eval'))
चूंकि सभी अभिव्यक्तियों को पायथन में बयानों के रूप में इस्तेमाल किया जा सकता है (इन्हें Exprपायथन अमूर्त व्याकरण में नोड्स कहा जाता है ; विपरीत सच नहीं है), आप हमेशा उपयोग कर सकते हैं execयदि आपको रिटर्न वैल्यू की आवश्यकता नहीं है। यह कहना है, आप eval('my_func(42)')या तो उपयोग कर सकते हैं exec('my_func(42)'), या अंतर जो evalरिटर्न द्वारा दिए गए मूल्य को लौटाता है my_func, और execइसे छोड़ देता है:
>>> def my_func(arg):
... print("Called with %d" % arg)
... return arg * 2
...
>>> exec('my_func(42)')
Called with 42
>>> eval('my_func(42)')
Called with 42
84
>>>
2 में से सिर्फ execस्रोत कोड है कि बयान, शामिल स्वीकार करता है की तरह def, for, while, import, या class, असाइनमेंट बयान (उर्फ a = 42) या संपूर्ण कार्यक्रम:
>>> exec('for i in range(3): print(i)')
0
1
2
>>> eval('for i in range(3): print(i)')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print(i)
^
SyntaxError: invalid syntax
दोनों execऔर eval2 अतिरिक्त स्थितिगत तर्क स्वीकार करते हैं - globalsऔर locals- जो कि वैश्विक और स्थानीय चर स्कोप हैं जो कोड देखता है। ये उस स्कोप के भीतर globals()और locals()उस दायरे के भीतर हैं, जिसे execया तो कहा जाता है eval, लेकिन किसी भी शब्दकोष का इस्तेमाल किया जा सकता है globalsऔर इसके mappingलिए locals( dictपाठ्यक्रम सहित )। इनका उपयोग न केवल उन चर को प्रतिबंधित / संशोधित करने के लिए किया जा सकता है जिन्हें कोड देखता है, बल्कि अक्सर उन चर को कैप्चर करने के लिए भी उपयोग किया जाता है जिन्हें execयूटर्ड कोड बनाता है:
>>> g = dict()
>>> l = dict()
>>> exec('global a; a, b = 123, 42', g, l)
>>> g['a']
123
>>> l
{'b': 42}
(आप पूरे के मान प्रदर्शित करते हैं g, यह बहुत लंबे समय तक होगा क्योंकि execऔर evalजोड़ने का निर्माण-इन के रूप में मॉड्यूल __builtins__वैश्विक स्वचालित रूप से अगर यह याद आ रही है के लिए)।
पायथन 2 में, execबयान के लिए आधिकारिक वाक्यविन्यास वास्तव में exec code in globals, locals, जैसा कि है
>>> exec 'global a; a, b = 123, 42' in g, l
हालाँकि वैकल्पिक वाक्यविन्यास exec(code, globals, locals)को हमेशा स्वीकार किया गया है (नीचे देखें)।
compilecompile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)बिल्ट-इन के साथ एक ही कोड के बार-बार आमंत्रण तेजी लाने के लिए इस्तेमाल किया जा सकता execहै या evalएक में स्रोत संकलन के द्वारा codeपहले से वस्तु। modeपैरामीटर नियंत्रण कोड टुकड़ा की तरह compileसमारोह स्वीकार करता है और के बाईटकोड यह पैदा करता तरह। विकल्प हैं 'eval', 'exec'और 'single':
'eval'मोड एक एकल अभिव्यक्ति की उम्मीद करता है, और जब वह उस अभिव्यक्ति के मूल्य को लौटाएगा तो बायटेकोड का उत्पादन करेगा :
>>> dis.dis(compile('a + b', '<string>', 'eval'))
1 0 LOAD_NAME 0 (a)
3 LOAD_NAME 1 (b)
6 BINARY_ADD
7 RETURN_VALUE'exec'किसी भी प्रकार के अजगर निर्माण को एकल अभिव्यक्तियों से लेकर कोड के पूरे मॉड्यूल तक स्वीकार करता है, और उन्हें निष्पादित करता है जैसे कि वे मॉड्यूल शीर्ष-स्तरीय वक्तव्य थे। कोड ऑब्जेक्ट रिटर्न None:
>>> dis.dis(compile('a + b', '<string>', 'exec'))
1 0 LOAD_NAME 0 (a)
3 LOAD_NAME 1 (b)
6 BINARY_ADD
7 POP_TOP <- discard result
8 LOAD_CONST 0 (None) <- load None on stack
11 RETURN_VALUE <- return top of stack'single'इसका एक सीमित रूप 'exec'एक स्रोत कोड को स्वीकार करता है , जिसमें एकल कथन (या एकाधिक स्टेटमेंट्स को अलग किया जाता है ;) यदि अंतिम स्टेटमेंट एक एक्सप्रेशन स्टेटमेंट है, तो परिणामस्वरूप बायटेकोड उस अभिव्यक्ति के मान को मानक आउटपुट (!) पर भी प्रिंट करता reprहै ।
एक if- elif- elseश्रृंखला, एक लूप के साथ else, और tryइसके साथ except, elseऔर finallyब्लॉकों को एक ही कथन माना जाता है।
2 शीर्ष-स्तरीय बयानों वाले स्रोत के टुकड़े के लिए एक त्रुटि है 'single', पायथन 2 को छोड़कर एक बग है जो कभी-कभी कोड में कई टॉपवेल बयानों की अनुमति देता है; केवल पहला संकलित है; बाकी को नजरअंदाज किया जाता है:
पायथन में 2.7.8:
>>> exec(compile('a = 5\na = 6', '<string>', 'single'))
>>> a
5
और पायथन 3.4.2 में:
>>> exec(compile('a = 5\na = 6', '<string>', 'single'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
a = 5
^
SyntaxError: multiple statements found while compiling a single statement
यह इंटरैक्टिव पायथन गोले बनाने के लिए बहुत उपयोगी है। हालाँकि, अभिव्यक्ति का मान वापस नहीं किया जाता है , भले ही आप evalपरिणामी कोड हों।
इस प्रकार सबसे बड़ा अंतर है execऔर evalवास्तव में compileकार्य और इसके तरीकों से आता है ।
स्रोत कोड को बायटेकोड पर संकलित करने के अलावा, वस्तुओं में सार सिंटैक्स ट्री (पाइथन कोड के पार्स ट्री) compileको संकलित करने का समर्थन करता है ; और अमूर्त सिंटैक्स पेड़ों में स्रोत कोड ( पायथन में लिखा गया है और बस कॉल ); उदाहरण के लिए मक्खी पर स्रोत कोड को संशोधित करने के लिए और गतिशील कोड निर्माण के लिए भी उपयोग किया जाता है, क्योंकि अक्सर जटिल मामलों में पाठ की पंक्तियों के बजाय नोड्स के पेड़ के रूप में कोड को संभालना आसान होता है।codeast.parsecompile(source, filename, mode, PyCF_ONLY_AST)
जबकि evalकेवल आपको एक स्ट्रिंग का मूल्यांकन करने की अनुमति देता है जिसमें एक एकल अभिव्यक्ति होती है, आप evalएक पूरे बयान, या यहां तक कि एक पूरे मॉड्यूल को भी शामिल कर सकते हैं जो compileडीटेकोडे में गया है; पायथन 2 के साथ, printयह एक बयान है, और evalसीधे नेतृत्व नहीं किया जा सकता है:
>>> eval('for i in range(3): print("Python is cool")')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print("Python is cool")
^
SyntaxError: invalid syntax
compileयह 'exec'एक codeवस्तु में मोड के साथ और आप eval यह कर सकते हैं ; evalसमारोह वापस आ जाएगी None।
>>> code = compile('for i in range(3): print("Python is cool")',
'foo.py', 'exec')
>>> eval(code)
Python is cool
Python is cool
Python is cool
में एक लग रहा है evalऔर execCPython 3 में स्रोत कोड, यह बहुत स्पष्ट है; वे दोनों PyEval_EvalCodeएक ही तर्क के साथ कहते हैं , एकमात्र अंतर जो execस्पष्ट रूप से लौटता हैNone ।
execपायथन 2 और पायथन 3 के बीच के सिंटैक्स अंतरपायथन 2 में एक प्रमुख अंतर यह है कि execएक बयान है और evalएक अंतर्निहित कार्य है (दोनों पायथन 3 में अंतर्निहित कार्य हैं)। यह एक सर्वविदित तथ्य है कि execपायथन 2 का आधिकारिक वाक्य विन्यास है exec code [in globals[, locals]]।
अजगर के बहुमत के विपरीत 2 से 3 पोर्टिंग गाइड का सुझाव लगता है , execसीपीथॉन 2 में बयान को वाक्यविन्यास के साथ भी इस्तेमाल किया जा सकता है जो बिल्कुल पायथन 3 में फ़ंक्शन आह्वान की तरह दिखता हैexec । इसका कारण यह है कि पायथन 0.9.9 ने exec(code, globals, locals)बनाया था- समारोह में! और उस अंतर्निहित समारोह को पायथन 1.0 रिलीज से पहले कहींexec बयान के साथ बदल दिया गया था ।
चूंकि यह अजगर 0.9.9 के साथ पीछे संगतता को नहीं करने के लिए वांछनीय था, गुइडो van Rossum 1993 में एक संगतता हैक जोड़ा : अगर codeलंबाई 2 या 3 के एक टपल था, और globalsऔर localsमें पारित नहीं हुए execअन्यथा बयान codeमें दर्शाया जाएगा के रूप में अगर टपल के 2 और 3 तत्व थे globalsऔर localsक्रमशः। पाइथन 1.4 डॉक्यूमेंटेशन (जल्द से जल्द उपलब्ध ऑनलाइन संस्करण) में भी संगतता हैक का उल्लेख नहीं किया गया था ; और इस प्रकार पोर्टिंग गाइड और टूल्स के कई लेखकों को नहीं पता था, जब तक कि इसे नवंबर 2012 में फिर से प्रलेखित नहीं किया गया था :
पहली अभिव्यक्ति भी लंबाई 2 या 3 का टपल हो सकती है। इस मामले में, वैकल्पिक भागों को छोड़ दिया जाना चाहिए। फॉर्म
exec(expr, globals)के बराबर हैexec expr in globals, जबकि फॉर्मexec(expr, globals, locals)के बराबर हैexec expr in globals, locals। की टपल प्रपत्रexecअजगर 3, जहां के साथ संगतता प्रदान करता हैexecएक समारोह के बजाय एक बयान है।
हां, सीपीथॉन 2.7 में कहा गया है कि इसे हाथ से फॉरवर्ड-कम्पैटिबिलिटी विकल्प के रूप में संदर्भित किया जाता है (इस पर लोगों को भ्रमित क्यों करें कि इसमें बैकवर्ड कम्पैटिबिलिटी ऑप्शन है), जब यह वास्तव में दो दशकों से पिछड़ी-अनुकूलता के लिए था ।
इस प्रकार जबकि execपायथन 1 और पायथन 2 में एक बयान है, और पायथन 3 और पायथन 0.9.9 में एक अंतर्निहित फ़ंक्शन है,
>>> exec("print(a)", globals(), {'a': 42})
42
संभवतः हर व्यापक रूप से जारी किए गए पायथन संस्करण में समान व्यवहार किया गया है; और Jython 2.5.2, PyPy 2.3.1 (Python 2.7.6) और IronPython 2.6.1 में भी काम करता है (सीपीयूथॉन के अनछुए व्यवहार का बारीकी से पालन करने के बाद उनके लिए)।
आप अपनी संगतता हैक के साथ पायथन 1.0 - 2.7 में क्या नहीं कर सकते, execएक चर में वापसी मूल्य को संग्रहीत करने के लिए है :
Python 2.7.11+ (default, Apr 17 2016, 14:00:29)
[GCC 5.3.1 20160413] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = exec('print(42)')
File "<stdin>", line 1
a = exec('print(42)')
^
SyntaxError: invalid syntax
(जो कि पायथन 3 में उपयोगी नहीं होगा, execहमेशा की तरह रिटर्न None), या एक संदर्भ पास करें exec:
>>> call_later(exec, 'print(42)', delay=1000)
File "<stdin>", line 1
call_later(exec, 'print(42)', delay=1000)
^
SyntaxError: invalid syntax
एक पैटर्न जो किसी ने वास्तव में उपयोग किया हो सकता है, हालांकि संभावना नहीं है;
या सूची समझ में इसका उपयोग करें:
>>> [exec(i) for i in ['print(42)', 'print(foo)']
File "<stdin>", line 1
[exec(i) for i in ['print(42)', 'print(foo)']
^
SyntaxError: invalid syntax
जो सूची की समझ का दुरुपयोग है ( forइसके बजाय एक लूप का उपयोग करें!)।
42एक अभिव्यक्ति भी है, और आप इसे @डेकोरेटर के रूप में उपयोग नहीं कर सकते ।
decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE; यानी आप डेकोरेटर के रूप में मनमाने ढंग से अभिव्यक्ति का उपयोग नहीं कर सकते हैं, केवल एक (शायद बिंदीदार) पहचानकर्ता, इसके बाद वैकल्पिक कॉल तर्क।
a = b = cएक पूरी तरह से मान्य कथन है, जैसा कि इसका दाहिना हाथ है b = c- जो एक अभिव्यक्ति नहीं है।
execएक अभिव्यक्ति नहीं है: पायथन 2.x में एक बयान, और पायथन 3.x में एक फ़ंक्शन। यह संकलित करता है और तुरंत एक स्ट्रिंग में निहित कथन या कथन का मूल्यांकन करता है। उदाहरण:
exec('print(5)') # prints 5.
# exec 'print 5' if you use Python 2.x, nor the exec neither the print is a function there
exec('print(5)\nprint(6)') # prints 5{newline}6.
exec('if True: print(6)') # prints 6.
exec('5') # does nothing and returns nothing.evalएक अंतर्निहित फ़ंक्शन ( कथन नहीं ) है, जो एक अभिव्यक्ति का मूल्यांकन करता है और उस मूल्य को लौटाता है जो अभिव्यक्ति का उत्पादन करता है। उदाहरण:
x = eval('5') # x <- 5
x = eval('%d + 6' % x) # x <- 11
x = eval('abs(%d)' % -100) # x <- 100
x = eval('x = 5') # INVALID; assignment is not an expression.
x = eval('if 1: x = 4') # INVALID; if is a statement, not an expression.compileके एक निचले स्तर संस्करण है execऔर eval। यह आपके कथनों या भावों का निष्पादन या मूल्यांकन नहीं करता है, बल्कि एक कोड ऑब्जेक्ट देता है जो इसे कर सकता है। मोड निम्नानुसार हैं:
compile(string, '', 'eval')कोड ऑब्जेक्ट जो आपके द्वारा निष्पादित किया गया था, लौटाता है eval(string)। ध्यान दें कि आप इस मोड में कथनों का उपयोग नहीं कर सकते हैं ; केवल (एकल) अभिव्यक्ति मान्य है।compile(string, '', 'exec')कोड ऑब्जेक्ट जो आपके द्वारा निष्पादित किया गया था, लौटाता है exec(string)। आप यहां किसी भी संख्या का उपयोग कर सकते हैं।compile(string, '', 'single')execमोड की तरह है, लेकिन यह पहले बयान को छोड़कर सब कुछ की अनदेखी करेगा। ध्यान दें कि if/ elseउसके परिणामों के साथ एक कथन को एक कथन माना जाता है।exec()अब वास्तव में एक फ़ंक्शन है।
execउस संस्करण में एक बयान है जिसे आप लक्षित कर रहे थे, यह उन परनों को शामिल करने के लिए भ्रामक है, और यदि आप उपयोग करने का प्रयास करते हैं in globals, locals, तो भी छोटी गाड़ी।
exec , पायथन 2 में होने वाले आह्वान की तरह कोष्ठक और कार्य का समर्थन करता है ।
x = (y), यह सच हो सकता है। एक और बयान-बदल-फ़ंक्शन है print; print(1, 2, 3)अजगर 2 और 3 के परिणाम की तुलना करें
निष्पादन कथन के लिए है और कुछ भी वापस नहीं करता है। eval अभिव्यक्ति के लिए है और अभिव्यक्ति का रिटर्न मान है।
अभिव्यक्ति का अर्थ "कुछ" है जबकि कथन का अर्थ "कुछ करना" है।
[i for i in globals().values() if hasattr(i, '__call__')][0]एक बयान या अभिव्यक्ति? यदि यह एक अभिव्यक्ति थी, तो मैं इसे@डेकोरेटर के रूप में क्यों नहीं इस्तेमाल कर सकता ?