python中的内置globals()详解

最近在看一段代码时,发现作者使用globals()来应对无法确定变量名的情况,故此对该函数进行了详细的了解。

一、基本情况

globals() 是Python的标准内置函数,用于返回当前模块中定义的全局变量的字典(包含所有的全局变量、函数、类、导入的模块) ,其中键是变量名,值是变量的值。字典可进行修改,修改后会随之反映到全局变量上。对于函数内的代码,返回的为在定义函数时确定的该字典,无论在哪里调用都保持不变。

globals是特殊场景的解决方案,如动态批量处理全局变量/函数(eg:配置加载)、调试时快速排查全局状态问题、框架/库的底层实现,且有完善的封装和文档。
缺点:可读性差,命名冲突、作用域误区、线程不安全、性能损耗、破坏封装
重点:非必要不使用,优先使用字典/类进行替代,使用时做好校验、锁和注释。

二、常用场景实例
核心价值是动态操作全局命名空间 ,由于操作的是全局状态,使用时需要谨慎。

1、批量处理配置变量、根据配置变量名读取对应的值

python 复制代码
config0= 10
config1 = 30
config2 = "INFO"

# 变量名来自外部(如配置文件、用户输入)
config_keys = ["config0", "config1", "config2"]
# 动态读取所有配置
for key in config_keys:
    if key in globals():
        print(f"{key}: {globals()[key]}")

运行结果:

2、批量初始化

编码前,无法预知所有的变量名或需要生成大量相似的变量名,需要通过代码逻辑批量生成全局变量

3、函数内部修改全局变量

编码需要时,则需要使用,此处不进行举例说明了。

三、使用注意事项

globals()直接操作全局命名空间,滥用会导致代码可读性、可维护性大幅下降,甚至引发隐藏bug

1、严重降低代码可读性与可维护性

动态操作的变量/函数名是字符串,IDE无法自动补全、跳转,代码审查时难以追踪变量的定义/修改位置,后期维护成本高,如下图所示:

上方globals()里面变量/函数内容很多,某个变量随时可能被其他方法更改,当出现问题时,排查很困难。下方单独使用var_dict很清晰能知道变量是在哪里来的,在哪里修改的。

2、易引发命名冲突与意外覆盖

全局命名空间包含模块顶层定义的变量、函数、类等,globals()动态创建/修改变量,若名称与已有重复,则会静默覆盖原有对象。

在程序中,如不小心覆盖内置函数,在访问中可能会遇到报错,如下所示

在程序中,如多处动态给某个变量赋值,则会造成功能错误

如上所示,本身天津和重庆都有叫张三的,结果由于程序后面进行了覆盖,只保留了最后的值。这种在程序中也不存在语法错误,在排查bug时会比较麻烦
建议:动态命名时加前缀,避免与内置名、已有变量重名
操作赋值前,先校验是否为已有变量

3、globals()作用区域理解存在误区

python中的几种作用域可详见:https://blog.csdn.net/qq_44801116/article/details/158041678?spm=1001.2014.3001.5501

很多人会误以为globals()可以获取到外层函数作用域,实际是未搞清楚外层函数的变量的作用域为嵌套作用域,不会影响全局变量。嵌套函数想访问外层函数变量,需要使用nonlocal或local(),而非globals()

4、多线程时,存在线程安全问题

多线程同时通过globals()读写全局变量时,同时修改一个变量,会导致数据不一致。

python 复制代码
count = 0
def increment():
    for _ in range(100000):
        globals()["count"] += 1

t1 = threading.Thread(target=increment)
t2 = threading.Thread(target=increment)
t1.start()
t2.start()
t1.join()
t2.join()
print(count)

运行结果是200000,但是实际结果是随机,如下

可以通过加锁的形式,访问全局变量从而保证结果的正确性。

python 复制代码
def increment():
    for _ in range(100000):
        while threading.Lock():
            globals()["count"] += 1

5、性能损耗:尤其频繁操作

globals返回的字典,字典的键查找/赋值比直接访问变量要慢,尤其在频繁操作时会累积性能损耗。

建议循环中需要频繁操作局部变量时,先将赋值给局部变量,操作完成后再赋值给全局变量

相关推荐
东莞市云毅网络有限公司10 小时前
AI 引用句逐条回指原文:让回答可回溯的校验实现
python·数据清洗·rag·企业知识库·文档解析
Sarvartha12 小时前
final 关键字
java·开发语言
数字融合12 小时前
透明化视频三维矿山井下照明重建技术
人工智能·python·数码相机
yi01112 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
程序员Sunday12 小时前
JavaScript 事件循环面试题,宏任务与微任务怎么执行|Sunday面试指南
开发语言·javascript·面试·校招·事件循环·程序员sunday
zhangzeyuaaa13 小时前
Ruby 多线程、GVL(GIL)与 Mutex 完全指南
开发语言·前端·ruby
Marst Code14 小时前
上位机开发日记 · 第 2 篇 · 架构先行:六层分层与边界
python
李日华大战鸡红14 小时前
FOC状态空间方程模型推导(学习记录)
python·学习·线性代数
谢亮_vipxieliang14 小时前
用 PHP 构建轻量级 REST API:从路由到鉴权的完整实践
开发语言·后端·php
思无邪6615 小时前
用 AI 做 JS 逆向:从抓包到复现的完整方法论
开发语言·javascript·人工智能