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多线程抓取天涯帖子内容示例
Apr 03 Python
一行代码让 Python 的运行速度提高100倍
Oct 08 Python
python交互界面的退出方法
Feb 16 Python
python tkinter库实现气泡屏保和锁屏
Jul 29 Python
python实现ip地址查询经纬度定位详解
Aug 30 Python
pytorch GAN生成对抗网络实例
Jan 10 Python
Python3 ffmpeg视频转换工具使用方法解析
Aug 10 Python
Python3如何使用多线程升程序运行速度
Aug 11 Python
Python爬取微信小程序通用方法代码实例详解
Sep 29 Python
python 合并多个excel中同名的sheet
Jan 22 Python
Matlab求解数组中的最大值及它所在的具体位置
Apr 16 Python
python 开心网和豆瓣日记爬取的小爬虫
May 29 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实现信用卡校验位算法THE LUHN MOD-10示例
2014/05/07 PHP
destoon出现验证码不显示时的紧急处理方法
2014/08/22 PHP
PHP在同一域名下两个不同的项目做独立登录机制详解
2017/09/22 PHP
PHP 的Opcache加速的使用方法
2017/12/29 PHP
JavaScipt基本教程之前言
2008/01/16 Javascript
document.compatMode介绍
2009/05/21 Javascript
jQuery EasyUI API 中文文档 搜索框
2011/09/29 Javascript
JS模板实现方法
2013/04/03 Javascript
JavaScript数字和字符串转换示例
2014/03/26 Javascript
js实现点击文本框显示日期选择器特效代码分享
2020/05/21 Javascript
动态设置form表单的action属性的值的简单方法
2016/05/25 Javascript
12306 刷票脚本及稳固刷票脚本(防挂)
2017/01/04 Javascript
用Vue-cli搭建的项目中引入css报错的原因分析
2017/07/20 Javascript
Angular4学习笔记router的简单使用
2018/03/30 Javascript
Vue+tracking.js 实现前端人脸检测功能
2020/04/16 Javascript
编写Python爬虫抓取暴走漫画上gif图片的实例分享
2016/04/20 Python
简单谈谈python中的多进程
2016/11/06 Python
对Python字符串中的换行符和制表符介绍
2018/05/03 Python
Python实现基于C/S架构的聊天室功能详解
2018/07/07 Python
基于django传递数据到后端的例子
2019/08/16 Python
python3爬虫GIL修改多线程实例讲解
2020/11/24 Python
python 写一个文件分发小程序
2020/12/05 Python
Django与AJAX实现网页动态数据显示的示例代码
2021/02/24 Python
韩国最大的购物网站:Gmarket
2019/06/20 全球购物
大学秋游活动方案
2014/02/11 职场文书
大学生两会学习心得体会
2014/03/10 职场文书
《泉水》教学反思
2014/04/11 职场文书
大学生优秀班干部事迹材料
2014/05/26 职场文书
节水口号标语
2014/06/19 职场文书
二年级语文下册复习计划
2015/01/19 职场文书
简历自荐信范文
2015/03/09 职场文书
2015年教师节慰问信
2015/03/23 职场文书
助学金申请书该怎么写?
2019/07/16 职场文书
Python实现灰色关联分析与结果可视化的详细代码
2022/03/25 Python
详解MongoDB排序时内存大小限制与创建索引的注意事项
2022/05/06 MongoDB