Python 在局部变量域中执行代码


Posted in Python onAugust 07, 2020

问题

你想在使用范围内执行某个代码片段,并且希望在执行后所有的结果都不可见。

解决方案

为了理解这个问题,先试试一个简单场景。首先,在全局命名空间内执行一个代码片段:

>>> a = 13
>>> exec('b = a + 1')
>>> print(b)
14
>>>

然后,再在一个函数中执行同样的代码:

>>> def test():
...   a = 13
...   exec('b = a + 1')
...   print(b)
...
>>> test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in test
NameError: global name 'b' is not defined
>>>

可以看出,最后抛出了一个NameError异常,就跟在 exec() 语句从没执行过一样。 要是你想在后面的计算中使用到 exec() 执行结果的话就会有问题了。

为了修正这样的错误,你需要在调用 exec() 之前使用 locals() 函数来得到一个局部变量字典。 之后你就能从局部字典中获取修改过后的变量值了。例如:

>>> def test():
...   a = 13
...   loc = locals()
...   exec('b = a + 1')
...   b = loc['b']
...   print(b)
...
>>> test()
14
>>>

讨论

实际上对于 exec() 的正确使用是比较难的。大多数情况下当你要考虑使用 exec() 的时候, 还有另外更好的解决方案(比如装饰器、闭包、元类等等)。

然而,如果你仍然要使用 exec() ,本节列出了一些如何正确使用它的方法。 默认情况下,exec() 会在调用者局部和全局范围内执行代码。然而,在函数里面, 传递给 exec() 的局部范围是拷贝实际局部变量组成的一个字典。 因此,如果 exec() 如果执行了修改操作,这种修改后的结果对实际局部变量值是没有影响的。 下面是另外一个演示它的例子:

>>> def test1():
...   x = 0
...   exec('x += 1')
...   print(x)
...
>>> test1()
0
>>>

上面代码里,当你调用 locals() 获取局部变量时,你获得的是传递给 exec() 的局部变量的一个拷贝。 通过在代码执行后审查这个字典的值,那就能获取修改后的值了。下面是一个演示例子:

>>> def test2():
...   x = 0
...   loc = locals()
...   print('before:', loc)
...   exec('x += 1')
...   print('after:', loc)
...   print('x =', x)
...
>>> test2()
before: {'x': 0}
after: {'loc': {...}, 'x': 1}
x = 0
>>>

仔细观察最后一步的输出,除非你将 loc 中被修改后的值手动赋值给x,否则x变量值是不会变的。

在使用 locals() 的时候,你需要注意操作顺序。每次它被调用的时候, locals() 会获取局部变量值中的值并覆盖字典中相应的变量。 请注意观察下下面这个试验的输出结果:

>>> def test3():
...   x = 0
...   loc = locals()
...   print(loc)
...   exec('x += 1')
...   print(loc)
...   locals()
...   print(loc)
...
>>> test3()
{'x': 0}
{'loc': {...}, 'x': 1}
{'loc': {...}, 'x': 0}
>>>
>>> def test3():
...   x = 0
...   loc = locals()
...   print(loc)
...   exec('x += 1')
...   print(loc)
...   locals()
...   print(loc)
...
>>> test3()
{'x': 0}
{'loc': {...}, 'x': 1}
{'loc': {...}, 'x': 0}
>>>

注意最后一次调用 locals() 的时候x的值是如何被覆盖掉的。

作为 locals() 的一个替代方案,你可以使用你自己的字典,并将它传递给 exec() 。例如:

>>> def test4():
...   a = 13
...   loc = { 'a' : a }
...   glb = { }
...   exec('b = a + 1', glb, loc)
...   b = loc['b']
...   print(b)
...
>>> test4()
14
>>>

大部分情况下,这种方式是使用 exec() 的最佳实践。 你只需要保证全局和局部字典在后面代码访问时已经被初始化。

还有一点,在使用 exec() 之前,你可能需要问下自己是否有其他更好的替代方案。 大多数情况下当你要考虑使用 exec() 的时候, 还有另外更好的解决方案,比如装饰器、闭包、元类,或其他一些元编程特性。

