Python的变量本质
Python中几种最常用的基本类型:
age = 25 # int,整数
price = 9.9 # float,浮点数
name = "Alice" # str,字符串
is_ok = True # bool,布尔值
result = None # NoneType,表示"空"或"未赋值"
Python 是动态类型语言,变量本身没有类型,类型是对象的属性。即,动态类型意味着变量本身没有类型,类型是附着在值上的。同一个变量可以先指向整数,再指向字符串,Python 不会报错:
# 动态类型的体现:同一变量可指向不同类型
x = 10 # x 是 int
x = "now str" # x 现在指向 str 对象,原 int 被回收
这与 Java、C++ 不同。Python 的变量更像是一个"标签",贴在对象上,而不是一个固定类型的盒子。
可变对象 vs 不可变对象
Python 的对象分两类:
- 不可变(immutable) :
int、float、str、tuple、bool - 可变(mutable) :
list、dict、set
"可变"的意思是:对象创建后,内容可以被修改,且内存地址不变:
a = [1, 2, 3]
# 使用id()函数返回对象的唯一标识符(内存地址)
print(id(a))
# 假设是 140234567
a.append(4)
print(id(a))
# 还是 140234567,地址没变,但内容变了
而不可变对象一旦"修改",实际上是创建了一个新对象:
s = "hello"
print(id(s)) # 假设是 205290313838
s = s + " world"
print(id(s)) # 变成了 205290245440,s现在指向一个全新的字符串对象
函数参数的 引用传递
Python 传参传的是"对象的引用"。如果你传进去的是可变对象,函数内部对它的修改会直接反映到外部。例如:
def add_default_field(records):
for record in records:
record["verified"] = False # 直接修改了 dict
return records
raw_data = [{"name": "Alice"}, {"name": "Bob"}]
processed = add_default_field(raw_data)
print(raw_data)
# [{'name': 'Alice', 'verified': False}, {'name': 'Bob', 'verified': False}]
注意:raw_data 被修改了。你没有在函数里写任何"修改原始数据"的意图,但它就是发生了。如果后续代码还依赖 raw_data 保持原样,就会出现难以追踪的数据污染问题。
浅拷贝 VS 深拷贝
Python 提供两种拷贝方式:
- 浅拷贝-
copy.copy():复制外层容器,但内部的对象仍然共享引用,修改内层对象会影响原对象。
import copy
original = [[1, 2], [3, 4]]
shallow = copy.copy(original)
shallow[0].append(99)
print(original) # [[1, 2, 99], [3, 4]],内层列表还是同一个
- 深拷贝-
copy.deepcopy():递归复制所有层级的对象,完全独立,修改任何层都不会影响原对象。
deep = copy.deepcopy(original)
deep[0].append(99)
print(original) # [[1, 2], [3, 4]],不受影响
总结
| 可变对象 | 不可变对象 | |
|---|---|---|
| 代表类型 | list、dict、set | str、tuple、int |
| 修改行为 | 原地修改,地址不变 | 产生新对象 |
| 函数传参风险 | 内部修改影响外部 | 无此问题 |