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发送邮件的实例代码(支持html、图片、附件)
Mar 04 Python
python实现根据窗口标题调用窗口的方法
Mar 13 Python
Python爬虫抓取手机APP的传输数据
Jan 22 Python
Python二维码生成识别实例详解
Jul 16 Python
浅析python redis的连接及相关操作
Nov 07 Python
python3实现单目标粒子群算法
Nov 14 Python
Python2与Python3的区别详解
Feb 09 Python
Python多线程正确用法实例解析
May 30 Python
python中return不返回值的问题解析
Jul 22 Python
python创建文本文件的简单方法
Aug 30 Python
容易被忽略的Python内置类型
Sep 03 Python
pytorch fine-tune 预训练的模型操作
Jun 03 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
iis下php mail函数的sendmail配置方法(官方推荐)
2012/04/25 PHP
php使用正则表达式进行字符串搜索的方法
2015/03/23 PHP
php实现的美国50个州选择列表实例
2015/04/20 PHP
Mac下php 5升级到php 7的步骤详解
2017/04/26 PHP
laravel 关联关系遍历数组的例子
2019/10/10 PHP
JS 学习笔记 防止发生命名冲突
2009/07/30 Javascript
JavaScript高级程序设计 读书笔记之九 本地对象Array
2012/02/27 Javascript
jquery网页元素拖拽插件效果及实现
2013/08/05 Javascript
cookie中的path与domain属性详解
2013/12/18 Javascript
js读取json的两种常用方法示例介绍
2014/10/19 Javascript
JavaScript使用DeviceOne开发实战(四)仿优酷视频应用
2015/12/02 Javascript
JS禁止浏览器右键查看元素或按F12审查元素自动关闭页面示例代码
2017/09/07 Javascript
少女风vue组件库的制作全过程
2019/05/15 Javascript
vue实现二级导航栏效果
2019/10/19 Javascript
基于JavaScript的数据结构队列动画实现示例解析
2020/08/06 Javascript
Vant picker 多级联动操作
2020/11/02 Javascript
python定时检查启动某个exe程序适合检测exe是否挂了
2013/01/21 Python
浅析Python中的多重继承
2015/04/28 Python
简单介绍Python中的floor()方法
2015/05/15 Python
在CentOS上配置Nginx+Gunicorn+Python+Flask环境的教程
2016/06/07 Python
Python多线程threading和multiprocessing模块实例解析
2018/01/29 Python
PyQt5打开文件对话框QFileDialog实例代码
2018/02/07 Python
Python异常对代码运行性能的影响实例解析
2018/02/08 Python
解决Pycharm中恢复被exclude的项目问题(pycharm source root)
2020/02/14 Python
浅谈对python中if、elif、else的误解
2020/08/20 Python
python time.strptime格式化实例详解
2021/02/03 Python
html5 video全屏播放/自动播放的实现示例
2020/08/06 HTML / CSS
美国奢侈品购物平台:Orchard Mile
2018/05/02 全球购物
关于Assembly命名空间的三个面试题
2015/07/23 面试题
教师节促销方案
2014/03/22 职场文书
精神文明建设先进工作者事迹材料
2014/05/02 职场文书
中文专业求职信
2014/06/20 职场文书
群众路线四风问题整改措施
2014/09/27 职场文书
房产销售独家委托书范本
2014/10/01 职场文书
apache基于端口创建虚拟主机的示例
2021/04/22 Servers
微软Win11什么功能最惊艳? Windows11新功能特性汇总
2021/11/21 数码科技