exec如何与当地人合作?

时间:2009-09-23 00:18:47

标签: python python-3.x exec locals

我认为这会打印3,但它打印1:

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

3 个答案:

答案 0 :(得分:36)

Python3 bug list对此问题进行了详细讨论。最终,要获得此行为,您需要执行以下操作:

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

如果您选中the Python3 documentation on exec,则会看到以下注释:

  

默认的locals的行为如下面的函数locals()所述:不应尝试修改默认的locals字典。如果您需要在函数exec()返回后查看代码对locals的影响,则传递显式的locals字典。

回到a specific message on the bug report,Georg Brandl说:

  

要动态修改函数的局部变量不是   可能没有几个后果:通常,函数本地人不是   存储在字典中,但是数组,其索引的确定位置为   从已知语言环境编译时间。这至少与新的碰撞   本地人由exec添加。旧的执行声明绕过了这个,因为   编译器知道如果没有globals / locals的exec发生了   在一个函数中,该命名空间将是“未优化的”,即不使用   本地数组。由于exec()现在是一个普通函数,编译器会执行   不知道“exec”可能会受到什么约束,因而无法对待   特别

重点是我的。

所以它的要点是Python3可以通过而不是更好地优化局部变量的使用,默认情况下允许这种行为。

为了完整起见,正如上面的评论所述, 在Python 2.X中按预期工作:

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

答案 1 :(得分:2)

如果你在某个方法中,你可以这样做:

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

x = Thing()
print(x.foo)

You can read more about it here

答案 2 :(得分:1)

您无法以这种方式使用exec更改函数中的局部变量,以及exec行为方式的原因,可归纳如下:

  1. exec是一个函数,它将本地范围与其调用的最内部范围的范围共享。
  2. 无论何时在函数范围内定义新对象,都可以在其本地名称空间中访问它,即它将修改local()字典。在exec中定义新对象时,它的作用大致相当于以下内容:
  3. 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. Python开始在本地命名空间中查找名称。它被称为LEGB方式。 Python从Local namespce开始,然后查看Enclosing范围,然后查看Global,最后在Buit-in命名空间中查找名称。
    2. 更全面的例子如下:

      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}
      

      当地人是一样的。

      {'l_var': 10, 'g_var': 222}
      

      添加g_var并更改l_var后,只会添加g_var并保持l_var不变。

      {'l_var': 111, 'g_var': 222}
      

      l_var已更改,因为我们正在更改并在一个实例中打印本地(一次调用exec)。

      {'l_var': 10, 'g_var': 222}
      {'l_var': 10, 'g_var': 222}
      

      在函数的本地和exec中,本地l_var未更改,并且添加了g_var

      Inner function: 
      {}
      {'inner_var': 100}
      {'inner_var': 100}
      

      inner_function的本地与exec的本地相同。

      ['g_var', 'test']
      

      global仅包含g_var和函数名称(排除特殊方法后)。

      ---------------------
      
      (5, 10)
      5