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查看多台服务器进程的脚本分享
Jun 11 Python
python多进程操作实例
Nov 21 Python
在Gnumeric下使用Python脚本操作表格的教程
Apr 14 Python
Python中的自省(反射)详解
Jun 02 Python
使用k8s部署Django项目的方法步骤
Jan 14 Python
Python爬虫之UserAgent的使用实例
Feb 21 Python
python导入不同目录下的自定义模块过程解析
Nov 18 Python
对python中assert、isinstance的用法详解
Nov 27 Python
pytorch中的上采样以及各种反操作,求逆操作详解
Jan 03 Python
python GUI库图形界面开发之PyQt5开发环境配置与基础使用
Feb 25 Python
Python如何使用队列方式实现多线程爬虫
May 12 Python
python模块内置属性概念及实例
Feb 18 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
PHP新手上路(三)
2006/10/09 PHP
PHP中数组定义的几种方法
2013/09/01 PHP
php实现aes加密类分享
2014/02/16 PHP
浅谈PHP的数据库接口和技术
2016/12/09 PHP
PHP实现数组转JSon和JSon转数组的方法示例
2018/06/14 PHP
thinkPHP5框架实现多数据库连接,跨数据连接查询操作示例
2019/05/29 PHP
JS 精确统计网站访问量的实例代码
2013/07/05 Javascript
jQuery+jRange实现滑动选取数值范围特效
2015/03/14 Javascript
JS实现仿新浪微博发布内容为空时提示功能代码
2015/08/19 Javascript
jquery实现下拉框功能效果【实例代码】
2016/05/06 Javascript
基于css3新属性transform及原生js实现鼠标拖动3d立方体旋转
2016/06/12 Javascript
简单实现js进度条加载效果
2020/03/25 Javascript
表格展示利器 Bootstrap Table实例代码
2017/09/06 Javascript
Node.js中Bootstrap-table的两种分页的实现方法
2017/09/18 Javascript
webpack的CSS加载器的使用
2018/09/11 Javascript
利用Node.js如何实现文件循环覆写
2019/04/05 Javascript
JavaScript HTML DOM元素 节点操作汇总
2019/07/29 Javascript
vue ssr服务端渲染(小白解惑)
2019/11/10 Javascript
JS实现的雪花飘落特效示例
2019/12/03 Javascript
[09:33]2015国际邀请赛第四日TOP10
2015/08/08 DOTA
Python subprocess模块学习总结
2014/03/13 Python
在DigitalOcean的服务器上部署flaskblog应用
2015/12/19 Python
python下读取公私钥做加解密实例详解
2017/03/29 Python
利用python画出折线图
2018/07/26 Python
Python实现的线性回归算法示例【附csv文件下载】
2018/12/29 Python
Python3.5 Json与pickle实现数据序列化与反序列化操作示例
2019/04/29 Python
python tkinter实现界面切换的示例代码
2019/06/14 Python
python实现知乎高颜值图片爬取
2019/08/12 Python
python实现的多任务版udp聊天器功能案例
2019/11/13 Python
Pytorch 多维数组运算过程的索引处理方式
2019/12/27 Python
使用HTML5 Canvas绘制直线或折线等线条的方法讲解
2016/03/14 HTML / CSS
意大利婴儿产品网上商店:Mukako
2018/10/14 全球购物
公司党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
党员教师四风自我剖析材料
2014/09/30 职场文书
志愿者服务活动总结报告
2015/05/06 职场文书
解析高可用Redis服务架构分析与搭建方案
2021/06/20 Redis