一文读懂 Python 值传递和引用传递

文章目录

  • 版本
  • 前言
  • 形参和实参
  • 值传递和引用传递
  • Python 变量存储
    • 值语义和引用语义
      • 值语义
      • 引用语义
  • 探讨 Python 值传递和引用传递
    • 不可变(immutable)类型
    • 可变(mutable)类型
      • 案例一
      • 案例二
  • 拓展:不可变类型真的不可变?
  • 总结
  • 个人简介

版本

  • Python 3.9

前言

  • 在编程语言中,值传递(pass by value)和引用传递(pass by reference)是两个重要的概念。它们涉及到变量在函数调用中的传递方式,对于理解函数调用和参数传递的机制至关重要。在本文中,我们将深入探讨 Python 中的值传递和引用传递,并通过代码示例进行说明。

形参和实参

  • 我们先了解一点前置知识,形参和实参,先说概念:形参出现在函数定义中,在整个函数体内都可使用,离开函数体则不可使用。实参出现在主调函数中,进入被调函数后,不能使用。
def func(param):# 这里 param 为形参print(param)if __name__ == "__main__":# 这里的 a 就是实参a = 1func(a)

值传递和引用传递

  • 我们先了解一下值传递和引用传递的概念:值传递是指在调用方式时,将实参的值拷贝一份给形参,对形参的修改不影响实参。引用传递也叫地址传递,指在调用方法时将实参的地址传递给形参,对形参的修改将影响实参的值,即传递的是实参的内存地址。

Python 变量存储

  • 对于python而言,python的一切变量都是对象,变量的存储采用了引用语义的方式,存储的只是一个变量的值所在的内存地址,而不是这个变量的只本身。

Python 变量存储

  • 代码实测:
a = 1
print(f"变量a的地址:{id(a)}")b = 1
print(f"变量b的地址:{id(b)}")b = 2
print(f"变量b的地址:{id(b)}")
  • 上面实例输出如下:
变量a的地址:2483649669424
变量b的地址:2483649669424
变量b的地址:2483649669456
  • 从实际用例我们可以看出,a、b = 1 时,这里底层为了性能考虑指向相同的内存,当 b 发生改变时,发生写时复制,b 指向了新的内存地址。

值语义和引用语义

值语义

  • 值语义是指将变量赋值为另一个变量时,会复制变量的值,而不是引用原始值所在的内存地址。如 Java 的基本数据类型。

引用语义

  • 引用语义是指将变量赋值为另一个变量时,实际上是将变量指向同一个对象的内存地址,而不是复制对象的值。如 Java 的引用数据类型、Python 值存储。

探讨 Python 值传递和引用传递

  • 了解完上面的一些基本概念后,我们从可变(mutable)和不可变(immutable)两种类型来探讨 Python 值传递和引用传递:

不可变(immutable)类型

  • 不可变变量的值一旦创建,就不能被修改。如果你尝试修改一个不可变对象的值,Python 将会创建一个新的对象。Python 中的不可变对象包括整数(int)、浮点数(float)、字符串(str)、元组(tuple)等。
  • 先简单看一个下面的例子:
def modify_value(x):print(f"变量x修改前地址:{id(x)}")x = x + 10print(f"变量x修改后地址:{id(x)}")print("函数内部修改后的值为:", x)# 调用函数
value = 5
print(f"变量value地址:{id(value)}")
modify_value(value)
print("函数外部原始值为:", value)
  • 在这个示例中,我们定义了一个函数 modify_value,它接受一个参数 x。在函数内部,我们对 x 的值进行修改,并打印出修改后的值。然后我们调用函数,传递了一个值为 5 的参数 value。运行以上代码,将会输出:
变量value地址:1886976960944
变量x修改前地址:1886976960944
变量x修改后地址:1886976961264
函数内部修改后的值为: 15
函数外部原始值为: 5
  • 可以看到,尽管在函数内部修改了形式参数 x 的值,但并没有影响到函数外部实际参数 value 的值,而发生了写时复制。

可变(mutable)类型

  • 可变变量的值可以在原地修改,而不会创建一个新的对象。Python 中的可变对象包括列表(list)、字典(dict)、集合(set)等。
  • 我们以 list 类型为例:

案例一

def modify_list(list):print(f"变量list地址:{id(list)}")list[2] = 4print(f"变量list修改地址:{id(list)}")print("函数内部修改后的列表为:", list)# 调用函数
my_list = [1, 2, 3]
print(f"变量my_list地址:{id(my_list)}")
modify_list(my_list)
print("函数外部原始列表为:", my_list)
  • 输出如下:
