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

学习python的第十三天之数据类型——函数传参中的传值和传址问题

学习python的第十三天之数据类型——函数传参中的传值和传址问题

函数传参中的传值和传址问题

函数传参的机制可以理解为传值(pass-by-value)和传址(pass-by-reference)的混合体,但实际上更接近于传对象引用(pass-by-object-reference)。

不可变类型(传值?)

对于不可变类型(如整数、浮点数、字符串、元组等),当你将它们作为参数传递给函数时,似乎是在传值,因为任何在函数内部对这些参数所做的修改都不会影响到函数外部的变量。

def modify_value(x):x = 10  # 解释:相当于将10的地址给到临时变量x,替换了原来5的地址print("Inside function:", x, id(x))  # 解释:所以打印的地址是10的地址a = 5  # 解释:将5的地址给到a
modify_value(a)  # 解释:相当于将a的地址给到modify_value函数中的临时变量x
print("Outside function:", a, id(a))  # 解释:a的地址是5的地址# Inside function: 10 2450059455056
# Outside function: 5 2450059454896
# 地址发生变化,因为小整数池的原因

在这个例子中,a 是一个整数对象,当它被传递给 modify_value 函数时,函数内部得到的是 a 的一个副本(在内存中是一个新的整数对象 10),而不是 a 本身。因此,函数内部对 x 的修改不会影响到外部的 a

然而,这并不是说 Python 在传递这些值时进行了完整的拷贝。实际上,Python 传递的是对不可变对象的引用,但由于这些对象是不可变的,所以你不能通过引用改变它们的内容。当你尝试改变它们时,你实际上是在创建一个新的对象。

可变类型(传址?)

对于可变类型(如列表、字典、集合等),当你将它们作为参数传递给函数时,函数内部可以直接修改这些对象的内容,这种行为看起来像是传址。

def modify_list(lst):lst.append(10)  # 解释:因为list列表是可变类型,内容发生变化后地址不会变,所以lst的地址还是传进来的my_list的地址2077876147584print("Inside function:", lst, id(lst))  # 解释:所以打印的地址还是my_list的地址2077876147584,但是内容变换了my_list = [1, 2, 3]
modify_list(my_list)  # 解释:相当于将my_list的地址2077876147584给到modify_list函数中的临时变量lst
print("Outside function:", my_list, id(my_list))  # 解释:因为在函数中将地址2077876147584的列表内容进行修改了,但是my_list的地址没变,还是指向2077876147584,所以my_list的内容也跟着变化了# Inside function: [1, 2, 3, 10] 2077876147584
# Outside function: [1, 2, 3, 10] 2077876147584
# 地址没发生变化,因为list列表为可变类型

在这个例子中,my_list 是一个列表对象,当它被传递给 modify_list 函数时,函数内部得到的是对同一个列表对象的引用。因此,函数内部对 lst 的修改会影响到外部的 my_list

传址和传值的对比解释(重要)

前情提要:如过函数中给入的参数是函数中有的变量,则在这个函数中变量会作为局部变量使用,不会影响到外面同名的变量。
在Python中,当我们提到“对象的地址”或“对象的内存地址”时,我们实际上是在谈论一个更抽象的概念,即对象的标识符。这个标识符是由Python解释器在内部生成的,用于唯一地标识每个对象。虽然标识符在底层实现上可能与对象的实际内存地址有关,但Python解释器并不直接暴露内存地址给开发者。标识符是一个更高级的抽象,它允许Python在内存管理方面保持更大的灵活性。

