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从ftp下载数据保存实例
Nov 20 Python
Python XML RPC服务器端和客户端实例
Nov 22 Python
python编程开发之textwrap文本样式处理技巧
Nov 13 Python
Python使用QRCode模块生成二维码实例详解
Jun 14 Python
python读取excel表格生成erlang数据
Aug 26 Python
Django项目开发中cookies和session的常用操作分析
Jul 03 Python
Tensorflow中的placeholder和feed_dict的使用
Jul 09 Python
浅谈python requests 的put, post 请求参数的问题
Jan 02 Python
Python简单处理坐标排序问题示例
Jul 11 Python
python读取hdfs上的parquet文件方式
Jun 06 Python
keras和tensorflow使用fit_generator 批次训练操作
Jul 03 Python
Python基础详解之描述符
Apr 28 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面向对象全攻略 (十七) 自动加载类
2009/09/30 PHP
php+mysql实现的二级联动菜单效果详解
2016/05/10 PHP
tp5.1框架数据库子查询操作实例分析
2020/05/26 PHP
JavaScript中的new的使用方法与注意事项
2007/05/16 Javascript
Javascript 获取滚动条位置等信息的函数
2009/09/08 Javascript
jquery 图片轮换效果
2010/07/29 Javascript
js自动生成的元素与页面原有元素发生堆叠的解决方法
2014/09/04 Javascript
JS弹出可拖拽可关闭的div层完整实例
2015/02/13 Javascript
JS实现兼容各浏览器解析XML文档数据的方法
2015/06/01 Javascript
JS检测数组类型的方法小结
2017/03/14 Javascript
vue cli使用绝对路径引用图片问题的解决
2017/12/06 Javascript
Vue实现内部组件轮播切换效果的示例代码
2018/04/07 Javascript
angularJs中json数据转换与本地存储的实例
2018/10/08 Javascript
微信小程序实现Swiper轮播图效果
2019/11/22 Javascript
vue实现前端分页完整代码
2020/06/17 Javascript
[46:47]完美世界DOTA2联赛PWL S2 FTD vs Magma 第二场 11.20
2020/11/23 DOTA
Python中用Ctrl+C终止多线程程序的问题解决
2013/03/30 Python
python3编写C/S网络程序实例教程
2014/08/25 Python
python实现的简单猜数字游戏
2015/04/04 Python
python 环境变量和import模块导入方法(详解)
2017/07/11 Python
使用tensorflow实现AlexNet
2017/11/20 Python
python数字图像处理实现直方图与均衡化
2018/05/04 Python
在python中安装basemap的教程
2018/09/20 Python
Pandas数据离散化原理及实例解析
2019/11/16 Python
Python处理mysql特殊字符的问题
2020/03/02 Python
使用Pyhton 分析酒店针孔摄像头
2020/03/04 Python
Python+unittest+requests 接口自动化测试框架搭建教程
2020/10/09 Python
用css3制作纸张效果(外翻卷角)
2013/02/01 HTML / CSS
爱尔兰领先的在线体育用品零售商:theGAAstore
2018/04/16 全球购物
美国在线鞋类零售商:LifeStride
2019/06/09 全球购物
如何整合JQuery和Prototype
2014/01/31 面试题
如何写出好的Java代码
2014/04/25 面试题
解释下面关于J2EE的名词
2013/11/15 面试题
年度考核自我鉴定
2014/02/02 职场文书
详细谈谈JavaScript中循环之间的差异
2021/08/23 Javascript
Vue+Flask实现图片传输功能
2022/04/01 Vue.js