变量my_list地址:2115249727936
变量list地址:2115249727936
变量list修改地址:2115249727936
函数内部修改后的列表为: [1, 2, 4]
函数外部原始列表为: [1, 2, 4]

案例二

def modify_list(list):print(f"变量list地址:{id(list)}")list = [6, 6, 6]print(f"变量list修改地址:{id(list)}")print("函数内部修改后的列表为:", list)# 调用函数
my_list = [1, 2, 3]
print(f"变量my_list地址:{id(my_list)}")
modify_list(my_list)
print("函数外部原始列表为:", my_list)
  • 输出如下:
变量my_list地址:2141908331136
变量list地址:2141908331136
变量list修改地址:2141908181248
函数内部修改后的列表为: [6, 6, 6]
函数外部原始列表为: [1, 2, 3]
  • 看完上面的两个案例你是否有些许疑惑,案例一修改了函数外的原始值,案例二未修改函数外的原始值,下面我们用图解来解释一下上面发生了什么:

案例一
在这里插入图片描述

  • 从图解中我们可以清晰的看到,在案例一和案例二中函数传递了 my_list 地址的拷贝值,案例一中持有数组的内存地址,因此成功修改了原数组元素,案例二中 list 的内存地址修改为新的数组内存地址,并没有修改原数组的值。
  • 通过对可变(mutable)和不可变(immutable)两种类型的函数传递的分析,我们可以知道由于 Python 中一切皆对象的特性,实际传递给函数的都是内存地址的拷贝,从表现上来说,我们可以说 Python 中都是值传递,了解过 Java 的同学会发现这里和 Java 的引用类型原理一致。

拓展:不可变类型真的不可变?

  • 上面我们提到了可变类型和不可变类型,不可变类型真的是不可变的?我们来看下面的案例:
arr = (1, 2, [4, 4])print(f"元组修改前:{arr}")
arr[2][0] = 2
print(f"元组修改后:{arr}")
  • 输出结果:
元组修改前:(1, 2, [4, 4])
元组修改后:(1, 2, [2, 4])
  • 上面的案例中不可变类型出现了变化,这个是 bug ? 其实并不是,不可变类型的不可变指的是组成的元素是不可变的,在上面的案例 arr 元组中存储的是对应的内存地址,而不可变指的是内存地址和指向无法改变,但如果内存地址指向的是可变类型,比如数组,那么元素内部是可变的。

总结

  • 本文以值传递、引用传递的基本概念、以及 Python 变量存储为基础,从可变(mutable)和不可变(immutable)两种类型来分析 Python 值传递和引用传递的真相,通过充足的案例分析我们发现,Python变量 和 Java 引用类型类似,只存在值传递。

个人简介

👋 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.

🚀 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。

🧠 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。

💡 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。

🌐 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。此外,我将分享最新的互联网和技术资讯,以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。

📖 保持关注我的博客,让我们共同追求技术卓越。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/705237.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探索 Sora 背后的核心技术

2024年2月16日,OpenAI发布Sora文生视频模型,一石激起千层浪,迅速刷屏爆火于整个AI圈。一方面,Sora从文本、图像迈向视频大模型,这可以说是通向通用人工智能的里程碑事件;另一方面,训练和推理需求…

设计模式(三)建造者模式

