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 相关文章推荐
python3新特性函数注释Function Annotations用法分析
Jul 28 Python
Python实现破解猜数游戏算法示例
Sep 25 Python
python代码 输入数字使其反向输出的方法
Dec 22 Python
pandas DataFrame的修改方法(值、列、索引)
Aug 02 Python
Python模块的定义,模块的导入,__name__用法实例分析
Jan 07 Python
Python中join()函数多种操作代码实例
Jan 13 Python
Python 识别12306图片验证码物品的实现示例
Jan 20 Python
Python脚本实现监听服务器的思路代码详解
May 28 Python
详解基于python的图像Gabor变换及特征提取
Oct 26 Python
python海龟绘图之画国旗实例代码
Nov 11 Python
Python文件名匹配与文件复制的实现
Dec 11 Python
10个顶级Python实用库推荐
Mar 04 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
什么是MVC,好东西啊
2007/05/03 PHP
美图秀秀web开放平台--PHP流式上传和表单上传示例分享
2014/06/22 PHP
php判断数组中是否存在指定键(key)的方法
2015/03/17 PHP
深入理解PHP中的Streams工具
2015/07/03 PHP
js 目录列举函数
2008/11/06 Javascript
javascript 表格排序和表头浮动效果(扩展SortTable)
2009/04/07 Javascript
ko knockoutjs动态属性绑定技巧应用
2012/11/14 Javascript
ajax不执行success回调而是执行了error回调
2012/12/10 Javascript
js动态创建、删除表格示例代码
2013/08/07 Javascript
深入理解javascript动态插入技术
2013/11/12 Javascript
js使用for循环与innerHTML获取选中tr下td值
2014/09/26 Javascript
node.js下when.js 的异步编程实践
2014/12/03 Javascript
详解JavaScript的AngularJS框架中的作用域与数据绑定
2016/03/04 Javascript
springMVC结合AjaxForm上传文件
2016/07/12 Javascript
express文件上传中间件Multer详解
2016/10/24 Javascript
巧用Vue.js+Vuex制作专门收藏微信公众号的app
2016/11/03 Javascript
javascript实现鼠标点击页面 移动DIV
2016/12/02 Javascript
js 文字超出长度用省略号代替,鼠标悬停并以悬浮框显示实例
2016/12/06 Javascript
EasyUI折叠表格层次显示detailview详解及实例
2016/12/28 Javascript
jQuery图片拖动组件Dropzone用法示例
2017/01/17 Javascript
Javascript下拉刷新的简单实现
2017/02/14 Javascript
JS+CSS实现网页加载中的动画效果
2017/10/27 Javascript
ptyhon实现sitemap生成示例
2014/03/30 Python
分析Python编程时利用wxPython来支持多线程的方法
2015/04/07 Python
Python语言快速上手学习方法
2018/12/14 Python
在Pycharm中对代码进行注释和缩进的方法详解
2019/01/20 Python
Tensorflow加载Vgg预训练模型操作
2020/05/26 Python
windows支持哪个版本的python
2020/07/03 Python
CSS3下的渐变文字效果实现示例
2018/03/02 HTML / CSS
在SQL Server中创建数据库主要有那种方式
2013/09/10 面试题
记者岗位职责
2014/01/06 职场文书
党员入党表决心的话
2014/03/11 职场文书
大班下学期幼儿评语
2014/12/30 职场文书
钱学森观后感
2015/06/04 职场文书
董事长年会致辞
2015/07/29 职场文书
JavaWeb Servlet实现网页登录功能
2021/07/04 Java/Android