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基于multiprocessing的多进程创建方法
Jun 04 Python
深入解析Python中的上下文管理器
Jun 28 Python
Python实现PS滤镜Fish lens图像扭曲效果示例
Jan 29 Python
python: 自动安装缺失库文件的方法
Oct 22 Python
Python常用特殊方法实例总结
Mar 22 Python
python opencv对图像进行旋转且不裁剪图片的实现方法
Jul 09 Python
django项目简单调取百度翻译接口的方法
Aug 06 Python
Pymysql实现往表中插入数据过程解析
Jun 02 Python
Django实现任意文件上传(最简单的方法)
Jun 03 Python
简单的命令查看安装的python版本号
Aug 28 Python
Pycharm自动添加文件头注释和函数注释参数的方法
Oct 23 Python
关于python中readlines函数的参数hint的相关知识总结
Jun 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
php将数据库中的电话号码读取出来并生成图片
2008/08/31 PHP
PHP获取日期对应星期、一周日期、星期开始与结束日期的方法
2018/06/22 PHP
Javascript 调试利器 Firebug使用详解六
2009/07/05 Javascript
基于OO的动画附加插件,可以实现弹跳、渐隐等动画效果 分享
2013/06/24 Javascript
文本框水印提示效果的简单实现代码
2014/02/22 Javascript
javascript实现瀑布流加载图片原理
2016/02/02 Javascript
快速获取/设置iframe内对象元素的几种js实现方法
2016/05/20 Javascript
require.js 加载 vue组件 r.js 合并压缩的实例
2016/10/14 Javascript
使用express搭建一个简单的查询服务器的方法
2018/02/09 Javascript
js实现删除li标签一行内容
2019/04/16 Javascript
Vue.js递归组件实现组织架构树和选人功能案例分析
2019/07/03 Javascript
vue实现购物车选择功能
2020/01/10 Javascript
JS实现网页烟花动画效果
2020/03/10 Javascript
python 正则式 概述及常用字符
2009/05/07 Python
python 中文字符串的处理实现代码
2009/10/25 Python
Python datetime时间格式化去掉前导0
2014/07/31 Python
python使用socket进行简单网络连接的方法
2015/04/29 Python
利用python爬取斗鱼app中照片方法实例
2017/12/03 Python
python对日志进行处理的实例代码
2018/10/06 Python
Linux下Python安装完成后使用pip命令的详细教程
2018/11/22 Python
详解python之heapq模块及排序操作
2019/04/04 Python
深入浅析Python科学计算库Scipy及安装步骤
2019/10/12 Python
Python浮点数四舍五入问题的分析与解决方法
2019/11/19 Python
python Jupyter运行时间实例过程解析
2019/12/13 Python
python自动生成证件号的方法示例
2021/01/14 Python
项目考察欢迎辞
2014/01/17 职场文书
菜篮子工程实施方案
2014/03/08 职场文书
最经典的商业地产项目广告词
2014/03/13 职场文书
职务聘任书范文
2014/03/29 职场文书
计算机系统管理员求职信
2014/06/20 职场文书
2014企业年终工作总结
2014/12/23 职场文书
个人汇报材料范文
2014/12/30 职场文书
环保证明
2015/06/23 职场文书
2016年“世界气象日”广播稿
2015/12/17 职场文书
七年级上册生物的课件
2019/08/07 职场文书
nginx里的rewrite跳转的实现
2021/03/31 Servers