2009-09-23 12 views
18

मैंने सोचा था कि यह 3 प्रिंट होगा, लेकिन यह 1 प्रिंट:कैसे स्थानीय लोगों के साथ कार्यकारी काम करता है?

def f(): 
    a = 1 
    exec("a = 3") 
    print(a) 
+0

कौन सा अजगर संस्करण? क्या यह 2.6 है? –

+0

पाइथन 2.5.4 – geoffspear

+0

के साथ मेरी मशीन पर प्रिंट 3, यहां 2.4.5। –

उत्तर

27

यह समस्या कुछ हद तक Python3 bug list में चर्चा की है। अंत में, इस व्यवहार प्राप्त करने के लिए, आप सब करने की ज़रूरत:

def foo(): 
    ldict = locals() 
    exec("a=3",globals(),ldict) 
    a = ldict['a'] 
    print(a) 

और अगर आप the Python3 documentation on exec जाँच, तो आपको निम्न नोट दिखाई देगा:

The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.

वापस a specific message on the bug report की चर्चा करते हुए जॉर्ज ब्रैंडिल का कहना है:

To modify the locals of a function on the fly is not possible without several consequences: normally, function locals are not stored in a dictionary, but an array, whose indices are determined at compile time from the known locales. This collides at least with new locals added by exec. The old exec statement circumvented this, because the compiler knew that if an exec without globals/locals args occurred in a function, that namespace would be "unoptimized", i.e. not using the locals array. Since exec() is now a normal function, the compiler does not know what "exec" may be bound to, and therefore can not treat is specially.

जोर मेरा है।

तो यह का सार है कि python3 बेहतर डिफ़ॉल्ट रूप से इस व्यवहार की अनुमति देकर नहीं स्थानीय चर के उपयोग का अनुकूलन कर सकते हैं।

Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) 
[GCC 4.3.3] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> def f(): 
...  a = 1 
...  exec "a=3" 
...  print a 
... 
>>> f() 
3 
+0

मुझे लगता है, यह स्थानीय लोगों() के साथ एक मुद्दा है जिसे पायथन 2.X में निष्पादन से बाहर किया गया था। यह मुद्दा स्पष्ट रूप से दस्तावेज नहीं है जैसा कि मुझे पसंद आया होगा। निष्पादन/स्थानीय 2.X से 3.X में बदलना चाहिए कहीं भी http://docs.python.org/3.1/library/functions.html#exec और मुझे लगता है कि निष्पादन में ए सुविधा सुविधा होना चाहिए जो इस अनुकूलन को रोकता है। .. – ubershmekel

+0

@MarkRushakoff मुझे निष्पादन की रेखा पर आपके कार्यान्वयन के साथ एक त्रुटि मिलती है: TypeError: 'dict' ऑब्जेक्ट कॉल करने योग्य नहीं है – Leo

+0

@Leo इसे 'ldict' नहीं होना चाहिए, न कि 'dict'? वैसे भी, मैं पाइथन में और अधिक काम नहीं करता हूं, इसलिए यदि ऐसा नहीं है, तो उम्मीद है कि कोई और इसमें घुस जाएगा। –

2

आप एक विधि के अंदर हैं, तो आप ऐसा कर सकते हैं:

और पूर्णता के लिए, ऊपर टिप्पणी में उल्लेख किया के लिए, इस काम पायथन 2.x में अपेक्षा के अनुरूप कार्य करता है:

class Thing(): 
    def __init__(self): 
     exec('self.foo = 2') 

x = Thing() 
print(x.foo) 

You can read more about it here

0

कारण यह है कि आप एक समारोहका उपयोग कर के भीतर स्थानीय चर को बदल नहीं सकते कि रास्ते मेंऔर क्यों exec अधिनियम जिस तरह से यह करता है निम्नलिखित के रूप में संक्षेप किया जा सकता है:

  1. exec एक समारोह है कि सबसे भीतरी गुंजाइश है जिसमें यह कहा जाता है के दायरे के साथ अपने स्थानीय स्केप के शेयरों है।
  2. जब भी आप एक समारोह के दायरे के भीतर एक नई वस्तु वह अपने स्थानीय नाम स्थान में सुलभ हो जाएगा, अर्थात परिभाषित यह local() शब्दकोश को संशोधित करेगा। जब आप exec में एक नई वस्तु को परिभाषित उसके द्वारा मोटे तौर पर निम्नलिखित के बराबर है:

from copy import copy 
class exec_type: 
    def __init__(self, *args, **kwargs): 
     # default initializations 
     # ... 
     self.temp = copy(locals()) 

    def __setitem__(self, key, value): 
     if var not in locals(): 
      set_local(key, value) 
     self.temp[key] = value 

temp एक अस्थायी नाम स्थान कि प्रत्येक इन्स्टेन्शियशन के बाद रीसेट करता है। (हर बार जब आप फोन exec)


  1. अजगर स्थानीय नाम स्थान से नाम के लिए देख शुरू होता है। यह LEGB तरीके के रूप में जाना जाता है। अजगर फिर स्थानीय namespce से शुरू होता है संलग्न स्कोप, तो वैश्विक में लग रहा है और अंत में यह नाम स्थान में Buit-भीतर नामों को लग रहा है।

एक अधिक व्यापक उदाहरण होगा हम निम्नलिखित की तरह कुछ:

g_var = 5 

def test(): 
    l_var = 10 
    print(locals()) 
    exec("print(locals())") 
    exec("g_var = 222") 
    exec("l_var = 111") 
    exec("print(locals())") 

    exec("l_var = 111; print(locals())") 

    exec("print(locals())") 
    print(locals()) 
    def inner(): 
     exec("print(locals())") 
     exec("inner_var = 100") 
     exec("print(locals())") 
     exec("print([i for i in globals() if '__' not in i])") 

    print("Inner function: ") 
    inner() 
    print("-------" * 3) 
    return (g_var, l_var) 

print(test()) 
exec("print(g_var)") 

आउटपुट:

{'l_var': 10} 
{'l_var': 10} 
# locals are the same 
{'l_var': 10, 'g_var': 222} 
# after adding g_var and changing the l_var it only adds g_var and left the l_var unchanged 
{'l_var': 111, 'g_var': 222} 
# l_var is changed because we are changing and printing the locals in one instantiation (one call to exec) 
{'l_var': 10, 'g_var': 222} 
{'l_var': 10, 'g_var': 222} 
# In both function's locals and exec's local l_var is unchanged and g_var is added 
Inner function: 
{} 
{'inner_var': 100} 
{'inner_var': 100} 
# inner_function's local is same as exec's local 
['g_var', 'test'] 
# global is only contain g_var and function name (after excluding the special methods) 
--------------------- 

(5, 10) 
5 
संबंधित मुद्दे