मैं पायथन कोड के गतिशील मूल्यांकन को देख रहा हूं , और यह फ़ंक्शन eval()
और compile()
फ़ंक्शन और exec
कथन पर आ रहा है।
क्या कोई कृपया eval
और के बीच अंतर की व्याख्या कर सकता है exec
, और कैसे compile()
फिट के विभिन्न तरीके ?
मैं पायथन कोड के गतिशील मूल्यांकन को देख रहा हूं , और यह फ़ंक्शन eval()
और compile()
फ़ंक्शन और exec
कथन पर आ रहा है।
क्या कोई कृपया eval
और के बीच अंतर की व्याख्या कर सकता है exec
, और कैसे compile()
फिट के विभिन्न तरीके ?
जवाबों:
मूल रूप से, eval
करने के लिए प्रयोग किया जाता है eval uate एक भी गतिशील रूप से उत्पन्न अजगर अभिव्यक्ति, और exec
करने के लिए प्रयोग किया जाता है कार्यकारी उटे गतिशील केवल अपने साइड इफेक्ट के लिए अजगर कोड उत्पन्न।
eval
और exec
ये दो अंतर हैं:
eval
केवल एक ही अभिव्यक्ति को स्वीकार करता है , exec
एक कोड ब्लॉक ले सकता है जिसमें पायथन कथन हैं: लूप्स try: except:
, class
और फ़ंक्शन / विधि def
initions और इतने पर।
पाइथन में एक अभिव्यक्ति वह है जो आप एक चर असाइनमेंट में मान के रूप में ले सकते हैं:
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
तथा eval
exec
समारोह (जो था अजगर 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
और eval
2 अतिरिक्त स्थितिगत तर्क स्वीकार करते हैं - 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)
को हमेशा स्वीकार किया गया है (नीचे देखें)।
compile
compile(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
को संकलित करने का समर्थन करता है ; और अमूर्त सिंटैक्स पेड़ों में स्रोत कोड ( पायथन में लिखा गया है और बस कॉल ); उदाहरण के लिए मक्खी पर स्रोत कोड को संशोधित करने के लिए और गतिशील कोड निर्माण के लिए भी उपयोग किया जाता है, क्योंकि अक्सर जटिल मामलों में पाठ की पंक्तियों के बजाय नोड्स के पेड़ के रूप में कोड को संभालना आसान होता है।code
ast.parse
compile(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
और exec
CPython 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]
एक बयान या अभिव्यक्ति? यदि यह एक अभिव्यक्ति थी, तो मैं इसे@
डेकोरेटर के रूप में क्यों नहीं इस्तेमाल कर सकता ?