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 相关文章推荐
pyside写ui界面入门示例
Jan 22 Python
python处理圆角图片、圆形图片的例子
Apr 25 Python
在Python中通过threading模块定义和调用线程的方法
Jul 12 Python
利用Python中unittest实现简单的单元测试实例详解
Jan 09 Python
Python实现PS图像调整黑白效果示例
Jan 25 Python
python获取服务器响应cookie的实例
Dec 28 Python
python 获取sqlite3数据库的表名和表字段名的实例
Jul 17 Python
Pytorch 实现自定义参数层的例子
Aug 17 Python
Python3连接Mysql8.0遇到的问题及处理步骤
Feb 17 Python
matplotlib基础绘图命令之bar的使用方法
Aug 13 Python
如何基于Python和Flask编写Prometheus监控
Nov 25 Python
解决Pycharm 运行后没有输出的问题
Feb 05 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/12/19 PHP
PHP中将字符串转化为整数(int) intval() printf() 性能测试
2020/03/20 PHP
Laravel中使用自己编写类库的3种方法
2015/02/10 PHP
PHP创建PowerPoint2007文档的方法
2015/12/10 PHP
Yii框架连表查询操作示例
2019/09/06 PHP
jQuery 全选效果实现代码
2009/03/23 Javascript
jQuery 树形结构的选择器
2010/02/15 Javascript
JS获取html对象的几种方式介绍
2013/12/05 Javascript
js使用循环清空某个div中的input标签值
2014/09/29 Javascript
js实现iframe跨页面调用函数的方法
2014/12/13 Javascript
jquery右下角自动弹出可关闭的广告层
2015/05/08 Javascript
JavaScript重载函数实例剖析
2016/05/13 Javascript
javascript中sort排序实例详解
2016/07/24 Javascript
分享JS数组求和与求最大值的方法
2016/08/11 Javascript
网页中右键功能的实现方法之contextMenu的使用
2017/02/20 Javascript
jquery radio 动态控制选中失效问题的解决方法
2018/02/28 jQuery
vue 路由嵌套高亮问题的解决方法
2018/05/17 Javascript
浅谈Webpack打包优化技巧
2018/06/12 Javascript
使用Easyui实现查询条件的后端传递并自动刷新表格的两种方法
2019/09/09 Javascript
layui的layedit富文本赋值方法
2019/09/18 Javascript
Python程序员开发中常犯的10个错误
2014/07/07 Python
python查询mysql中文乱码问题
2014/11/09 Python
Python读写Json涉及到中文的处理方法
2016/09/12 Python
详谈python在windows中的文件路径问题
2018/04/28 Python
python简易远程控制单线程版
2018/06/20 Python
Laravel+Dingo/Api 自定义响应的实现
2019/02/17 Python
Python实现去除图片中指定颜色的像素功能示例
2019/04/13 Python
Python3操作Excel文件(读写)的简单实例
2019/09/02 Python
解决tensorflow读取本地MNITS_data失败的原因
2020/06/22 Python
传播学专业毕业生自荐信
2013/11/04 职场文书
岗位职责范本
2013/11/23 职场文书
激励口号大全
2014/06/17 职场文书
省委召开党的群众路线教育实践活动总结大会报告
2014/10/21 职场文书
Python连续赋值需要注意的一些问题
2021/06/03 Python
python实现A*寻路算法
2021/06/13 Python
Python 正则模块详情
2021/11/02 Python