当前位置:首页>python>Python中可变对象和不可变对象有哪些?区别是什么?

Python中可变对象和不可变对象有哪些?区别是什么?

  • 2026-09-02 20:19:09
Python中可变对象和不可变对象有哪些?区别是什么?

一、开场白

在Python的世界里,数据就像有不同性格的“精灵”:有的一旦诞生就坚守本心,无论如何尝试修改,核心都纹丝不动;有的却灵活多变,能在原地不断调整形态,甚至换了模样还保持着最初的“身份”。这种看似不起眼的差异,却直接决定了代码运行的逻辑、内存的使用方式,甚至是新手最容易踩的坑——比如明明修改了变量,结果却和预期完全相反。理解这些“精灵”的性格,也就是可变对象与不可变对象,是真正读懂Python运行机制的关键,也是从“会写代码”到“写好代码”的必经之路。

二、可变对象与不可变对象:概念与例子

核心概念

  • 不可变对象:创建后内存中的值无法被修改的对象。当你试图“修改”它时,Python不会改变原对象,而是会在内存中新建一个对象,原变量会指向这个新对象。
  • 可变对象:创建后内存中的值可以直接修改的对象。修改操作会直接作用于原对象,不会新建对象,变量始终指向同一个内存地址。

具体例子

  1. 不可变对象示例

    • 整数(int):定义a = 10,执行a += 5后,a的值变成15,但本质是Python新建了值为15的整数对象,a从指向10的内存地址改为指向15,原10的对象并未被修改。
    • 字符串(str):定义s = "hello",执行s += " world",看似修改了字符串,实则新建了"hello world"对象,原"hello"对象仍存在且未变化。
    • 元组(tuple):定义t = (1, 2, 3),尝试t[0] = 10会直接报错,因为元组的元素无法被修改;即便元组内包含可变对象(如t = (1, [2, 3])),也只能修改内部可变对象的内容,元组本身的结构(元素的个数、指向)无法变。
  2. 可变对象示例

    • 列表(list):定义lst = [1, 2, 3],执行lst.append(4),列表直接在原内存地址新增元素,变为[1, 2, 3, 4],lst的内存地址始终未变。
    • 字典(dict):定义d = {"name": "小明"},执行d["age"] = 18,字典在原地址新增键值对,无新对象创建。
    • 集合(set):定义s = {1, 2, 3},执行s.add(4),集合直接在原地址添加元素,内存地址保持不变。

三、引人入胜的相关问题与解答

问题1:为什么给整数变量赋值后,内存地址变了,但给列表添加元素,内存地址却不变?

解答过程:

  • 第一步:明确对象类型属性。整数是不可变对象,列表是可变对象,这是核心属性差异。
  • 第二步:分析内存机制。不可变对象的内存空间一旦分配,值就被固定,无法修改;当执行赋值/运算操作时,只能新建对象并让变量指向新地址。而可变对象的内存空间设计为“可扩展/可修改”,修改操作(如append、add)直接操作原内存空间,无需新建对象,因此地址不变。
  • 第三步:验证(代码示例):
    # 验证整数(不可变)a = 10print(id(a))  # 输出:如140708467224432a += 5print(id(a))  # 输出:如140708467224592(地址变化)# 验证列表(可变)lst = [1, 2, 3]print(id(lst))  # 输出:如2282150767104lst.append(4)print(id(lst))  # 输出:2282150767104(地址不变)

问题2:为什么元组里能放列表,却不能直接修改元组的元素?

解答过程:

  • 第一步:拆解元组的“不可变”本质。元组的不可变是指“元素的指向不可变”,即元组中每个位置保存的是元素的内存地址,这个地址不能改;但如果地址指向的是可变对象(如列表),则可变对象本身的内容可以改。
  • 第二步:举例验证:
    t = (1, [2, 3])t[1].append(4)  # 可行,修改的是列表(可变对象)的内容print(t)  # 输出:(1, [2, 3, 4])t[0] = 10# 报错,试图修改元组元素的指向(不可变)
  • 第三步:总结:元组的“不可变”是“结构不可变”,而非内部元素的“内容不可变”,这是新手极易混淆的点。

问题3:函数传参时,可变对象和不可变对象的表现为什么不一样?

解答过程:

  • 第一步:明确传参规则。Python函数传参是“按引用传递”,但引用的表现因对象类型而异。
  • 第二步:分析差异:
    • 不可变对象传参:函数内修改参数,实际是新建对象,不影响外部变量(因为外部变量仍指向原地址)。
    • 可变对象传参:函数内修改参数,会直接改变原对象,外部变量也会同步变化(因为指向同一地址)。
  • 第三步:验证(代码示例):
    # 不可变对象(整数)传参defchange_num(x):    x += 5return xnum = 10change_num(num)print(num)  # 输出:10(外部变量未变)# 可变对象(列表)传参defchange_list(l):    l.append(4)return llst = [1, 2, 3]change_list(lst)print(lst)  # 输出:[1, 2, 3, 4](外部变量已变)

四、全文汇总总结

核心知识点

  1. 分类:
    • 不可变对象:int(整数)、str(字符串)、tuple(元组)、float(浮点数)、bool(布尔值)等;
    • 可变对象:list(列表)、dict(字典)、set(集合)等。
  2. 核心区别:
    • 不可变对象:创建后值不可修改,修改操作会新建对象,变量指向新地址;
    • 可变对象:创建后值可直接修改,修改操作作用于原对象,变量地址不变。
  3. 关键联系:
    • 两者都是Python的基础数据对象,遵循“变量指向内存地址”的核心逻辑;
    • 不可变对象的“不可变”是“值不可变”,可变对象的“可变”是“值可在原地址修改”;
    • 元组是特殊的不可变对象:其元素指向不可变,但内部可变对象的内容可改。

易混淆点梳理

  • 不要把“变量赋值”和“对象修改”混淆:对不可变对象的“赋值”是新建对象,对可变对象的“修改操作(如append)”才是真正的原地修改;
  • 函数传参的差异本质是对象是否可变:修改不可变参数不影响外部,修改可变参数会影响外部,如需避免可变参数被修改,可在函数内创建副本(如l = lst.copy())。 

最新文章

随机文章