0

0

Python列表的引用、可变性与循环引用行为详解

心靈之曲

心靈之曲

发布时间:2025-07-14 23:22:14

|

771人浏览过

|

来源于php中文网

原创

Python列表的引用、可变性与循环引用行为详解

本教程深入探讨Python中列表(list)的引用机制、可变数据类型特性以及由此引发的别名(aliasing)和循环引用行为。通过详细的代码示例,解释了变量如何存储内存地址而非直接值,以及可变与不可变对象在修改时的不同表现。文章特别剖析了列表之间相互引用的复杂场景,揭示了[...]输出背后的原理,旨在帮助读者全面理解Python对象模型,避免潜在的编程陷阱。

python中,理解变量如何存储数据以及数据类型是可变(mutable)还是不可变(immutable)至关重要,尤其是在处理列表等复杂数据结构时。这直接影响到数据修改的行为,并可能导致出乎意料的结果,例如列表的别名(aliasing)和循环引用。

1. Python数据类型:可变与不可变

Python中的每种数据类型都具有可变或不可变的属性。当一个变量被赋值时,它实际上是存储了一个指向内存中某个对象的引用(内存地址)。

  • 不可变数据类型:一旦创建,其值就不能被修改。如果尝试“修改”一个不可变对象,Python会在内存中创建一个新的对象,并让变量指向这个新对象。常见的不可变类型包括:整数(int)、浮点数(float)、字符串(str)、元组(tuple)等。

    我们可以使用内置的 id() 函数来获取对象的唯一标识符(内存地址),以此验证不可变类型的行为。

    # 初始化一个字符串并打印其ID
    some_str = "Hello"
    print("变量值:", some_str)
    print("变量ID:", id(some_str))
    print("-" * 20)
    
    # 修改字符串并再次打印其ID
    some_str += " World" # 实际上是创建了一个新字符串
    print("变量值:", some_str)
    print("变量ID:", id(some_str))
    print("-" * 20)

    运行上述代码,你会发现 some_str 在修改前后的 id 是不同的,这证明了每次“修改”字符串时,实际上是创建了一个新的字符串对象,并将 some_str 变量重新指向了这个新对象。

    立即学习Python免费学习笔记(深入)”;

  • 可变数据类型:创建后,其值可以在不改变内存地址的情况下被修改。这意味着对可变对象的修改会直接作用于内存中的原始对象。常见的可变类型包括:列表(list)、字典(dict)、集合(set)等。

    让我们用列表来验证可变类型的行为:

    智川X-Agent
    智川X-Agent

    中科闻歌推出的一站式AI智能体开发平台

    下载
    # 初始化一个列表并打印其ID
    some_list = ["Hello"]
    print("变量值:", some_list)
    print("变量ID:", id(some_list))
    print("-" * 20)
    
    # 修改列表并再次打印其ID
    some_list.append("World") # 直接在原内存地址上修改
    print("变量值:", some_list)
    print("变量ID:", id(some_list))
    print("-" * 20)

    输出显示,尽管 some_list 的内容发生了变化,但其 id 保持不变。这表明列表是在原地修改的,没有创建新的对象。

2. 变量赋值与引用机制

在Python中,当我们将一个变量赋值给另一个变量,或者将一个变量添加到列表中时,通常传递的是对象的引用,而不是值的副本。

考虑以下场景:

# 初始化一个字符串和列表
some_str = "Hello"
some_list_1 = ["Hello"]

print("some_str 的ID:", id(some_str))
print("some_list_1 的ID:", id(some_list_1))
print("-" * 20)

# 创建一个空列表并将上述变量添加到其中
some_list_2 = []
some_list_2.append(some_str)
some_list_2.append(some_list_1)

print("some_list_2 的第一个元素:", some_list_2[0])
print("some_list_2[0] 的ID:", id(some_list_2[0]))
print("some_list_2[0] 是否与 some_str 引用同一对象?:", id(some_list_2[0]) == id(some_str))
print("*" * 20)

