Python 值类型和引用类型:你真的懂了吗?

简介: 在 Python 中,变量赋值时为何有时影响其他变量?这与值类型和引用类型密切相关。值类型(如 int、str)复制时传递的是实际值,而引用类型(如 list、dict)传递的是内存地址。理解这一区别,有助于避免常见陷阱,如误改共享数据、默认参数陷阱等。本文通过内存图解和实例对比,深入解析赋值行为、函数参数传递机制,并提供避坑技巧,助你彻底掌握这一核心概念。

在 Python 里,我们经常会遇到这样的疑惑:“为啥我改了一个变量,另一个也变了?”、“= 号到底是复制了值,还是复制了地址?”……这些问题,其实都和“值类型”和“引用类型”有关。今天我们就来搞清楚这个让很多人犯迷糊的知识点。

参考文章:Python 值类型和引用类型 | 简单一点学习


大纲目录

  1. 什么是值类型和引用类型?
  2. Python 中的值类型有哪些?
  3. Python 中的引用类型有哪些?
  4. 内存图解:变量赋值到底发生了什么?
  5. 值类型和引用类型的行为对比
  6. 函数参数传递:值传递还是引用传递?
  7. 常见的坑和误解
  8. 怎么避免这些坑?
  9. 总结归纳

1. 什么是值类型和引用类型?

  • 值类型(Value Type):变量保存的是值本身
  • 引用类型(Reference Type):变量保存的是值的地址(引用),多个变量可能引用同一个值。

说白了,就是你到底是直接拿着东西,还是只是拿着指向它的门牌号。


2. Python 中的值类型有哪些?

虽然 Python 万物皆对象,但我们通常把以下几种类型当作“值类型”来看待:

  • int(整数)
  • float(浮点数)
  • bool(布尔值)
  • str(字符串)*(注意它是不可变类型)
  • tuple(元组)*(不可变,也常被当作值类型)

这些类型的一个共同点是:不可变。一旦你对它们进行修改,Python 会创建一个新的对象。

示例:

a = 10
b = a
a = 20
print(b)  # 输出 10,b 不受 a 影响

3. Python 中的引用类型有哪些?

通常来说,只要是可变类型,基本就是引用类型:

  • list(列表)
  • dict(字典)
  • set(集合)
  • 自定义的对象(class 实例)

示例:

a = [1, 2, 3]
b = a
a.append(4)
print(b)  # 输出 [1, 2, 3, 4],b 跟着变了

4. 内存图解:变量赋值到底发生了什么?

来看个直观示意(伪图):

a = [1, 2]
b = a

图示理解:

a ───▶  [1, 2]
b ───┘

修改 a.append(3) 后:

a ───▶  [1, 2, 3]
b ───┘

说明 ab 指向的是同一个列表对象。


5. 值类型和引用类型的行为对比

操作行为 值类型(如 int) 引用类型(如 list)
变量赋值 复制值 复制引用(地址)
修改变量 不影响其他 可能影响其他变量
作为函数参数传入 拷贝一份 传递引用

6. 函数参数传递:值传递还是引用传递?

Python 里一切都是对象,参数传递本质上是对象引用的传递

来看两个例子:

值类型:

def foo(x):
    x = 100

a = 10
foo(a)
print(a)  # 10,a 不受影响

引用类型:

def foo(lst):
    lst.append(100)

a = [1, 2]
foo(a)
print(a)  # [1, 2, 100],a 被修改了

7. 常见的坑和误解

坑 1:复制引用当作复制值

a = [1, 2, 3]
b = a
b[0] = 999
print(a)  # [999, 2, 3],a 也变了

解决方法:使用 copy() 或 deepcopy()

import copy
b = copy.deepcopy(a)

坑 2:默认参数是引用类型

def foo(lst=[]):
    lst.append(1)
    return lst

print(foo())  # [1]
print(foo())  # [1, 1],坑在这!

改法:

def foo(lst=None):
    if lst is None:
        lst = []
    lst.append(1)
    return lst

8. 怎么避免这些坑?

  • 对可变对象做修改前,想清楚是否要复制一份
  • 默认参数不要用 list/dict 这类引用类型
  • 理解 = 是赋值引用,不是复制内容
  • copydeepcopy 区分浅拷贝和深拷贝

9. 总结归纳

  • 值类型 : 不可变、值复制
  • 引用类型 : 可变、地址共享
目录
相关文章
uniapp上拉加载更多
uniapp上拉加载更多
325 0
|
机器学习/深度学习 编解码 搜索推荐
【卷积集】近万字长文总结了日常使用的“卷积”特征,内附代码实现送给准备面试的你
【卷积集】近万字长文总结了日常使用的“卷积”特征,内附代码实现送给准备面试的你
293 0
|
存储 人工智能 算法
聚类的k值确定之轮廓系数
聚类的k值确定之轮廓系数
2617 0
|
Python
Python软件包及环境管理器conda实战篇
详细介绍了如何使用conda进行Python软件包管理及环境管理,包括查看、安装、卸载软件包,切换源,管理不同版本的Python环境,以及解决使用过程中可能遇到的错误。
479 2
Python软件包及环境管理器conda实战篇
|
自然语言处理 安全 Java
Java 语法糖是什么?
语法糖是一种编程语言的设计概念,旨在通过更简洁、易读的方式表示某些操作,提升代码可读性和减少错误。它不增加语言功能,而是简化代码。Java中的语法糖包括自动装箱与拆箱、增强型for循环、泛型、可变参数、try-with-resources、Lambda表达式、方法引用、字符串连接、Switch表达式和类型推断等,这些特性使Java代码更为简洁易读。
391 23
CMake的拷贝文件到指定目录——CMake三板斧
CMake的拷贝文件到指定目录——CMake三板斧
1905 0
|
Java 关系型数据库 MySQL
DataX教程(10)- DataX插件热插拔原理
DataX教程(10)- DataX插件热插拔原理
1104 0
Mac处理系统快捷键与应用快捷键的冲突
Mac处理系统快捷键与应用快捷键的冲突
1374 0
|
前端开发 JavaScript UED
前端 js 经典:async 和 await
前端 js 经典:async 和 await
375 2

热门文章

最新文章