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 ip正则式
May 07 Python
linux系统使用python获取内存使用信息脚本分享
Jan 15 Python
python中查看变量内存地址的方法
May 05 Python
Python中的迭代器与生成器高级用法解析
Jun 28 Python
Python正则表达式使用范例分享
Dec 04 Python
python妙用之编码的转换详解
Apr 21 Python
Tensorflow 实现修改张量特定元素的值方法
Jul 30 Python
Python定时发送消息的脚本:每天跟你女朋友说晚安
Oct 21 Python
解决python线程卡死的问题
Feb 18 Python
python环境路径配置以及命令行运行脚本
Apr 02 Python
Pytorch: 自定义网络层实例
Jan 07 Python
PyTorch的torch.cat用法
Jun 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
拼音码表的生成
2006/10/09 PHP
调整优化您的LAMP应用程序的5种简单方法
2011/06/26 PHP
php each 返回数组中当前的键值对并将数组指针向前移动一步实例
2016/11/22 PHP
Windows平台实现PHP连接SQL Server2008的方法
2017/07/26 PHP
用window.location.href实现刷新另个框架页面
2007/03/07 Javascript
深入理解JavaScript系列(12) 变量对象(Variable Object)
2012/01/16 Javascript
JavaScript保留两位小数的2个自定义函数
2014/05/05 Javascript
使用RequireJS优化JavaScript引用代码的方法
2015/07/01 Javascript
jQuery实现form表单基于ajax无刷新提交方法详解
2015/12/08 Javascript
jQuery prototype冲突的2种解决方法(附demo示例下载)
2016/01/21 Javascript
概述如何实现一个简单的浏览器端js模块加载器
2016/12/07 Javascript
前端html中jQuery实现对文本的搜索功能并把搜索相关内容显示出来
2017/11/14 jQuery
angular2 组件之间通过service互相传递的实例
2018/09/30 Javascript
纯异步nodejs文件夹(目录)复制功能
2019/09/03 NodeJs
jQuery实现轮播图源码
2019/10/23 jQuery
JS数组方法reverse()用法实例分析
2020/01/18 Javascript
vue 使用插槽分发内容操作示例【单个插槽、具名插槽、作用域插槽】
2020/03/06 Javascript
vue 实现在同一界面实现组件的动态添加和删除功能
2020/06/16 Javascript
Element图表初始大小及窗口自适应实现
2020/07/10 Javascript
js实现表格单列按字母排序
2020/08/12 Javascript
python的文件操作方法汇总
2017/11/10 Python
Python实现上下班抢个顺风单脚本
2018/02/07 Python
Django 连接sql server数据库的方法
2018/06/30 Python
手把手教你如何安装Pycharm(详细图文教程)
2018/11/28 Python
用Python中的turtle模块画图两只小羊方法
2019/04/09 Python
python获取本周、上周、本月、上月及本季的时间代码实例
2020/09/08 Python
requests在python中发送请求的实例讲解
2021/02/17 Python
英国奢侈品网站:MatchesFashion
2016/12/16 全球购物
番木瓜健康和保健产品第一大制造商:Herbal Papaya
2017/04/25 全球购物
在C#中如何实现多态
2014/07/02 面试题
人资专员岗位职责
2014/04/04 职场文书
世博会口号
2014/06/20 职场文书
2015年校长新年寄语
2014/12/08 职场文书
考试作弊检讨
2015/01/27 职场文书
兼职安全员岗位职责
2015/02/15 职场文书
浅谈mysql哪些情况会导致索引失效
2021/11/20 MySQL