list1 = ['a', 'b', 'c', [1,3,5]]
list2 = list1[::-1]
list3 = list1[1:-1]print(list1,id(list1))  # 输出: ['a', 'b', 'c', [1, 3, 5]] 2464707002304
print(list2,id(list1))  # 输出: [[1, 3, 5], 'c', 'b', 'a'] 2464707002304
print(list3,id(list1))  # 输出: ['b', 'c'] 2464707002304
print('-----------------------------------')def func1(l1, l2):l1 = l2l2.append(10)func1(list2, list3)
print('-----------------------------------')
print(list1,id(list1))  # 输出: ['a', 'b', 'c', [1, 3, 5]] 2464707002304
print(list2,id(list1))  # 输出: [[1, 3, 5], 'c', 'b', 'a'] 2464707002304
print(list3,id(list1))  # 输出: ['b', 'c', 10] 2464707002304# func1(list2, list3)实际上是将list2的‘身份标识符’给到了函数里的l1,将list3的‘身份标识符’给到了函数里的l2,
# 因为函数中存在l1这个赋值变量,但是为什么l2不算是临时变量呢?
# 是因为l1 = l2这句,通俗的说你要存放一个东西,无论这个东西是什么,你要先有一个位置,
# l1就是这个位置,l2就是这个东西,而l2这个东西的来源就是靠调用func1()这个函数来分配的;
# 同样l2.append(10)这一句,只是对这个未知的l2进行的一步操作,也没有创建一个叫l2的临时变量,
# 综上,函数中的l1是临时变量,所以对l1的赋值操作不会影响到给予‘身份标识符’的list2,
# 但是l2不是临时变量,所以l2指代的就是list3,所以l2的操作就会影响到给予‘身份标识符’的list3。
# 如果函数改为:
list1 = ['a', 'b', 'c', [1,3,5]]
list2 = list1[::-1]
list3 = list1[1:-1]print(list1,id(list1))  # 输出: ['a', 'b', 'c', [1, 3, 5]] 2587051900864
print(list2,id(list1))  # 输出: [[1, 3, 5], 'c', 'b', 'a'] 2587051900864
print(list3,id(list1))  # 输出: ['b', 'c'] 2587051900864
print('-----------------------------------')def func2(l1, l2):l1 = l2l2 = l2[::-1]func2(list2, list3)
print('-----------------------------------')
print(list1,id(list1))  # 输出: ['a', 'b', 'c', [1, 3, 5]] 2587051900864
print(list2,id(list1))  # 输出: [[1, 3, 5], 'c', 'b', 'a'] 2587051900864
print(list3,id(list1))  # 输出: ['b', 'c'] 2587051900864# 可以发现,这次l2就没有影响到list3,因为这次l2也变成了临时变量
# 同理就算l1换成list1,l2换成list2,函数中的list1和list2也只是存在与函数中,和全局的list1、list2不是同一个;
list1 = ['a', 'b', 'c', [1,3,5]]
list2 = list1[::-1]
list3 = list1[1:-1]print(list1,id(list1))  # 输出: ['a', 'b', 'c', [1, 3, 5]] 2221755744192
print(list2,id(list1))  # 输出: [[1, 3, 5], 'c', 'b', 'a'] 2221755744192
print(list3,id(list1))  # 输出: ['b', 'c'] 2221755744192
print('-----------------------------------')def func2(list1, list2):list1 = list2list2.pop()func2(list2, list3)
print('-----------------------------------')
print(list1,id(list1))  # 输出: ['a', 'b', 'c', [1, 3, 5]] 2221755744192
print(list2,id(list1))  # 输出: [[1, 3, 5], 'c', 'b', 'a'] 2221755744192
print(list3,id(list1))  # 输出: ['b'] 2221755744192# 结果就是函数中的list1临时变量既没有影响到全局同名的list1,也没有影响到给予‘身份标识符’的list2;
# 函数中的list2(非临时变量),只影响到给予‘身份标识符’的list3,而没有影响到全局同名的list2;
总结

更准确地说,Python 在函数传参时传递的是对对象的引用。对于不可变对象,由于你不能改变它们的内容,所以这种传递方式看起来像是传值。对于可变对象,由于你可以改变它们的内容,所以这种传递方式看起来像是传址。

相关文章:

学习python的第十三天之数据类型——函数传参中的传值和传址问题

学习python的第十三天之数据类型——函数传参中的传值和传址问题 函数传参中的传值和传址问题 函数传参的机制可以理解为传值(pass-by-value)和传址(pass-by-reference)的混合体,但实际上更接近于传对象引用&#xff…...

Windows11深度学习环境配置

CUDA、CUDNN 一、安装另一个版本的CUDA 下载.exe文件,网址打不开自己开热点就能解决:CUDA Toolkit 11.2 Downloads | NVIDIA Developer 若遇到“You already have a newer version of the NVIDIA Frameview SDK installed” 1.把电脑已经存在的FrameVi…...

电销老是被标记,该如何解决!!!

在当今的商业世界中,电话销售依然是许多企业拓展业务、接触客户的重要手段。然而,电销人员常常面临一个令人头疼的问题 —— 老是被标记。 一、电销被标记的困扰 当你的电话号码被频繁标记为 “骚扰电话”“推销电话” 等,会带来一系列不良…...

MyBatis入门——基本的增删改查

目录 一、MyBatis简介 二、搭建MyBatis (一)配置依赖 (二)log4j日志功能 (三)数据库配置文件——jdbc.properties (四)创建MyBatis的核心配置文件 (五)使用MyBatisX插件 三、项目其他配置搭建 (一)创建数据库连接工具类 (二)创建表 (三)创建数据库的实体类 (四)Use…...

学习Gentoo系统中二进制软件包和源代码包的概念

Gentoo Linux 是一个以源代码包管理和高度定制化特性著称的Linux发行版。以下是关于Gentoo系统中二进制软件包和源代码包的概念、发展历程以及它们各自的优势: 二进制软件包概念及发展历程: 概念:Gentoo的二进制软件包是指预先编译好的软件包…...

麦肯锡报告 | 未来的经济引擎:解读下一代竞争领域

随着科技和商业的快速发展,一些具有高增长性和高动态性的行业正在悄然崛起,成为推动全球经济发展的新引擎。这些行业被称为“竞争领域”(Arenas)。据麦肯锡全球研究院(MGI)的研究,这些领域有望在…...