print("some_list_2 的第二个元素:", some_list_2[1])
print("some_list_2[1] 的ID:", id(some_list_2[1]))
print("some_list_2[1] 是否与 some_list_1 引用同一对象?:", id(some_list_2[1]) == id(some_list_1))
print("*" * 20)

# 现在修改 some_str 和 some_list_1,并再次检查 some_list_2 的元素
some_str += " World" # some_str 指向新对象
some_list_1.append("World") # some_list_1 在原地址修改

print("some_str 现在ID:", id(some_str))
print("some_list_1 现在ID:", id(some_list_1))
print("-" * 20)

print("some_list_2 的第一个元素 (修改后):", some_list_2[0])
print("some_list_2[0] 的ID (修改后):", id(some_list_2[0]))
print("some_list_2[0] 是否与 some_str 引用同一对象 (修改后)?:", id(some_list_2[0]) == id(some_str)) # 应为False
print("*" * 20)

print("some_list_2 的第二个元素 (修改后):", some_list_2[1])
print("some_list_2[1] 的ID (修改后):", id(some_list_2[1]))
print("some_list_2[1] 是否与 some_list_1 引用同一对象 (修改后)?:", id(some_list_2[1]) == id(some_list_1)) # 应为True
print("*" * 20)

从输出中可以看出:

  • 当 some_str 被“修改”时,some_str 指向了一个新的内存地址,但 some_list_2[0] 仍然指向最初的 "Hello" 字符串对象。这是因为字符串是不可变的,+= 操作实际上创建了一个新字符串。
  • 当 some_list_1 被 append 方法修改时,some_list_1 的内存地址保持不变,因此 some_list_2[1] 依然指向同一个列表对象。所以,some_list_2[1] 的内容也随之改变。

这个实验清晰地展示了Python变量存储的是引用,以及可变和不可变对象在引用行为上的关键差异。

3. 列表的别名与循环引用

理解了上述概念,我们就能解释列表之间相互引用(即循环引用)的“递归”行为。

考虑以下代码片段:

a = [1, 2, 3]
b = [4, 5]

# 将b添加到a中
a.append(b)
print("a:", a) # a: [1, 2, 3, [4, 5]]
print("a[3] 的ID:", id(a[3]))
print("b 的ID:", id(b))
print("a[3] is b:", a[3] is b) # True,a[3]和b指向同一个列表对象

# 此时,a[3]是b的别名。修改a[3]会影响b。
print("a[3][1]:", a[3][1]) # 访问 b[1],结果是 5

# 将a添加到b中
b.append(a)
print("b:", b) # b: [4, 5, [1, 2, 3, [...]]]
print("b[2] 的ID:", id(b[2]))
print("a 的ID:", id(a))
print("b[2] is a:", b[2] is a) # True,b[

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

337

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

224

2025.10.31

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

138

2026.02.12

css中float用法
css中float用法

css中float属性允许元素脱离文档流并沿其父元素边缘排列,用于创建并排列、对齐文本图像、浮动菜单边栏和重叠元素。想了解更多float的相关内容,可以阅读本专题下面的文章。

595

2024.04.28

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

106

2025.10.23

mysql标识符无效错误怎么解决
mysql标识符无效错误怎么解决

mysql标识符无效错误的解决办法:1、检查标识符是否被其他表或数据库使用;2、检查标识符是否包含特殊字符;3、使用引号包裹标识符;4、使用反引号包裹标识符;5、检查MySQL的配置文件等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

210

2023.12.04

Python标识符有哪些
Python标识符有哪些

Python标识符有变量标识符、函数标识符、类标识符、模块标识符、下划线开头的标识符、双下划线开头、双下划线结尾的标识符、整型标识符、浮点型标识符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

322

2024.02.23

java标识符合集
java标识符合集

本专题整合了java标识符相关内容,想了解更多详细内容,请阅读下面的文章。

292

2025.06.11

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 4.9万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号