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实现ipsec开权限实例
Nov 11 Python
python 简单的多线程链接实现代码
Aug 28 Python
python如何修改装饰器中参数
Mar 20 Python
python使用turtle库绘制时钟
Mar 25 Python
详解python 爬取12306验证码
May 10 Python
使用python获取邮箱邮件的设置方法
Sep 20 Python
Python字典的概念及常见应用实例详解
Oct 30 Python
Python xlrd excel文件操作代码实例
Mar 10 Python
Python使用Excel将数据写入多个sheet
May 16 Python
Python基于locals返回作用域字典
Oct 17 Python
Python request post上传文件常见要点
Nov 20 Python
利用Python实现翻译HTML中的文本字符串
Jun 21 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 删除记录实现代码
2009/03/12 PHP
php调用mysql数据 dbclass类
2011/05/07 PHP
php类常量的使用详解
2013/06/08 PHP
thinkPHP3.1验证码的简单实现方法
2016/04/22 PHP
基于php中echo用逗号和用点号的区别详解
2018/01/23 PHP
Laravel + Elasticsearch 实现中文搜索的方法
2020/02/02 PHP
本地对象Array的原型扩展实现代码
2010/12/04 Javascript
node.js中的fs.readSync方法使用说明
2014/12/17 Javascript
jQuery Validation Plugin验证插件手动验证
2016/01/26 Javascript
深入理解bootstrap框架之入门准备
2016/10/09 Javascript
微信小程序 合法域名校验出错详解及解决办法
2017/03/09 Javascript
从对象列表中获取一个对象的方法,依据关键字和值
2017/09/20 Javascript
简单谈谈CommonsChunkPlugin抽取公共模块
2017/12/31 Javascript
js实现动态改变radio状态的方法
2018/02/28 Javascript
vue如何截取字符串
2019/05/06 Javascript
对layui初始化列表的CheckBox属性详解
2019/09/13 Javascript
用Python计算三角函数之acos()方法的使用
2015/05/15 Python
pandas的object对象转时间对象的方法
2018/04/11 Python
Python替换月份为英文缩写的实现方法
2019/07/15 Python
python从list列表中选出一个数和其对应的坐标方法
2019/07/20 Python
Django中自定义模型管理器(Manager)及方法
2019/09/23 Python
Django后台管理系统的图文使用教学
2020/01/20 Python
5行Python代码实现图像分割的步骤详解
2020/05/25 Python
Python连接mysql方法及常用参数
2020/09/01 Python
用css3制作纸张效果(外翻卷角)
2013/02/01 HTML / CSS
canvas烟花特效锦集
2018/01/17 HTML / CSS
西班牙电子产品购物网站:Electronicamente
2018/07/26 全球购物
管理专员自荐信
2014/01/26 职场文书
初三政治教学反思
2014/01/30 职场文书
翻译学院毕业生自荐书
2014/02/02 职场文书
体育之星事迹材料
2014/05/11 职场文书
亮剑精神演讲稿
2014/05/23 职场文书
物流管理专业求职信
2014/05/29 职场文书
关于环保的标语
2014/06/13 职场文书
1000字打架检讨书
2014/11/03 职场文书
2016年5月份红领巾广播稿
2015/12/21 职场文书