使用“exec”调用时,如何更新局部变量?

2024-12-04 08:56:00
admin
原创
152
摘要:问题描述:我以为这会打印 3,但它打印了 1:def f(): a = 1 exec("a = 3") print(a) f() 我正在使用 Python 3。在 Python 2 中,它可以按预期工作(打印 3)。解决方案 1:Python3 错误列表中对此问题...

问题描述:

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

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

f()

我正在使用 Python 3。在 Python 2 中,它可以按预期工作(打印 3)。


解决方案 1:

Python3 错误列表中对此问题进行了一些讨论。最终,要获得此行为,您需要执行以下操作:

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

如果你查看Python3 文档exec,你会看到以下说明:

默认局部变量的作用如下所述locals()*不应尝试修改默认局部变量字典。如果您需要在函数返回后查看代码对局部变量的影响,请传递显式局部变量字典。*exec()

这意味着单参数exec不能安全地执行任何绑定局部变量的操作,包括变量赋值、导入、函数定义、类定义等。如果它使用声明global,它可以分配给全局变量,但不能分配给局部变量。

回顾错误报告中的具体消息,Georg Brandl 说:

在没有几个后果的情况下,动态修改函数的局部变量是不可能的:通常,函数局部变量不存储在字典中,而是存储在数组中,其索引是在编译时根据已知的本地设置确定的这至少与 exec 添加的新局部变量相冲突。

然后,关于 Python 2:

旧的 exec 语句可以避免这种情况,因为编译器知道,如果函数中出现没有全局/本地参数的 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

解决方案 2:

无法exec以此方式更改函数内的局部变量的原因以及为什么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. Python 开始从本地命名空间查找名称。这被称为 LEGB 方式。Python 从本地命名空间开始,然后查找封闭范围,然后是全局范围,最后在内置命名空间中查找名称。

一个更全面的例子如下:

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

解决方案 3:

如果你在方法内部,你可以这样做:

# python 2 or 3
class Thing():
    def __init__(self):
        exec('self.foo = 2')
    
x = Thing()
print(x.foo)

您可以在此处阅读更多相关信息

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用