遍历 globals() 时必不可少的 RuntimeError

news/2024/11/28 6:25:47/

文章目录

  • 参考
  • 描述
  • globals() 函数
  • For Loop 过程中产生的迭代变量
  • Runtime Error
      • dictionary changed size during iteration
      • 异常产生原因
      • 解决方案
          • copy 方法
          • 绕过 RuntimeError
      • 产生 RuntimeError 异常的基本要求
      • 遍历 locals() 时可能产生的 RuntimeError

参考

项目描述
Python 官方文档https://docs.python.org/zh-cn/3/
搜索引擎Google 、Bing

描述

项目描述
PyCharm2023.1 (Professional Edition)
Python3.10.6

globals() 函数

在 Python 中,globals() 是一个 内置函数,它返回一个 表示当前模块全局命名空间的字典,该字典存储了当前模块中定义的所有全局变量和函数。

globals() 函数返回一个字典,其中包含全局作用域中的变量名及其对应的值。这个字典可以用于 访问、修改和删除 全局变量。请注意,通过globals() 函数返回的字典是 实时更新 的,反映了当前的全局命名空间的状态。

举个栗子

free_var = 'Hello World'# globals() 在程序的任何位置访问的结果都是
# 一致的。
for name in globals().copy():print(f'{name}\t{globals()[name]}')# 在调用 globals() 函数时,MyClass
# 与 func 都尚未添加到全局命名空间中。
# 仅但解释器执行到 MyClass 与 func 的定义部分
# Python 才会将其添加至全局命名空间。
class MyClass:passprint()
print('MyClass' in globals())
print('func' in globals())
print()def func():passprint('MyClass' in globals())
print('func' in globals())

执行效果

当解释器加载一个 模块(任何 Python 文件都可被视为模块) 时,它首先会创建一个新的全局作用域对象,用于存储该模块的全局变量、函数、类和其他定义。解释器会 按顺序解析 模块中的代码,并在执行过程中 将标识符绑定到相应的作用域对象中

__name__	__main__
__doc__	None
__package__	None
__loader__	<_frozen_importlib_external.SourceFileLoader object at 0x000002868F414820>
__spec__	None
__annotations__	{}
__builtins__	<module 'builtins' (built-in)>
__file__	C:\Users\RedHeart\PycharmProjects\pythonProject\example.py
__cached__	None
free_var	Hello WorldTrue
FalseTrue
True

For Loop 过程中产生的迭代变量

在 Python 的 for 循环 中,迭代变量 是指在每次迭代中 用于表示可迭代对象中的当前元素的变量。迭代变量的名称是根据程序员的选择来确定的,它可以是 任意有效的变量名

举个栗子

# 在下面的 For Loop 中,迭代变量为 num
for num in range(100):pass# 在 For Loop 过程中,将会在当前作用域下
# 创建迭代变量。因此在 For Loop 结束后,
# 仍能够在当前作用域中访问到该变量。
print(num)

执行效果

99

Runtime Error

dictionary changed size during iteration

当你在 Python 中尝试直接遍历 globals() 的返回结果时,不可避免的将引发 Runtime Error。对此,请参考如下示例:

for key in globals():pass

执行效果

在 Python 中执行上述代码后,Python 将抛出异常错误,其中包含如下内容:

RuntimeError: dictionary changed size during iteration

异常产生原因

字典在内部使用 散列表(也被称为哈希表) 来实现 键值对存储查找。散列表的 工作原理 涉及将键通过哈希函数转换为索引,然后在存储桶中存取相应的值。
散列表的结构在 迭代过程 中是 敏感的。当你在迭代字典的 视图对象(字典提供的视图对象是动态的、实时反映字典内容变化的可迭代对象) 时,若 添加删除 字典中的条目,会导致 字典的结构发生变化
当你迭代字典提供的视图对象时,迭代器会维护一个 内部状态 来跟踪字典的条目。如果在迭代过程中修改字典的大小,迭代器的内部状态与字典的实际状态将不再一致。如果继续迭代,可能会产生意想不到的结果或错误的行为。为了保持迭代的一致性和正确性,Python 选择在这种情况下抛出 RuntimeError 异常,以提醒开发者字典发生了变化,并防止继续迭代可能导致的问题。

