5 Python的变量与内存模型
什么是变量?(便利贴 vs 盒子)
在传统的静态语言(如 C 语言)中,变量通常被比喻为一个盒子:你申请一个盒子,给它贴上名字,然后把数据放进去。
但在 Python 中,变量更像是一个便利贴(标签)。
- 对象(Object):是内存中实实在在存储数据的地方(比如数字
10,字符串"Hello")。 - 变量(Variable):只是一个名字,你把这个名字“贴”到了某个对象上。
核心概念: 变量本身不存储数据,它只是指向了存储数据的内存地址。
变量的基本用法
Python 是动态类型语言,这意味着你不需要显式声明变量的类型(如 int a),直接赋值即可使用。
基础赋值
# 将 "score" 这个标签贴在数字 100 上
score = 100
# 将 "username" 这个标签贴在字符串 "Alice" 上
username = "Alice"
print(score) # 输出: 100
print(username) # 输出: Alice动态类型特性
同一个变量名可以随时被贴到不同类型的对象上:
var = 123 # var 现在指向整数
print(var)
var = "Python" # var 现在指向字符串(类型变了,但在Python中是合法的)
print(var)深入理解:内存引用与 id() 函数
这是理解 Python 变量逻辑最关键的一步。为了验证“变量是引用”这一说法,我们需要使用 Python 的内置函数 id()。
id(object):返回对象的“身份”,在 CPython 实现中,这通常就是对象在内存中的地址。
- Python 是一种编程语言,它是一套语法规范和语义规则,但是它本身不能直接运行代码。为了执行 Python 代码,我们需要一个解释器(Interpreter)。CPython 是最常用的 Python 解释器的实现,它使用 C 语言编写,并且在 CPython 中,
id()函数返回的是对象在内存中的地址。- CPython 是 Python 语言的官方参考实现,由 Python 创始人 Guido van Rossum 主导开发,用 C 语言 编写,因此得名 C + Python = CPython。当你从 python.org 下载并安装 Python 时,你安装的就是 CPython。
示例:查看变量的内存地址
x = 10
print(f"x的值: {x}, x的内存地址: {id(x)}")
# 让我们看看发生了什么
y = 10
print(f"y的值: {y}, y的内存地址: {id(y)}")运行结果(示例):
x的值: 10, x的内存地址: 4304675344
y的值: 10, y的内存地址: 4304675344分析:
你会发现 x 和 y 的 id 是一样的!
- Python 内存中创建了一个整数对象
10。 x = 10:把标签x贴在对象10上。y = 10:Python 检测到内存中已经有小整数10了(由于 Python 的小整数缓存机制),它直接把标签y也贴到了同一个对象10上。- 结论: 变量
x和y指向了同一个内存块。
示例:重新赋值的真相
如果我们修改 x 的值,会发生什么?
x = 10
print(f"初始 x 地址: {id(x)}")
x = 20
print(f"修改后 x 地址: {id(x)}")分析:
你会发现地址变了。
- 不是把内存中
10改成了20。 - 而是在内存中新建(或找到)了一个对象
20,然后把标签x从10身上撕下来,贴到了20身上。 - 原来的对象
10如果没有其他变量引用它,稍后会被垃圾回收机制回收。
变量的传递(引用传递)
理解了“便利贴”模型,变量之间的赋值逻辑就很好理解了。
场景一:不可变对象(数字、字符串、元组)
a = 100
b = a # 把 b 贴到 a 当前指向的对象上
print(f"a的地址: {id(a)}")
print(f"b的地址: {id(b)}") # 地址相同
a = 200 # a 换到了新对象 200 上,b 仍然贴在 100 上
print(f"a的值: {a}, b的值: {b}")结果: b 依然是 100。因为改变 a 只是移动了 a 这个标签,不影响 b 这个标签。
场景二:可变对象(列表、字典)—— 新手最大的坑
对于列表这种“可变对象”,情况会变得有趣:
list_1 = [1, 2, 3]
list_2 = list_1 # list_2 和 list_1 指向同一个列表对象
print(f"list_1 地址: {id(list_1)}")
print(f"list_2 地址: {id(list_2)}") # 地址完全一样
# 修改 list_1 的内容
list_1.append(4)
print(f"list_1: {list_1}")
print(f"list_2: {list_2}") # 注意:list_2 也变了!分析:
list_1和list_2贴在同一个“箱子”(列表)上。list_1.append(4)是往箱子里扔了一个新数据,并没有换箱子(地址没变)。- 所以,通过
list_2往里看,也能看到新增加的数据。
变量表达式赋值
Python 提供了非常优雅的赋值方式,可以让代码更简洁。
1. 链式赋值
将同一个值赋给多个变量:
a = b = c = 0
print(a, b, c) # 输出: 0 0 0注意:如果是可变对象(如列表),它们都会指向同一个对象,修改其中一个会影响全部。
2. 解包赋值 (Unpacking)
这是 Python 的杀手级特性,可以同时给多个变量赋值:
# 对应位置赋值
name, age = "Bob", 25
print(name) # Bob
print(age) # 25
# 交换变量值(无需中间变量)
x = 5
y = 10
x, y = y, x
print(x, y) # 输出: 10 53. 星号解包
当变量数量和元素数量不匹配时,可以使用 * 收集剩余元素:
data = [1, 2, 3, 4, 5]
head, *middle, tail = data
print(head) # 1
print(middle) # [2, 3, 4] <- 变成了一个列表
print(tail) # 5变量的命名规范
编写 Python 代码时,遵守 PEP 8(Python 官方编码风格指南)是非常重要的。
命名规则(强制)
- 只能包含字母、数字和下划线 (
_)。 - 不能以数字开头。
- 区分大小写 (
Age和age是两个变量)。 - 不能使用 Python 的关键字(如
if,class,def,return等)。
命名风格(约定俗成)
普通变量/函数名:使用 Snake Case(蛇形命名法),即全小写,单词间用下划线连接。
- ✅
user_name,total_score,is_active - ❌
userName(Java风格),UserName,u_n
- ✅
常量:虽然 Python 没有真正的常量,但约定全大写代表常量。
- ✅
PI,MAX_CONNECTIONS,DEFAULT_COLOR
- ✅
类名:使用 Camel Case(大驼峰命名法)。
- ✅
UserProfile,CarEngine
- ✅
私有变量(惯例):以单下划线开头,表示不希望被外部访问。
_internal_var
代码示例
# 好的命名
student_count = 50
max_score = 100
# 不好的命名
a = 50 # 意义不明
StudentCount = 50 # 像类名,容易混淆 本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据