相关文章设计模式系列 1.建造者模式简介 定义 建造者模式(builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 简介 建造者模式(builder)是创建一个复杂对象的创建型…

2024图像处理分析与信息工程国际学术会议(IACIPIE2024)

2024图像处理分析与信息工程国际学术会议(IACIPIE2024) 会议简介 2024图像处理分析与信息工程国际学术会议(IACIPIE2024)将在中国长沙举行。 IACIPIE2024是一个年度会议,探讨图像处理分析和信息工程相关领域的发展和影响,旨在介…

状态机-----

1.原理 同步的意思就是状态的跳转都是在时钟的作用下跳转的,有限是指状态机中状态的个数是有限的。两种状态机的共同点都是状态的跳转只和输入有关,区别就是如果最后的输出只和当前状态有关而与输入无关,则是moore型状态机。如果最后的输出不…

STM32学习3 寄存器映射和GPIO寄存器编程

STM32学习3 寄存器映射和GPIO寄存器编程 一、STM32外设内存空间1. 内存空间划分2. 区域功能说明(1)block0(2)block1(3)block2(4)block3~4(5)block5&#xff0…

猫咪挑食不吃猫粮怎么办?适口性高、可以改善猫咪挑食的主食冻干分享

猫咪挑食不吃猫粮怎么办?在现今社会,养猫的人越来越多,大家都把自家的小猫当作宝贝来宠爱。但宠爱过度有时也会导致猫咪养成挑食的坏习惯。面对这一问题,我们应该如何解决呢?今天,我要分享一个既能确保猫咪…

Adobe Illustrator 2022 for Mac/Win:设计的新篇章

在数字艺术和设计领域,Adobe Illustrator一直以其强大的功能和高效的工具受到专业人士的青睐。随着2022年的到来,Adobe Illustrator 2022(简称AI 2022)的发布无疑为设计师们带来了新的希望和期待。 一、强大的新功能 AI 2022引入…

什么是小红书品牌笔记,如何做好达人投放?

认认真真撰写了小红书品牌笔记,从各个方面确保了笔记的优质程度,却没能产生爆文。这很可能是笔记与用户之间的中间环节出了问题,也就是达人投放有问题。今天我们就为大家带来什么是小红书品牌笔记,如何做好达人投放? 一…

【c语言】if 选择语句

🎈个人主页:豌豆射手^ 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:C语言 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步&…

Navicat的使用

1. Navicat介绍 Navicat: 是一款流行的数据库管理和开发工具, 它支持多种数据库系统, 如: MySQL, MariaDB, MongoDB, SQL Server, Oracle, PostgreSQL 等. Navicat通过提供直观的图形用户界面(GUI), 使用户能够更轻松地执行各种数据库操作, 而无需记住复杂的SQL命令.以下是Nav…

PyQt5图片浏览器

PyQt5图片浏览器 实现方式功能实现具体代码 界面实现pillow源码修改ImageQt错误主页面布局 项目开源地址 分享一个图片浏览器 实现方式 qt本身有一个QGraphicsView类用来当做视图框架。 具体参考:如何在pyqt中使用 QGraphicsView 实现图片查看器 不过大佬给的例子…

聚集高速托盘类四向穿梭车ASRV|一车跑全仓可获得10000个货位的HEGERLS智能搬运机器人

随着国内外制造业加速转型升级,越来越多的企业需要进行物流智能化升级,但是往往受到仓库面积、高度、形状等现实条件的限制,以及市场不确定性因素的影响。因此,相对于投资传统的自动化立体库,企业更倾向于选择智能化、…

机器学习-01-课程目标与职位分析

总结 本系列是机器学习课程的第01篇,主要介绍本门课程的课程目标与职位分析 教材 数据挖掘与机器学习 课程教学方法 布鲁姆教学法 认知领域(cognitive domain) 1.知道(知识)(knowledge) 是指…

细嗦MySQL三大日志

文章目录 三大日志:binlog(归档日志)、redo log(重做日志)、undo log(回滚日志)redo log刷盘机制日志文件组 binlog记录格式写入机制 两阶段提交undo log提供回滚操作提供MVCC(多版本…

科技云报道:黑马Groq单挑英伟达,AI芯片要变天?

科技云报道原创。 近一周来,大模型领域重磅产品接连推出:OpenAI发布“文字生视频”大模型Sora;Meta发布视频预测大模型 V-JEPA;谷歌发布大模型 Gemini 1.5 Pro,更毫无预兆地发布了开源模型Gemma… 难怪网友们感叹&am…

【Excel PDF 系列】POI + iText 库实现 Excel 转换 PDF

你知道的越多,你不知道的越多 点赞再看,养成习惯 如果您有疑问或者见解,欢迎指教: 企鹅:869192208 文章目录 前言转换前后效果引入 pom 配置代码实现 前言 最近遇到生成 Excel 并转 pdf 的需求,磕磕碰碰总…

stm32——hal库学习笔记(DMA实验)

一、DMA介绍(了解) 二、DMA结构框图介绍(熟悉) 三、DMA相关寄存器介绍(熟悉) 四、DMA相关HAL库驱动介绍(掌握) 五、DMA配置步骤(掌握) 六、编程实战&#xff…

Anaconda和TensorFlow环境搭建!!

Anaconda下载 进入官网下载 https://www.anaconda.com/download 也可以通过清华的映像站下载: https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 我这里下载的是3.4.20版本。下载好就可以安装默认安装就行。 打开Anaconda Prompt修改成国内镜像 conda c…

大概了解一下G1收集器

在上一篇文章中(链接:大概了解一下CMS收集器)我们提到,CMS是一种主要针对旧生代对象进行回收的收集器。与CMS不同,G1号称“全功能的垃圾收集器”,对初生代内存和旧生代内存均进行管理。鉴于此,这…

pyspark分布式部署随机森林算法

前言 分布式算法的文章我早就想写了,但是一直比较忙,没有写,最近一个项目又用到了,就记录一下运用Spark部署机器学习分类算法-随机森林的记录过程,写了一个demo。 基于pyspark的随机森林算法预测客户 本次实验采用的…