当前位置: 首页 > news >正文

一文读懂 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编程。

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

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

相关文章:

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

文章目录 版本前言形参和实参值传递和引用传递Python 变量存储值语义和引用语义值语义引用语义 探讨 Python 值传递和引用传递不可变(immutable)类型可变(mutable)类型案例一案例二 拓展:不可变类型真的不可变&#xf…...

Linux进阶——系统安全,重要文件,加固系统的相关配置

目录 引出Linux系统安全一、重要文件二、帐户口令三、权限管理四、日志配置五、服务安全六、其他配置 缓存三兄弟:缓存击穿、穿透、雪崩缓存击穿缓存穿透缓存雪崩 总结 引出 Linux进阶——系统安全,重要文件,加固系统的相关配置 Linux系统安…...

C++三级专项 字符串逆序

输入一串‘!’结束的字符,按逆序输出。 输入 如题述。 输出 如题述。 输入样例 abc! 输出样例 cba解析:strlen(s)用来计算指定的字符串s的长度,不包括结束字符“\0”。 不准直接抄!!! …...

【iOS ARKit】ARWorldMap

ARWorldMap 用于存储 ARSession 检测扫描到的空间信息数据,包括地标(Landmark)、特征点(Feature Point)、平面(Plane)等,以及使用者的操作信息,如使用者添加的 ARAnchor …...

敏捷开发最佳实践:质量维度实践案例之软硬一体持续交付

在过去的Top敏捷实践案例中,我们可以看到企业或团队在敏捷质量管理上的创新,包括场景化测试、迭代T1自动化覆盖、一套自动用例到处运行、用例持续运行可视化等,而这也进一步促进了价值流动。本文将继续给大家带来全新的质量维度实践案例&…...

PMP证书的含金量如何?

PMP含金量更多的是“敲门砖”作用,公司招聘的门槛,现在坐项目的大部分都需要PMP/NPDP证书。 当然现在PMP管理模式也很热门,对企业发展很有利,各大企业都有引进改良应用在公司的项目上,之前在校友群里面大家在讨论PMP …...

Linux 下安装Jupyter

pip3 install jupyter pip3 install ipython -------------------------------------------- pip3 install jupyterlab jupyter lab pip3 list | grep jupyterlab 启动: python3 -m jupyter lab 2.安装朱皮特 pip3 install -i https://pypi.douban.com/simpl…...

docker 基础(二)

常见命令 Docker最常见的命令就是操作镜像、容器的命令,详见官方文档:https://docs.docker.com/ 数据卷 命令说明文档地址docker volume create创建数据卷docker volume createdocker volume ls创建数据卷docker volume lsdocker volume rm查看所有数…...

LeetCode 刷题 [C++] 第236题.二叉树的最近公共祖先

题目描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以…...

vue3+vite 项目的创建

这里要提醒一下,如果我们要使用 vue3 的组合式api 的写法的话, 那么我们使用的 vue 版本不能低于 vue3.2 版本,不能低于 vue3.2 版本,不能低于 vue3.2 版本 vue2 已停止维护了, 现在全面拥抱vue3 之前用 vue-cli 创建…...

Windows Server 2022 使用ApacheDS用户认证

Windows Server 2022 使用ApacheDS用户认证 参考文档:https://docs.foxpass.com/docs/windows-ldap-auth-with-pgina 安装pGina软件,打开pGina软件 勾选启用LDAP认证,点击Configure 修改LDAP认证信息 点击Gateway,设置只要登…...

【Oracle】Oracle清理日志空间

(一)通过adrci清理日志空间 1.通过find命令查询大数据文件 find / -type f -size 100M 2.登录oracle数据库服务器用户 su - oracle 3.执行故障诊断命令 adrci 4.查询ADR目录 show home 5.切换到对应目录 set homepath diag/rdbms/orcl 6.执行日志清理命令…...

数据抽取平台pydatax介绍--实现和项目使用

数据抽取平台pydatax实现过程中,有2个关键点: 1、是否能在python3中调用执行datax任务,自己测试了一下可以,代码如下: 这个str1就是配置的shell文件 try:result os.popen(str1).read() except Exception as …...

容易发生内存泄漏的八个场景,你都知道吗?

内存泄漏与内存溢出 JVM在运行时会存在大量的对象,一部分对象是长久使用的,一部分对象只会短暂使用 JVM会通过可达性分析算法和一些条件判断对象是否再使用,当对象不再使用时,通过GC将这些对象进行回收,避免资源被用…...

掌握 Vue3 中的 setup 函数

Vue.js 经历了从 Vue 2 到 Vue 3 的重大变革,带来了许多引人注目的新特性和性能优化。其中,setup函数无疑是最引人瞩目的新星之一。 一、概览 setup函数是 Vue 3 引入的一个新的组件选项,作为组合式 API 中心,它允许开发者在一个…...

BUUCTF AWD-Test1

打开靶场是这个有些简陋的界面。 随便点点,找到这个东西。 看到ThinkPHP,思路瞬间清晰,老熟人了。这个就是ThinkPHP漏洞。根据版本我们去找一下poc。 /index.php/?sIndex/\think\View/display&content%22%3C?%3E%3C?php%20phpinfo();…...

百亿诈骗案频出,欧科云链用“技术责任”拓宽Web3安全边界

2022年12月1日,《中华人民共和国反电信网络诈骗法》正式实施,中国正式迈入“全民反诈时代”。据CNNIC和智研咨询统计显示,截至2021年12月,国内网民遭遇网络诈骗比例为16.6%,数千万人深受网络诈骗的危害。 以新兴技术区…...

一个实时波形图的封装demo(QT)(qcustomplot)

前言: 封装的一个实时波形图的类,可以直接提升使用。 提供了接口,可以更改颜色,样式,等等 参考: Qt Plotting Widget QCustomPlot - Introduction 另外参考了一个大神的作品,链接没找到。 项目…...

Java进阶-反射

来学习一下Java的反射,通过Class实例获取class信息的方法称为反射(Reflection),内容如下 一、反射机制 1、概述 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一…...

力扣180 连续出现的数字

如何有效地识别在数据库中至少连续出现三次的数字? 目录 题目描述 解题思路 完整代码 进一步探索 题目描述 表:Logs ---------------------- | Column Name | Type | ---------------------- | id | int | | num | varch…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

在rocky linux 9.5上在线安装 docker

前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

生成 Git SSH 证书

🔑 1. ​​生成 SSH 密钥对​​ 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​: -t rsa&#x…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...