变量与对象
在 Python 中,变量并非存储数据的容器,而是指向对象的名字。理解这一区别是掌握 Python 数据模型的关键。
变量是名字,对象是实体
执行 a = 3 时,Python 先创建整数对象 3,再将变量 a 绑定到这个对象上。变量本身不携带类型信息,类型属于对象:
a = 3
print(type(a)) # <class 'int'>
a = "hello"
print(type(a)) # <class 'str'>
这里 a 先指向整数对象,后指向字符串对象。变量可以随时重新绑定到不同类型的对象,这是 Python 动态类型的核心特征。
如果访问未绑定的变量,解释器会抛出 NameError:
print(undefined_var)
# NameError: name 'undefined_var' is not defined
对象的三要素
Python 中的一切都是对象,每个对象都有三个基本属性:
身份(identity):对象的唯一标识,生命周期内永不改变。用 id() 查看,通常对应内存地址:
x = 1000
print(id(x)) # 如 140234567890304
类型(type):决定对象支持的操作。用 type() 查看:
print(type(42)) # <class 'int'>
print(type(3.14)) # <class 'float'>
print(type(None)) # <class 'NoneType'>
值(value):对象承载的数据。对于不可变对象,创建后值不可改变;可变对象的值可以修改:
# 不可变对象:修改会创建新对象
s = "abc"
print(id(s)) # 140234567890432
s = s + "d"
print(id(s)) # 140234567890560,新对象
# 可变对象:原地修改,id 不变
lst = [1, 2, 3]
print(id(lst)) # 140234567890688
lst.append(4)
print(id(lst)) # 140234567890688,同一对象
多重引用与别名
多个变量可以绑定到同一个对象,这种现象称为别名(aliasing):
a = [1, 2, 3]
b = a # b 与 a 指向同一列表
print(id(a) == id(b)) # True
b[0] = 99
print(a) # [99, 2, 3] —— 通过 b 修改,a 也可见
对于不可变对象,别名不会产生副作用,因为任何"修改"都会创建新对象:
x = 10
y = x
y = y + 1
print(x) # 10,不受影响
print(y) # 11
判断两个变量是否指向同一对象,应使用 is 运算符(比较 id),而非 ==(比较值):
a = [1, 2]
b = [1, 2]
print(a == b) # True,值相等
print(a is b) # False,不是同一对象
c = a
print(a is c) # True
动态类型与强类型
Python 是动态类型语言:变量类型在运行时确定,且可以随时改变。但它同时也是强类型语言:不同类型之间不会隐式转换,必须显式转换:
# 动态类型:变量可重新绑定到不同类型
value = 100
value = "text"
# 强类型:不会自动混用
print(3 + "5") # TypeError: unsupported operand type(s)
print(3 + int("5")) # 8,必须显式转换
垃圾回收
当一个对象不再被任何变量引用时,Python 的垃圾回收器会自动回收其内存。对于简单的引用计数,当引用数降为零时立即回收:
import sys
a = "a" * 10000
print(sys.getrefcount(a)) # 至少为 2(a 和 getrefcount 参数)
b = a
print(sys.getrefcount(a)) # 3
del b
print(sys.getrefcount(a)) # 2
del a
# 此时原字符串对象引用计数归零,被回收
循环引用需要更复杂的垃圾回收机制处理,但日常编程中很少需要手动干预。
交互模式中的特殊变量 _
在交互式解释器中,最近一次表达式的结果自动存入变量 _:
>>> 17 / 3
5.666666666666667
>>> _ * 3
17.0
注意:显式给 _ 赋值会覆盖这个特殊行为,创建普通局部变量。
可变与不可变对象
Python 对象按值是否可修改分为两类:
| 不可变对象 | 可变对象 |
|---|---|
| int, float, bool, str, tuple, frozenset | list, dict, set |
不可变对象一旦创建,其值和 id 的关联就固定了。小整数(通常 -5 到 256)会被缓存复用:
a = 100
b = 100
print(a is b) # True,小整数缓存
x = 1000
y = 1000
print(x is y) # False(交互模式下可能为 True,取决于实现)
字符串也有类似的驻留(interning)优化,但仅适用于标识符样式的字符串:
a = "hello"
b = "hello"
print(a is b) # True
x = "hello world!"
y = "hello world!"
print(x is y) # False,含空格和标点,不驻留
理解变量与对象的关系,是避免 Python 中大多数数据相关 bug 的基础。记住核心原则:变量是标签,对象是实体;赋值是贴标签,不是复制数据。