连接mysql并读取指定表单数据到DataFrame

提问 python 如何连接mysql并读取指定表单数据到DataFrame 解答 要在Python中连接MySQL并读取指定表单数据到DataFrame,你可以使用pandas库结合sqlalchemy引擎或者mysql-connector-python。这里我将展示两种方法的示例代码。 使用pandas和sqlalchemy 确保安装了…...

从入门到精通数据结构----四大排序(上)

目录 首言: 1. 插入排序 1.1 直接插入排序 1.2 希尔排序 2. 选择排序 2.1 直接选择排序 2.2 堆排序 3. 交换排序 3.1 冒泡排序 3.2 快排 结尾: 首言: 本篇文章主要介绍常见的四大排序:交换排序、选择排序、插入排序、归并排…...

【bug】使用transformers训练二分类任务时,训练损失异常大

使用transformers训练二分类任务时,训练损失异常大 问题分析 问题 training_loss异常大,在二分类损失中,收敛在1~2附近,而eval_loss却正常(小于0.5) 分析 参考: Bug in gradient accumulation…...

文献阅读与笔记整理技巧

文献阅读 1.原因 (1)了解背景知识(硕博学位论文,大牛文献综述) (2)把握研究方向(行业最新论文,大牛文献综述) (3)学习设计思路&am…...

Python Flask中集成SQLAlchemy和Flask-Login

在现代Web应用开发中,数据库和用户认证是两个非常重要的功能。Flask作为一个轻量级的Python Web框架,本身只提供了最基本的Web功能。但是,它可以通过集成各种优秀的扩展库来增强功能。本文将介绍如何在Flask应用中集成SQLAlchemy(数据库)和Flask-Login(用户认证),并提供一个完整…...

esp32 JTAG 串口 bootload升级

文章目录 一、前言二、了解 JTAG 和 Ymodem 的工作原理2.1 环境准备2.2 Ymodem 协议工作原理2.3 固件分区准备 三、关键升级函数五、使用shell 测试 一、前言 如果使用 JTAG 串口 结合 Ymodem 协议 实现 ESP32 的固件升级,整体逻辑将围绕通过串口传输固件文件并将其…...

【linux】(17)压缩和解压

tar tar 是一个用于创建、维护、修改和解压缩存档文件的 Linux 命令。tar 常常用于备份文件或者将多个文件打包成一个文件以便于传输或存储。以下是 tar 命令的详细教程,包括常用选项和示例: 基本语法 tar [选项] [文件或目录]常用选项 -c&#xff1…...

摄像机视频分析软件下载LiteAIServer视频智能分析平台玩手机打电话检测算法技术的实现

随着科技的不断进步,摄像机视频分析软件的发展已经为我们的生活带来了许多便捷。其中,LiteAIServer视频智能分析平台的玩手机打电话检测算法技术尤为突出,它利用先进的图像处理和人工智能技术,能够自动识别并监控视频中的玩手机或…...

springboot购物推荐网站的设计与实现(代码+数据库+LW)

摘要 随着信息互联网购物的飞速发展,一般企业都去创建属于自己的电商平台以及购物管理系统。本文介绍了东大每日推购物推荐网站的开发全过程。通过分析企业对于东大每日推购物推荐网站的需求,创建了一个计算机管理东大每日推购物推荐网站的方案。文章介…...

【Unity3D插件】Unity3D HDRP Outline高亮发光轮廓描边插件教程

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群:398291828小红书小破站 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 最近用Unity3D的HDRP(高清渲染管…...

QT基础 UI编辑器 QT5.12.3环境 C++环境

一、UI编辑器 注意:创建工程时,要勾上界面按钮 UI设计师界面的模块 UI编辑器会在项目构建目录中自动生成一个ui_xxx.h(构建一次才能生成代码),来表示ui编辑器界面的代码,属于自动生成的,一定不…...

计算机网络socket编程(5)_TCP网络编程实现echo_server

个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 计算机网络socket编程(5)_TCP网络编程实现echo_server 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记,欢迎大家在评论区交…...

go语言闭包捕获的是变量的引用而不是变量的值

在 Go 语言中,闭包捕获的是变量的引用,而不是变量的值。这意味着闭包会引用循环变量或外部变量的实际内存位置,而不是在闭包创建时复制变量的值。这种行为有时会导致意外的结果,尤其是在循环中创建多个闭包时。 闭包捕获变量的引…...

周期法频率计的设计

目录 周期法频率计 分析: 设计过程: 周期法频率计 对于低频信号,应用周期法进行测频。周期法测频的基本原理是:应用标准频率信号统计被测信号两个相邻脉冲之间的脉冲数,然后通过脉冲数计算出被测信号的周期&#xff…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

嵌入式常见 CPU 架构

架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...

实战设计模式之模板方法模式

概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...

OCR MLLM Evaluation

为什么需要评测体系?——背景与矛盾 ​​ 能干的事:​​ 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。​​干不了的事:​​ 碰到复杂表格(合并单元…...