2010-05-25 11 views
32

मैं निष्पादन का उपयोग कर पाइथन कोड का एक टुकड़ा चलाने की कोशिश कर रहा हूं।पाइथन निष्पादन में ग्लोबल्स और स्थानीय()

my_code = """ 
class A(object): 
    pass 

print 'locals: %s' % locals() 
print 'A: %s' % A 

class B(object): 
    a_ref = A 
""" 

global_env = {} 
local_env = {} 
my_code_AST = compile(my_code, "My Code", "exec") 
exec(my_code_AST, global_env, local_env) 

print local_env 

जो निम्नलिखित उत्पादन में परिणाम है

locals: {'A': <class 'A'>} 
A: <class 'A'> 
Traceback (most recent call last): 
    File "python_test.py", line 16, in <module> 
    exec(my_code_AST, global_env, local_env) 
    File "My Code", line 8, in <module> 
    File "My Code", line 9, in B 
NameError: name 'A' is not defined 

हालांकि, अगर मैं इस के लिए कोड बदलने - यह ठीक काम करता है

my_code = """ 
class A(object): 
    pass 

print 'locals: %s' % locals() 
print 'A: %s' % A 

class B(A): 
    pass 
""" 

global_env = {} 
local_env = {} 
my_code_AST = compile(my_code, "My Code", "exec") 
exec(my_code_AST, global_env, local_env) 

print local_env 

तो - देने निम्न उत्पादन -

locals: {'A': <class 'A'>} 
A: <class 'A'> 
{'A': <class 'A'>, 'B': <class 'B'>} 

स्पष्ट रूप से ए प्री ent और सुलभ - कोड के पहले भाग में क्या गलत हो रहा है?

my_code = """ 
class A(object): 
    pass 

print 'locals: %s' % locals() 
print 'A: %s' % A 

class B(object): 
    print locals() 
    a_ref = A 
""" 

global_env = {} 
local_env = {} 
my_code_AST = compile(my_code, "My Code", "exec") 
exec(my_code_AST, global_env, local_env) 

print local_env 

तो यह हो जाता है - मैं 2.6.5, चियर्स,

कॉलिन

* अद्यतन 1 *

अगर मैं() स्थानीय लोगों की जांच वर्ग के अंदर उपयोग कर रहा हूँ स्पष्ट करें कि स्थानीय स्थान() दोनों स्थानों पर समान नहीं है -

locals: {'A': <class 'A'>} 
A: <class 'A'> 
{'__module__': '__builtin__'} 
Traceback (most recent call last): 
    File "python_test.py", line 16, in <module> 
    exec(my_code_AST, global_env, local_env) 
    File "My Code", line 8, in <module> 
    File "My Code", line 10, in B 
NameError: name 'A' is not defined 

हालांकि, अगर मैं ऐसा करते हैं, वहाँ कोई समस्या नहीं है -

def f(): 
    class A(object): 
    pass 

    class B(object): 
    a_ref = A 

f() 

print 'Finished OK' 

* अद्यतन 2 *

ठीक है, इसलिए यहाँ डॉक्स - http://docs.python.org/reference/executionmodel.html

'एक वर्ग परिभाषा एक निष्पादन योग्य है बयान जो नामों का उपयोग और परिभाषित कर सकता है। ये संदर्भ नाम समाधान के लिए सामान्य नियमों का पालन करते हैं। कक्षा परिभाषा का नामस्थान कक्षा का गुण शब्दकोश बन जाता है। कक्षा के दायरे में परिभाषित नाम विधियों में दिखाई नहीं दे रहे हैं। '

ऐसा लगता है कि 'ए' निष्पादन योग्य कथन के भीतर एक मुक्त चर के रूप में उपलब्ध कराया जाना चाहिए जो कि बी की परिभाषा है, और यह तब होता है जब हम ऊपर f() कहते हैं, लेकिन जब हम निष्पादन का उपयोग नहीं करते हैं ()।

my_code = """ 
class A(object): 
    pass 

print 'locals in body: %s' % locals() 
print 'A: %s' % A 

def f(): 
    print 'A in f: %s' % A 

f() 

class B(object): 
    a_ref = A 
""" 

जो आउटपुट

locals in body: {'A': <class 'A'>} 
A: <class 'A'> 
Traceback (most recent call last): 
    File "python_test.py", line 20, in <module> 
    exec(my_code_AST, global_env, local_env) 
    File "My Code", line 11, in <module> 
    File "My Code", line 9, in f 
