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中使用urllib2获取http请求状态码的代码例子
Jul 07 Python
零基础写python爬虫之抓取百度贴吧并存储到本地txt文件改进版
Nov 06 Python
Python中的__new__与__init__魔术方法理解笔记
Nov 08 Python
Python中优化NumPy包使用性能的教程
Apr 23 Python
Python编程中运用闭包时所需要注意的一些地方
May 02 Python
用pandas按列合并两个文件的实例
Apr 12 Python
Django框架之登录后自定义跳转页面的实现方法
Jul 18 Python
Python批量安装卸载1000个apk的方法
Apr 10 Python
python调用百度API实现人脸识别
Nov 17 Python
Python爬虫自动化获取华图和粉笔网站的错题(推荐)
Jan 08 Python
Jupyter notebook 更改文件打开的默认路径操作
May 21 Python
python ConfigParser库的使用及遇到的坑
Feb 12 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下通过POST还是GET来传值
2008/06/05 PHP
php 动态执行带有参数的类方法
2009/04/10 PHP
ThinkPHP验证码使用简明教程
2014/03/05 PHP
PHP基于CURL进行POST数据上传实例
2014/11/10 PHP
学习php设计模式 php实现访问者模式(Visitor)
2015/12/07 PHP
PHP实现按之字形顺序打印二叉树的方法
2018/01/16 PHP
php使用curl模拟浏览器表单上传文件或者图片的方法
2018/11/10 PHP
javascript 数组的方法集合
2008/06/05 Javascript
如何利用AngularJS打造一款简单Web应用
2015/12/05 Javascript
Javascript复制实例详解
2016/01/28 Javascript
js格式化输入框内金额、银行卡号
2016/02/01 Javascript
浅谈在vue项目中如何定义全局变量和全局函数
2017/10/24 Javascript
angularJS实现动态添加,删除div方法
2018/02/27 Javascript
socket io与vue-cli的结合使用的示例代码
2018/11/01 Javascript
vue实现的请求服务器端API接口示例
2019/05/25 Javascript
layui实现数据表格table分页功能(ajax异步)
2019/07/27 Javascript
Vue.js 无限滚动列表性能优化方案
2019/12/02 Javascript
详解vue-router 动态路由下子页面多页共活的解决方案
2019/12/22 Javascript
vue中解决微信html5原生ios虚拟键返回不刷新问题
2020/10/20 Javascript
pandas全表查询定位某个值所在行列的方法
2018/04/12 Python
Django框架多表查询实例分析
2018/07/04 Python
python实现爬山算法的思路详解
2019/04/09 Python
python买卖股票的最佳时机(基于贪心/蛮力算法)
2019/07/05 Python
python使用 request 发送表单数据操作示例
2019/09/25 Python
python3 sleep 延时秒 毫秒实例
2020/05/04 Python
浅谈keras中的后端backend及其相关函数(K.prod,K.cast)
2020/06/29 Python
详解Canvas 实现炫丽的粒子运动效果(粒子生成文字)
2018/02/01 HTML / CSS
html5与css3小应用
2013/04/03 HTML / CSS
梅西酒窖:Macy’s Wine Cellar
2018/01/07 全球购物
英国在线自行车店:Merlin Cycles
2018/08/20 全球购物
医学类导师推荐信范文
2013/11/19 职场文书
大学生的创业计划书就该这么写
2014/01/30 职场文书
项目申请汇报材料
2014/08/16 职场文书
创建绿色学校先进个人材料
2014/08/20 职场文书
工商局局长个人对照检查材料思想汇报
2014/09/23 职场文书
小学英语课教学反思
2016/02/15 职场文书