在迭代 globals() 函数时,不可避免的将引发 Runtime Error。其原因是,在迭代过程中产生的迭代变量将注册至当前作用域中,导致字典的结构发生改变,从而引发了 RuntimeError 异常错误。

在迭代 globals() 函数时,也可以存在特例不会导致发生 RuntimeError 。对此,请参考如下示例:

def func():for i in globals():passfunc()

在上述代码中,迭代变量将注册至 局部作用域 中,代表全局命名空间的字典并不会因此受到影响。因此,Python 将正常执行上述代码而不引发异常错误。

解决方案

copy 方法

在 Python 中,字典对象具有 copy() 方法,用于创建字典的 浅拷贝
字典对象的 copy() 方法用于创建一个 的字典对象,其中包含原始字典的副本。该副本是一个独立的字典对象,具有相同的键值对。但是,它是一个 浅拷贝,意味着副本中的键值对是原始字典中相应键值对的 引用

举个栗子

d = {'member': ['RedHeart', 'BinaryMoon']}# 获取字典对象 d 的浅拷贝
shallow_d = d.copy()# 判断两个字典中的键值对的内容是否完全相同,
# 不考虑键值对的排列顺序。
print(d == shallow_d)# 判断原对象与其浅拷贝对象的身份标识是否相同,
# 对象的身份标识及其在内存空间中存放的内存地址信息。
print(d is shallow_d)# 尝试修改字典中的可变对象(列表)
d['member'].append('BlackOvercoat')# 由于浅拷贝后的数据结构中的元素是原数据结构的元素的引用,
# 因此可变对象的更改将影响其他浅拷贝中相应可变对象的更改。
print(d)
print(shallow_d)

执行效果

True
False
{'member': ['RedHeart', 'BinaryMoon', 'BlackOvercoat']}
{'member': ['RedHeart', 'BinaryMoon', 'BlackOvercoat']}
绕过 RuntimeError

在迭代过程中产生的迭代变量将注册至当前作用域的命名空间中。若在全局作用域中迭代 globals() 函数,将在全局命名空间中注册迭代变量,这会导致 globals() 函数发生改变,从而引发 RuntimeError。若我们迭代的是 globals() 的副本,即使迭代过程中产生的迭代变量会导致原对象发生改变,但这并不会影响到其相关的拷贝对象。

举个栗子

for i in globals().copy():pass

执行效果

遍历对象由 globals() 改为 globals().copy() 后,执行上述代码,Python 将不会抛出 RuntimeError 异常错误。

产生 RuntimeError 异常的基本要求

在遍历 globals() 产生 RuntimeError 的一个基本要求是,globals() 函数的返回结果中存在 至少一个 的键值对。第一次迭代过程中将产生并注册 迭代变量(Python 将从被迭代对象中取出一个值并赋值给迭代变量),若没有进行第二次迭代,则 For Loop 将无法发现被迭代字典对象的改变。
由于 Python 在执行代码前会创建多个全局变量供用户使用,因此 globals() 的返回值总是会满足该要求。但由 遍历 globals() 产生 RuntimeError 的基本要求 我们可以理解为什么遍历 globals() 时,总是在访问第一个 globals() 元素后产生 RuntimeError。对此,请参考如下示例:

for i in globals():print(i)

执行效果

执行上述代码后,Python 将在输出 globals() 返回的字典对象的第一个 后产生 RuntimeError

__name__

遍历 locals() 时可能产生的 RuntimeError