NameError: global name 'A' is not defined 

तो मुझे लगता है कि नए सवाल यह है कि - - क्यों उन स्थानीय लोगों कार्यों और वर्ग परिभाषा में नि: शुल्क चर के रूप में दिखाया जा रहा है नहीं कर रहे हैं यह निम्नलिखित के साथ और अधिक आसानी से दिखाया जा सकता है - यह एक सुंदर मानक बंद परिदृश्य की तरह लगता है।

+0

अच्छा लगा। कभी नहीं देखा। – zefciu

+0

यह इस प्रश्न में के रूप में ही मुद्दा हो रहा है: http://stackoverflow.com/questions/2749655/why-are-closures-broken-within-exec सूचक के लिए – interjay

+0

धन्यवाद - मैं एक अजगर गुरु नहीं हूँ, लेकिन ऐसा प्रतीत होता है कि जब मैं स्थानीय() को मुद्रित करता हूं, ए * को * स्थानीय चर में संकलित किया गया है - यानी यह जानता है कि इसके साथ क्या करना है। सवाल आप पर प्रकाश डाला में जवाब कहते हैं - 'के लिए संकलन पता चला है कि एक एक freevar है कोई तरीका नहीं है, तो यह एक वैश्विक संदर्भ के लिए यह संकलित' समस्या यहां है कि स्थानीय लोगों() के अंदर नए सिरे से परिभाषित लगता है निष्पादन का उपयोग करते समय बी का शरीर, लेकिन फ़ंक्शन का उपयोग करते समय नहीं (प्रश्न में अद्यतन देखें)? आसानी से है कि इसका जवाब यद्यपि के निहितार्थ की मेरी गलतफहमी हो सकता है ... – hawkett

उत्तर

17

अच्छा, मेरा मानना ​​है कि यह या तो कार्यान्वयन बग या एक अनियंत्रित डिज़ाइन निर्णय है। इस मुद्दे का क्रूक्स यह है कि मॉड्यूल-स्कोप में नाम-बाइंडिंग ऑपरेशन वैश्विक चर से जुड़ना चाहिए। जिस तरह से यह हासिल किया जाता है वह यह है कि जब मॉड्यूल स्तर में, ग्लोबल्स() स्थानीय हैं() (दुभाषिया में एक को आज़माएं), इसलिए जब आप कोई नाम-बाध्यकारी करते हैं, तो यह स्थानीय रूप से इसे सामान्य रूप से असाइन करता है () शब्दकोश, जो ग्लोबल्स भी है, इसलिए एक वैश्विक चर बनाया गया है।

जब आप एक चर को देखते हैं, तो आप पहले अपने वर्तमान स्थानीय लोगों की जांच करते हैं, और यदि नाम नहीं मिलता है, तो आप परिवर्तनीय नाम के लिए स्कॉप्स युक्त स्थानीय लोगों की जांच करते हैं जब तक कि आप चर नहीं पाते या मॉड्यूल-स्कोप तक नहीं पहुंच जाते। यदि आप उस तक पहुंचते हैं, तो आप ग्लोबल्स की जांच करते हैं, जिन्हें मॉड्यूल स्कोप के स्थानीय माना जाता है।

>>> exec(compile("import sys\nprint sys._getframe().f_code.co_name", "blah", "exec"), {}, {}) 
<module> 
>>> exec("a = 1\nclass A(object):\n\tprint a\n", {}, {}) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<string>", line 2, in <module> 
    File "<string>", line 3, in A 
NameError: name 'a' is not defined 
>>> d = {} 
>>> exec("a = 1\nclass A(object):\n\tprint a\n", d,d) 
1 

यह व्यवहार यही वजह है कि विरासत में काम किया (नाम-देखने के लिए इस्तेमाल किया कोड वस्तु की गुंजाइश स्थानीय लोगों(), जो वास्तव में उस में एक था)।

अंत में, यह सीपीथन कार्यान्वयन, विशेष-आवरण ग्लोबल्स लुकअप में एक बदसूरत हैक है। यह कुछ अतर्कसंगत कृत्रिम स्थितियों भी कारण बनता है - उदा .:

>>> def f(): 
...  global a 
...  a = 1 
... 
>>> f() 
>>> 'a' in locals() 
True 