以上就是Python 在局部变量域中执行代码的详细内容,更多关于Python 局部变量域的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python使用内存zipfile对象在内存中打包文件示例
Apr 30 Python
深入理解Python3中的http.client模块
Mar 29 Python
梯度下降法介绍及利用Python实现的方法示例
Jul 12 Python
python机器学习理论与实战(一)K近邻法
Jan 28 Python
啥是佩奇?使用Python自动绘画小猪佩奇的代码实例
Feb 20 Python
Python函数参数匹配模型通用规则keyword-only参数详解
Jun 10 Python
python 默认参数相关知识详解
Sep 18 Python
基于python求两个列表的并集.交集.差集
Feb 10 Python
Python如何设置指定窗口为前台活动窗口
Aug 12 Python
Python lxml库的简单介绍及基本使用讲解
Dec 22 Python
python3 实现mysql数据库连接池的示例代码
Apr 17 Python
numpy数据类型dtype转换实现
Apr 24 Python
Python如何创建装饰器时保留函数元信息
Aug 07 #Python
python的launcher用法知识点总结
Aug 07 #Python
详解PyQt5中textBrowser显示print语句输出的简单方法
Aug 07 #Python
PyQt5的相对布局管理的实现
Aug 07 #Python
详解pyqt5的UI中嵌入matplotlib图形并实时刷新(挖坑和填坑)
Aug 07 #Python
Python configparser模块封装及构造配置文件
Aug 07 #Python
Python logging模块进行封装实现原理解析
Aug 07 #Python
You might like
浅谈thinkphp的实例化模型
2015/01/04 PHP
php网页版聊天软件实现代码
2016/08/12 PHP
php中static和const关键字用法分析
2016/12/07 PHP
AngularJS实现表单验证
2015/01/28 Javascript
JavaScript实现带箭头标识的多级下拉菜单效果
2015/08/27 Javascript
微信小程序-消息提示框实例
2016/11/24 Javascript
JS实现线性表的链式表示方法示例【经典数据结构】
2017/04/11 Javascript
利用node.js实现反向代理的方法详解
2017/07/24 Javascript
vue中的数据绑定原理的实现
2018/07/02 Javascript
详解webpack模块加载器兼打包工具
2018/09/11 Javascript
微信小程序自定义组件的实现方法及自定义组件与页面间的数据传递问题
2018/10/09 Javascript
微信小程序 自定义弹窗实现过程(附代码)
2019/12/05 Javascript
vue 路由守卫(导航守卫)及其具体使用
2020/02/25 Javascript
keep-alive不能缓存多层级路由菜单问题解决
2020/03/10 Javascript
vue在响应头response中获取自定义headers操作
2020/07/24 Javascript
[07:20]2018DOTA2国际邀请赛寻真——逐梦Mineski
2018/08/10 DOTA
[01:46]新英雄登场
2019/09/10 DOTA
[54:19]完美世界DOTA2联赛PWL S2 Magma vs PXG 第二场 11.28
2020/12/01 DOTA
Python 类的继承实例详解
2017/03/25 Python
Python实现的概率分布运算操作示例
2017/08/14 Python
python3.4实现邮件发送功能
2018/05/28 Python
python实现图片上添加图片
2019/11/26 Python
pytorch实现mnist分类的示例讲解
2020/01/10 Python
解决python 执行sql语句时所传参数含有单引号的问题
2020/06/06 Python
pymysql模块使用简介与示例
2020/11/17 Python
python subprocess pipe 实时输出日志的操作
2020/12/05 Python
HTML5 File API改善网页上传功能
2009/08/19 HTML / CSS
大学生简历中个人的自我评价
2013/10/06 职场文书
挖掘机司机岗位职责
2014/02/12 职场文书
项目合作协议书范本
2014/04/16 职场文书
向女朋友道歉的话
2015/01/20 职场文书
成品仓管员岗位职责
2015/04/01 职场文书
图书馆义工感想
2015/08/07 职场文书
python 安全地删除列表元素的方法
2022/03/16 Python
mysqldump进行数据备份详解
2022/07/15 MySQL
python计算列表元素与乘积详情
2022/08/05 Python