在 Python 中,locals() 是一个 内置函数,用于返回 当前作用域的命名空间的字典,该字典存储了当前作用域中定义的所有全局变量和函数。
locals() 函数返回一个字典,其中包含局部作用域中的变量名及其对应的值。这个字典可以用于 访问、修改和删除 当前作用域中的变量。

locals()globals() 函数的功能类似,这也意味着 locals() 也存在与 globals() 相同的问题,但 locals() 相比 globals() 来说,更为复杂也更难被触发。如需对其进行了解,欢迎前往我的另一篇博客 遍历 locals() 时可能产生的 RuntimeError


http://www.ppmy.cn/news/83683.html

相关文章

HR不会告诉你!Java程序员月薪8K和20K的区别!

昨天有同学问好程序员&#xff0c;为啥都是干Java程序员&#xff0c;别人可以拿20k&#xff0c;我才拿8k呢&#xff1f;为啥人家能提前转正我就得晚俩月&#xff1f;小源一听大事不妙&#xff0c;赶紧连夜整理了以下清单供大家check&#xff01; 对于刚入职场还有跳槽成功的同学…

NRK3303语音识别芯片在照明灯上的运用,一款可分布式语音IC方案

随着科技的不断进步&#xff0c;人们对于家居生活中的照明设备的要求也逐渐提高。传统的照明方式已经不能满足人们对智能家居的需求&#xff0c;我们需要更加智能、易于操作、高效节能的智能化照明系统。因此&#xff0c;智能照明应运而生&#xff0c;为我们提供了更加智能化、…

Java Swing 快速入门

Java Swing 快速入门 文章目录 Java Swing 快速入门一、Java Swing 简单介绍1、Java Swing 介绍2、Java Swing 使用步骤3、Java Swing 组件二、Java Swing 简单使用案例1、Hello World 程序2、一个用户登录框实例三、附录1、概念解析2、Swing 的坐标图一、Java Swing 简单介绍 …

【LeetCode】字符串转换整数 (atoi) [M](模拟)

8. 字符串转换整数 (atoi) - 力扣&#xff08;LeetCode&#xff09; 一、题目 请你来实现一个 myAtoi(string s) 函数&#xff0c;使其能将字符串转换成一个 32 位有符号整数&#xff08;类似 C/C 中的 atoi 函数&#xff09;。 函数 myAtoi(string s) 的算法如下&#xff1a…

第十二章 异常(Exception)

一、异常的概念&#xff08;P444&#xff09; Java 语言中&#xff0c;将程序执行中发生的不正常情况称为“异常”。&#xff08;开发过程中的语法错误和逻辑错误不是异常&#xff09; 执行过程中所发生的异常事件可分为两大类&#xff1a; &#xff08;1&#xff09;Error&…

C#入门:编写运行第一个C#程序Helloworld

参考链接&#xff1a; C#入门学习-希里安 下载安装Visual Studio&#xff0c;创建项目 在官网下载安装Professional 2022即可. https://visualstudio.microsoft.com/zh-hans/ 下载时选择C#、.Net框架等支持&#xff0c;安装后运行&#xff0c;新建模板选择 Visual C#、Windo…

【uni-app】实现上拉加载

【场景】 假设你正在开发一款社交软件&#xff0c;用户可以浏览其他用户发布的动态信息。当用户下滑页面查看信息时&#xff0c;如果所有信息都被加载出来了&#xff0c;那么用户无法继续获取新的动态信息。因此&#xff0c;我们需要在这种情况下使用“上拉加载更多”的功能。…

整理6个超好用的在线编辑器!

随着 Web 开发对图像可扩展性、响应性、交互性和可编程性的需求增加&#xff0c;SVG 图形成为最适合 Web 开发的图像格式之一。它因文件小、可压缩性强并且无论如何放大或缩小&#xff0c;图像都不会失真而受到欢迎。然而&#xff0c;为了编辑 SVG 图像&#xff0c;需要使用 SV…