कृपया ध्यान दें कि यह सब मेरे अनुमान दुभाषिया के साथ खिलवाड़ अजगर भाषा संदर्भ की धारा 4.1 पढ़ने (नामकरण और बाध्यकारी), जबकि पर आधारित है। हालांकि यह निश्चित नहीं है (मैंने सीपीथन के स्रोत नहीं खोले हैं), मुझे पूरा यकीन है कि मैं व्यवहार के बारे में सही हूं।

+0

ठीक है - कि जानकारी के लिए धन्यवाद - कि एक परेशानी :) मुख्य कारण मुझे लगता है कि जैसे स्थानीय लोगों का उपयोग करना चाहता है, अन्य सभी सामान है कि वैश्विक में अजगर पुट के बिना सब सामान कोड स्ट्रिंग में परिभाषित किया गया, मिल गया था। तो मुझे लगता है कि कोड, सामान की अपनी एक बड़ा शब्दकोश है, जो समझ में आता है अंदर 'वैश्विक() प्रिंट', लेकिन अब मैं कैसे सिर्फ सामान है कि एक शब्दकोश में कोड स्ट्रिंग में परिभाषित किया गया था प्राप्त करने के लिए के रूप में एक नुकसान में हूँ - यानी एक शब्दकोष जिसमें '{ए', , 'बी', } है। मैं मैन्युअल रूप से सबकुछ बाहर नहीं करना चाहता हूं, और मुझे पहले से पता नहीं है कि कोड स्ट्रिंग में क्या है। – hawkett

+1

मैं इस प्रश्न का उत्तर देने जा रहा हूं - मैंने यहां एक पाइथन बग दायर किया - http://bugs.python.org/issue8819 - चीयर्स। – hawkett

+1

मैंने जो बग दायर किया वह एक डुप्लिकेट था। मैं एक तर्क यह यहां 2.6+ में लगाई जानी के लिए बनाया गया है - http://bugs.python.org/issue991196 – hawkett

2

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

exec code in dict() 
6

print locals() और globals() के बाद, आप कारण है कि कार्यकारी थ्रो "परिभाषित नहीं" अपवाद मिलेगा, और आप इस

d = dict(locals(), **globals()) 
exec (code, d, d) 
+0

यह केवल प्रतिक्रिया जहां जहाज और वैश्विक/स्थानीय लोगों वापस प्राप्त कर सकते हैं। शानदार जवाब। फिर आप बच्चे कोड से चर का उपयोग करने के आधार के रूप में डी का उपयोग कर सकते हैं। डी ['स्थिति'] यदि आपके पास आपके कोड में स्थिति = {} थी। धन्यवाद @ ज़ो – Dovy

1
my_code = """ 
class A(object): 
    pass 

class B(object): 
    a = A 
""" 

my_code_AST = compile(my_code, "My Code", "exec") 
extra_global = "hi" 
global_env = {} 
exec my_code_AST in global_env 
print "global_env.keys() =", global_env.keys() 
print "B.a =", global_env["B"].a 

प्रिंट कोशिश कर सकते हैं

global_env.keys() = ['__builtins__', 'A', 'B'] 
B.a = <class 'A'> 

Hawkett , आप कहते हैं,

मुख्य कारण मैं स्थानीय लोगों का उपयोग करना चाहता था, कोड स्ट्रिंग में परिभाषित सभी चीजें प्राप्त करना था, बिना अन्य सभी चीजें जो पाइथन ग्लोबल्स में रखती हैं।

कार्यकारी के साथ

, यदि आपका वैश्विक __builtins__ परिभाषित नहीं है, कार्यकारी, एक आइटम, __builtins__ अपने वैश्विक करने के लिए कहते हैं तो आप ए, बी, और __builtins__ मिलता है। __builtins__ स्वयं एक बड़ा शब्दकोश है, लेकिन यह हमेशा एक ही तत्व है जिसे हटाने के लिए (जब तक आप इसे हटाने से पहले अपने कोड को समाप्त होने तक प्रतीक्षा करते हैं!)। Exec() here के तहत प्रलेखित। built in functions तहत eval के लिए

डॉक्स कहना

तो वैश्विक शब्दकोश मौजूद है और का अभाव 'builtins', इससे पहले कि अभिव्यक्ति पार्स किया गया है वर्तमान वैश्विक वैश्विक में नकल कर रहे हैं।

लेकिन असल में यह केवल में __builtins__ कॉपी करने के लिए

(और N.B. क्या हर किसी ने कहा कि लगता है: एक अलग local_env बिना या तो सेट वैश्विक और स्थानीय लोगों को एक ही या कहना exec my_code_AST in global_env।।)

संबंधित मुद्दे