初学代码时总有一个问题困扰我:a = 10 # a指向地址0x1234(存储10)
变量a的值10存储在0x1234,那么变量a需要存储吗?a又存储在什么地址呢
目录
1. 命名空间的本质
2. 命名空间的内存占用
3. 变量名 vs 变量值的存储对比
4. 静态语言(如C)的对比
5. 为什么需要命名空间?
6. 总结
7.小测试
1. 命名空间的本质
- 动态语言(如Python):
变量名与值的绑定关系通过 命名空间字典(如globals()
)维护,但这个字典本身是一个 运行时动态创建的对象,存储在内存中。- 变量名
"a"
:作为字典的 键(Key)(字符串对象)存储。 - 变量值
10
:作为字典的 值(Value)(指向实际对象的引用)。
- 变量名
# 伪代码展示Python内部实现(简化版)
global_namespace = {"a": 0x1234, # 键是字符串"a",值是对象10的地址"b": 0x5678 # 其他变量...
}
2. 命名空间的内存占用
- 存储位置:
命名空间字典本身是一个 堆内存中的对象,有独立的内存地址(可通过id(globals())
查看)。print(hex(id(globals()))) # 输出如0x55a1b2d3e0(命名空间字典的地址)
- 内存消耗:
- 每个键(变量名)作为字符串对象存储,占用内存。
- 每个值(变量引用)是指针(通常8字节,64位系统)。
- 字典的哈希表结构还有额外开销(如哈希桶、冲突处理)。
3. 变量名 vs 变量值的存储对比
存储内容 | 存储位置 | 示例(Python) |
---|---|---|
变量名 "a" | 命名空间字典的键(堆内存) | globals()["a"] 中的 "a" |
变量值 10 | 独立对象(堆内存) | id(a) 返回的地址(如 0x1234 ) |
命名空间字典 | 堆内存中的对象 | id(globals()) 返回的地址(如 0x55a1b2d3e0 ) |
4. 静态语言(如C)的对比
- 无运行时命名空间:
变量名在编译后直接替换为固定内存地址,不占用运行时内存。int a = 10; // 编译后,所有对a的访问变为对地址0x1000的操作
- 无字典开销:
变量名仅在源码和符号表中存在,编译后的二进制文件中无痕迹。
5. 为什么需要命名空间?
- 动态语言的灵活性:
Python 允许运行时动态添加/删除变量(如globals()["x"] = 100
),必须维护变量名与值的映射关系。 - 作用域管理:
每个函数有独立的locals()
字典,实现变量隔离。
6. 总结
- 变量名存储:作为字符串键存在于命名空间字典中(堆内存)。
- 命名空间存储:字典对象本身占用内存(地址可通过
id(globals())
获取)。 - 核心区别:
- 静态语言:变量名是编译期概念,无运行时存储。
- 动态语言:变量名是运行时对象,需内存存储以支持动态特性。
7.小测试
- 多个变量的值相同的情况下,内存空间里是如何存储的?(答案在下期)
- 举例:a=b=c=10
这种设计是 Python 等动态语言灵活性的代价——牺牲部分内存和速度换取开发便捷性。
元宝老师提供标准化答案,解释权归迪普斯克老师,侵删~