2015-03-30 8 views
25

में इवल स्कोप पाइथन 3 में विचित्र eval व्यवहार में आया - स्थानीय चर को तब तक नहीं लिया जाता जब सूची समझ में eval कहा जाता है। अजगर 3 मेंपाइथन 2 बनाम 3

def apply_op(): 
    x, y, z = [0.5, 0.25, 0.75] 
    op = "x,y,z" 
    return [eval(o) for o in op.split(",")] 
print(apply_op()) 

यह त्रुटियों:

▶ python --version 
Python 3.4.3 
▶ python eval.py 
Traceback (most recent call last): 
    File "eval.py", line 7, in <module> 
    print(apply_op()) 
    File "eval.py", line 5, in apply_op 
    return [eval(o) % 1 for o in op.split(",")] 
    File "eval.py", line 5, in <listcomp> 
    return [eval(o) % 1 for o in op.split(",")] 
    File "<string>", line 1, in <module> 
NameError: name 'x' is not defined 

और यह अजगर 2 में ठीक काम करता है:

▶ python --version 
Python 2.7.8 
▶ python eval.py 
[0.5, 0.25, 0.75] 

सूची समझ के बाहर स्थानांतरित करना समस्या को हटा।

def apply_op(): 
    x, y, z = [0.5, 0.25, 0.75] 
    return [eval("x"), eval("y"), eval("z")] 

क्या यह इरादा व्यवहार है, या यह एक बग है?

+0

[यहां] (http://stackoverflow.com/questions/4198906/python-list-comprehension-rebind-names-even- बाद के दायरे की समझ-थी-थी) पी 2 और पी 3 में स्कॉप्स और सूची की समझ के बारे में कुछ और जानकारी है। – Marcin

+3

मजेदार हिस्सा है, इसे फ़ंक्शन स्कोप से बाहर ले जाना भी समस्या को रोक देता है। संबंधित: http://bugs.python.org/msg81898 – wim

+0

@ मार्सिन यह सूची समझ के बाहर लूप वैरिएबल लीकिंग के दायरे से संबंधित नहीं है। यह लूप वैरिएबल * के भीतर * समझ के भीतर ही है। – wim

उत्तर

25

इस के लिए बग ट्रैकर में समस्या बंद है: Issue 5242

इस बग के लिए संकल्प को ठीक नहीं करेगा।

अंक से कुछ टिप्पणियां पढ़ें:

यह आशा की जाती है, और आसानी से ठीक नहीं होगा। कारण यह है कि सूची 3.x में समझें फ़ंक्शन नामस्थान "हुड के तहत" का उपयोग करती हैं (2.x, में उन्हें लूप के लिए सरल के रूप में लागू किया गया था)। क्योंकि आंतरिक कार्यों को यह जानने की आवश्यकता है कि नामांकन नाम से कौन से नाम प्राप्त किए जाएंगे, नाम eval() में संदर्भित नाम संलग्न कार्यों से नहीं आ सकते हैं। उन्हें या तो स्थानीय या ग्लोबल्स होना चाहिए।

eval() शायद पहले से ही एक हैक है, इसे काम करने के लिए एक और हैक जोड़ने की आवश्यकता नहीं है। केवल eval() से छुटकारा पाने के लिए बेहतर है और आप जो करना चाहते हैं उसे करने के लिए बेहतर तरीका ढूंढें।

+2

हां, मैं एक स्पष्ट आंतरिक फ़ंक्शन का उपयोग करके पाइथन 2 में एक ही व्यवहार को पुन: उत्पन्न कर सकता हूं। दिलचस्प बात यह है कि, पर्ल और जावास्क्रिप्ट दोनों, जो आंतरिक कार्यों का भी समर्थन करते हैं, * * इस व्यवहार को प्रदर्शित नहीं करते हैं: 'function foo() {var x = 42; फ़ंक्शन बार() {वापसी eval ("x")}; वापसी बार}; foo()() 'उम्मीद के अनुसार 42 उत्पन्न करता है, इसलिए आवश्यकता है कि" आंतरिक कार्यों को यह जानने की आवश्यकता है कि नामांकन किस नाम से प्राप्त किया जाना चाहिए "वास्तव में पाइथन का एक कर्कश है, आंतरिक कार्यों की सामान्य सीमा नहीं। –

+1

यह वास्तव में दुर्भाग्यपूर्ण है कि कोई कहता है "यह अपेक्षित है"। मुझे इसकी उम्मीद नहीं है। एक फिक्स cpython के लिए एक अज्ञात फ़ंक्शन बनाने के लिए है जो सभी कॉलर के स्थानीय चर को देखता है, लेकिन यदि नहीं, तो दस्तावेज़ को अद्यतन किया जाना चाहिए। –

+0

@NeilG: उस समय तक 'eval' कहा जाता है, बंद चर परिवर्तनीय उपलब्धता के बारे में निर्णय लेने में बहुत देर हो चुकी है। इसका समर्थन करने के लिए 'eval' की संकलन-समय की पहचान की आवश्यकता होगी, जैसे हैक 0-Args' super' के लिए उपयोग की जाने वाली हैक, जैसा कि आप 'supper = super' करते हैं, उसी तरह के परिणाम के साथ, आप 0-args' supper 'का उपयोग नहीं कर सकते । कि, या एक स्पष्ट या निहित घोंसले वाले फ़ंक्शन वाले प्रत्येक फ़ंक्शन को अपने सभी चर के लिए क्लोजर वेरिएबल मैकेनिज्म का उपयोग करना होगा और उन सभी को सभी नेस्टेड फ़ंक्शंस में उपलब्ध कराया जाएगा, जो सभी पायथन वैरिएबल रिज़ॉल्यूशन का एक बड़ा हिस्सा धीमा कर देगा। – user2357112

4

यदि आप चाहते हैं:

def apply_op(): 
    x, y, z = [0.5, 0.25, 0.75] 
    op = "x,y,z" 
    return [eval(o) for o in op.split(",")] 
print(apply_op()) 

काम करने के लिए आप स्थानीय लोगों और वैश्विक कब्जा करने के लिए के रूप में मुद्दा यह है कि eval(o) ही eval(o, globals(), locals()) गया है है की आवश्यकता होगी लेकिन eval जनरेटर समारोह भीतर प्रकट होता है के रूप में उन कार्यों के परिणाम ही नहीं हैं के रूप में वे थे जब eval एक रैपिंग समारोह इसलिए उन्हें जनरेटर बाहर कब्जा नहीं था और उन्हें अंदर का उपयोग करें:

def apply_op(): 
    x, y, z = [0.5, 0.25, 0.75] 
    op = "x,y,z" 
    _locals = locals() 
    _globals = globals() 
    return [eval(o, _globals, _locals) for o in op.split(",")] 
print(apply_op()) 
,210

या x,y,z बेहतर रूप में स्थानीय लोगों को कर रहे हैं और तार केवल चर नाम हैं:

def apply_op(): 
    x, y, z = [0.5, 0.25, 0.75] 
    op = "x,y,z" 
    _locals = locals() 
    return [_locals[o] for o in op.split(",")] 
print(apply_op()) 
संबंधित मुद्दे