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实现自动登录百度空间的方法
Jun 10 Python
python 中random模块的常用方法总结
Jul 08 Python
[原创]教女朋友学Python3(二)简单的输入输出及内置函数查看
Nov 30 Python
python监控文件并且发送告警邮件
Jun 21 Python
从请求到响应过程中django都做了哪些处理
Aug 01 Python
对python中的高效迭代器函数详解
Oct 18 Python
Python日志syslog使用原理详解
Feb 18 Python
Pytorch 使用 nii数据做输入数据的操作
May 26 Python
Python Tkinter实例——模拟掷骰子
Oct 24 Python
Django websocket原理及功能实现代码
Nov 14 Python
pycharm 实现调试窗口恢复
Feb 05 Python
Python软件包安装的三种常见方法
Jul 07 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
Django 中 cookie的使用
2017/08/17 PHP
thinkphp5框架扩展redis类方法示例
2019/05/06 PHP
Jquery下attr和removeAttr的使用方法
2010/12/28 Javascript
JS模板实现方法
2013/04/03 Javascript
JavaScript伸缩的菜单简单示例
2013/12/03 Javascript
JavaScript中用getDate()方法返回指定日期的教程
2015/06/09 Javascript
Bootstrap的Refresh Icon也spin起来
2016/07/13 Javascript
Bootstrap 最常用的JS插件系列总结(图片轮播、标签切换等)
2016/07/14 Javascript
js实现常用排序算法
2016/08/09 Javascript
深入分析javascript中console命令
2016/08/14 Javascript
jQuery插件HighCharts实现的2D条状图效果示例【附demo源码下载】
2017/03/15 Javascript
详解Vue中添加过渡效果
2017/03/20 Javascript
整理关于Bootstrap排版的慕课笔记
2017/03/29 Javascript
Vue报错:Uncaught TypeError: Cannot assign to read only property’exports‘ of object’#‘的解决方法
2017/06/17 Javascript
详解Vue 中 extend 、component 、mixins 、extends 的区别
2017/12/20 Javascript
vue+elementUI 复杂表单的验证、数据提交方案问题
2019/06/24 Javascript
layui关闭层级、简单监听的实例
2019/09/06 Javascript
vue使用transition组件动画效果的实例代码
2021/01/28 Vue.js
[02:28]DOTA2亚洲邀请赛 LGD战队巡礼
2015/02/03 DOTA
[01:11:35]Liquid vs LGD 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python绘制频率分布直方图的示例
2019/07/08 Python
Python 找出出现次数超过数组长度一半的元素实例
2020/05/11 Python
matplotlib基础绘图命令之errorbar的使用
2020/08/13 Python
Python实现壁纸下载与轮换
2020/10/19 Python
Python实现中英文全文搜索的示例
2020/12/04 Python
matplotlib之多边形选区(PolygonSelector)的使用
2021/02/24 Python
HTML5 textarea高度自适应的两种方案
2020/04/08 HTML / CSS
俄罗斯药房连锁店:ASNA
2020/06/20 全球购物
标准毕业生自荐信范文
2013/11/04 职场文书
班长岗位职责
2013/11/10 职场文书
大学生找工作求职信
2014/07/09 职场文书
2014年幼儿园园务工作总结
2014/12/05 职场文书
2016年春节慰问信息
2015/03/25 职场文书
SQL写法--行行比较
2021/08/23 SQL Server
Python函数对象与闭包函数
2022/04/13 Python
html网页引入svg图片的4种方式
2022/08/05 HTML / CSS