一文读懂 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://xiahunao.cn/news/2812585.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java SSM框架实现家庭食谱管理系统项目【项目源码+论文说明】

基于java的SSM框架实现家庭食谱管理系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个家庭食谱管理系统 ,本系统将严格按照软件开发流程进行各个阶段的工作,采用B/S架构,面向对象编程思想进行项目开发。在引言中,作者将论…

大数据可视化的设计规范,全面剖析,很实用。

大数据可视化的设计规范需要考虑到数据量大、复杂度高、数据类型多样等特点。以下是一份常见的大数据可视化设计规范,供您参考: 设计原则 简单易用:保证用户操作简单、直观,降低用户认知负担。数据准确:保证数据准确…

如何保护企业免受人工智能网络钓鱼攻击

文章目录 前言一、生成式人工智能带来了新的网络安全威胁二、人工智能将使网络钓鱼攻击变得更加危险三、企业如何阻止人工智能驱动的网络钓鱼四、网络钓鱼模拟确保责任感和适应性前言 网络钓鱼是网络犯罪分子社会工程武器库中的超级武器。网络钓鱼尤其危险,因为它是网络犯罪分…

力扣经典题目解析--搜索二维矩阵(小米一面)

原题地址: . - 力扣(LeetCode) 给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中&#xff0c…

一键生成values-sw<N>dp文件夹插件

插件名&#xff1a;SmallestWidth Dimens&#xff0c;可在AS插件中搜索安装 安装插件后&#xff0c;可使用快捷键ALTP或者在Tools|SmallestWidth 启动插件 插件启动后可自主选择要在那个moudel下生成values-sw<N>dp文件夹&#xff0c;默认有一些文件夹&#xff0c;你也…

Day 2.exec函数族和线程的基本概念、相关函数接口

exec函数族 extern char **environ; int execl(const char *path, const char *arg, ... /* (char *) NULL */); int execlp(const char *file, const char *arg, ... /* (char *) NULL */); int execle(const…

无人艇军事应用展望与思考

源自&#xff1a;《远望要报》 作者&#xff1a;赵国安 “人工智能技术与咨询” 发布 一、无人艇作战使用场景 二、军用无人艇的发展趋势 三、军用无人艇的关键技术 四、世界主要国家无人艇发展动态 结束语 声明:公众号转载的文章及图片出于非商业性的教育和科研目的供大家参…

Vue概念详解【目录】

本专栏简介&#xff1a; 这个专栏是关于 Vue2 和 Vue3 各种概念的大集合&#xff01;它深入挖掘原理&#xff0c;分析各种优势和劣势&#xff0c;适配各种应用场景&#xff0c;部分内容还列出了代码示例&#xff0c;以清晰地讲述原理。在这里&#xff0c;你将全面了解 Vue2 和…

集团机构组网

在数字化转型的浪潮中&#xff0c;企业网络需求日益复杂化&#xff0c;尤其是对于大规模的集团机构来说&#xff0c;高效、安全且可靠的网络连接成为了业务发展的关键。传统网络架构已难以满足这些需求&#xff0c;而SD-WAN&#xff08;软件定义广域网&#xff09;技术的崛起&a…

四川易点慧电子商务有限公司抖音小店:可靠的新零售典范

随着电子商务的迅猛发展和社交媒体的广泛普及&#xff0c;越来越多的消费者选择在网上购物。在这个背景下&#xff0c;四川易点慧电子商务有限公司以其独特的商业模式和强大的供应链整合能力&#xff0c;在抖音小店平台上崭露头角&#xff0c;成为了一个值得信赖的购物新选择。…

提高办公效率:Excel在文秘与行政办公中的应用技巧

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 在当今信息化时代&#xff0c;Excel作为一款常…

Python算法题集_全排列

Python算法题集_全排列 题46&#xff1a;全排列1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【标记数组递归】2) 改进版一【指针递归】3) 改进版二【高效迭代模块】4) 改进版三【高效迭代模块极简代码】 4. 最优算法5. 相关资源 本文为Python…

B树和MySql索引

1.什么是B树 它是一种平衡得多叉树&#xff0c;称为B树&#xff0c;一颗M阶的B树&#xff0c;是一颗平衡的M路的多叉树&#xff0c;可以是空树或者满足一下性质&#xff1a; 根节点至少有两个孩子。每个节点都包含k-1个关键字和K个孩子&#xff0c;其中 ceil(m/2) ≤ k ≤ m …

安泰超声功率放大器技术参数有哪些

超声功率放大器是一种用于放大超声信号的设备&#xff0c;而超声功率放大器的技术参数对于设备的性能和应用场景起着重要作用。在本文中&#xff0c;我们将介绍一些常见的超声功率放大器的技术参数。 功率输出&#xff1a;超声功率放大器的功率输出是指放大器能够输出的最大功率…

【Android移动开发】Windows10平台安装Android Studio与人工智能算法模型部署案例

目录 一、Android Studio下载地址二、开发环境JDK三、开始安装Android Studio四、案例展示与搭建五、人工智能算法模型移动端部署案例参考 一、Android Studio下载地址 https://developer.android.google.cn/studio/install.html 电脑配置要求&#xff1a; 下载保存在指定文…

3.Prometheus数据模型

采样时间戳 指标 指标值平凡也就两个字: 懒和惰; 成功也就两个字: 苦和勤; 优秀也就两个字: 你和我。 跟着我从0学习JAVA、spring全家桶和linux运维等知识&#xff0c;带你从懵懂少年走向人生巅峰&#xff0c;迎娶白富美&#xff01; 关注微信公众号【 IT特靠谱 】&#xff0…

Niginx介绍和安装使用

Nginx是什么&#xff1f; Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器&#xff0c;同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔赛索耶夫为俄罗斯访问量第二的Rambler.ru站点&#xff08;俄文&#xff1a;Рамблер&#xff09;开发的&#xff0c;第一…

你并不了解 JavaScript:作用域与闭包 - 第二版 - 第八章:模块化模式

第八章&#xff1a;模块化模式 在本章中&#xff0c;我们将通过探索所有编程中最重要的代码组织模式之一&#xff1a;模块&#xff0c;来结束本书的正文。正如我们将看到的那样&#xff0c;模块本质上是由我们已经讲过的内容构建而成&#xff1a;这是你学习词法作用域和闭包所…

k8s(5)

目录 使用Kubeadm安装k8s集群&#xff1a; 初始化操作&#xff1a; 每台主从节点&#xff1a; 升级内核&#xff1a; 所有节点安装docker &#xff1a; 所有节点安装kubeadm&#xff0c;kubelet和kubectl&#xff1a; 修改了 kubeadm-config.yaml&#xff0c;将其传输给…

Azure Eventhub项目引入Servicebus报NoClassDefFoundError

前提 现有项目使用azure eventhub作为IOT数据载体进行数据传输。由于业务需要&#xff0c;需要同时引入servicebus。 <dependency><groupId>com.azure</groupId><artifactId>azure-messaging-servicebus</artifactId><version>7.13.3<…