
当使用 [item] * n 创建列表时,python实际上创建了一个包含 n 个对 item 对象引用的新列表。这意味着所有 n 个元素都指向内存中的同一个对象。对于不可变对象(如整数、字符串、元组),这通常不会引起问题,因为对元素的修改总是创建新对象并重新赋值引用。但对于可变对象(如列表、字典),这种浅层引用机制会导致意外行为。
示例:观察初始引用
假设我们有一个二维数据结构 A,我们希望创建一个与 A 同尺寸的空矩阵 empty_matrix。
# 假设A是一个3x2的矩阵,仅用于确定维度
A = [[0, 0], [0, 0], [0, 0]]
# 创建一个包含两个None的列表作为行模板
empty_row = [None] * len(A[0]) # 结果:[None, None]
# 使用empty_row创建3个重复的行
empty_matrix = [ empty_row ] * len(A) # 结果:[[None, None], [None, None], [None, None]]
print("--- 初始引用ID ---")
for i in range(len(empty_matrix)):
# 打印每行列表对象的ID
print(f"行对象ID: {id(empty_matrix[i])}")
for j in range(len(empty_matrix[0])):
# 打印每行中元素对象的ID
print(f" 元素对象ID: {id(empty_matrix[i][j])}", end = ", ")
print()输出分析:
--- 初始引用ID ---
行对象ID: 2856577670848 # 示例ID,实际值会不同
元素对象ID: 140733388238040, 元素对象ID: 140733388238040,
行对象ID: 2856577670848
元素对象ID: 140733388238040, 元素对象ID: 140733388238040,
行对象ID: 2856577670848
元素对象ID: 140733388238040, 元素对象ID: 140733388238040, 从输出可以看出,empty_matrix 中的所有行(empty_matrix[i])都具有相同的ID,这明确表明它们都指向内存中的同一个列表对象 empty_row。同样,empty_row 中的所有元素(None)也指向同一个 None 对象。
立即学习“Python免费学习笔记(深入)”;
当对列表的某个元素执行赋值操作(例如 list[index] = new_value)时,Python会改变 list[index] 所存储的引用,使其指向 new_value 对象。这并不会修改 index 位置原先指向的对象,而是断开了原有的引用关系,建立了一个新的引用关系。
示例:赋值后的行为
现在,我们尝试为 empty_matrix 的每个元素赋值:
# 假设A的维度与之前相同,例如3x2
# empty_matrix 仍然是 [[None, None], [None, None], [None, None]],所有行和元素共享引用
for i in range(len(A)): # 遍历行
for j in range(len(A[0])): # 遍历列
empty_matrix[i][j] = i*10+j # 赋值操作
print("\n--- 赋值后的矩阵内容 ---")
for r in empty_matrix:
for c in r:
print(c, end = ", ")
print()
print("\n--- 赋值后的引用ID ---")
for i in range(len(empty_matrix)):
print(f"行对象ID: {id(empty_matrix[i])}")
for j in range(len(empty_matrix[0])):
print(f" 元素对象ID: {id(empty_matrix[i][j])}", end = ", ")
print()输出分析:
--- 赋值后的矩阵内容 ---
20, 21,
20, 21,
20, 21,
--- 赋值后的引用ID ---
行对象ID: 1782995372160 # 示例ID,与初始行ID相同
元素对象ID: 1782914902928, 元素对象ID: 1782914902960,
行对象ID: 1782995372160
元素对象ID: 1782914902928, 元素对象ID: 1782914902960,
行对象ID: 1782995372160
元素对象ID: 1782914902928, 元素对象ID: 1782914902960, 为何结果是 20, 21, 20, 21, 20, 21 而不是预期的 0, 1, 10, 11, 20, 21?
要创建具有独立行的嵌套列表(或矩阵),确保每行都是一个独立的列表对象是关键。最常见且推荐的方法是使用列表推导式,它会为每次迭代生成一个新的列表对象。
A = [[0, 0], [0, 0], [0, 0]] # 3x2 矩阵
# 使用列表推导式创建独立的行
# 每次循环都会生成一个新的 [None] * len(A[0]) 列表对象
correct_matrix = [[None] * len(A[0]) for _ in range(len(A))]
print("\n--- 正确创建的矩阵 (初始引用ID) ---")
for i in range(len(correct_matrix)):
print(f"行对象ID: {id(correct_matrix[i])}") # 观察:行ID将不同
for j in range(len(correct_matrix[0])):
print(f" 元素对象ID: {id(correct_matrix[i][j])}", end = ", ")
print()
# 赋值操作
for i in range(len(A)):
for j in range(len(A[0])):
correct_matrix[i][j] = i*10+j
print("\n--- 正确赋值后的矩阵内容 ---")
for r in correct_matrix:
for c in r:
print(c, end = ", ")
print()
print("\n--- 正确赋值后的引用ID ---")
for i in range(len(correct_matrix)):
print(f"行对象ID: {id(correct_matrix[i])}") # 观察:行ID依然不同
for j in range(len(correct_matrix[0])):
print(f" 元素对象ID: {id(correct_matrix[i][j])}", end = ", ")
print()预期输出 (正确行为):
--- 正确创建的矩阵 (初始引用ID) ---
行对象ID: 140733388238040 # 示例ID,与下一行不同
元素对象ID: 140733388238040, 元素对象ID: 140733388238040,
行对象ID: 140733388238120 # 示例以上就是Python列表乘法与引用:深度解析*操作符的行为的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号