Python基础之值传递和引用传递详解

作者:真的不能告诉你我的名字 时间:2023-06-16 08:53:35 

python中,向函数传递参数的类型有两种,一种是值传递,还有一种是引用传递,如果你恰恰好会一点c基础,你可以理解为前者为传递形参,而后者传递指针。本篇文章将探究python的值传递和引用传递。

文本所依赖的python环境为:

Python基础之值传递和引用传递详解

什么是值传递和引用传递

值传递,我们可以理解为传递了一个副本过去,即变量的拷贝,修改副本值不会影响原先的值,例如:

def modify_x(x):
   x = 99
   print("函数中修改过后的值: " , x)

x=66
modify_x(x)
print("执行modify_x函数后的值:" , x)

在上述代码中,我们定义了一个变量x,并赋值为66,而后将x传入其modify_x函数中,在函数中,我们将x赋值为99,打印一下函数中的x值,函数结果。 在主函数中再打印一下x的值。

此结果执行后如下:

Python基础之值传递和引用传递详解

如上代码,我们传入的是形参,在函数中修改形参是不会改变原先的值的,这是因为函数运行时候会先进行压栈,运行过程中会产线局部信息等,恰恰好,我们传入的形参就是该类型的值,所以运行后会出栈,出栈后函数所在的内存也会被销毁,所以函数内的局部变量随着出栈也被销毁了。所以直接修改形参无效。

以上这个就是值传递。

那什么是引用传递呢?我们还是拿上面这个例子做比方,只不过传递的类型换一下,从数值类型更换为字典类型,如:

def modify_x(dict):
   dict["x"] = 99
   print("数中修改过后的值:" , dict)

a={
   "x":66
}
modify_x(a)
print("执行modify_x函数后的值:", a)

如上代码,我们定义了一个字典a,该字典有一个keyx,值为66。在调用modify_x函数中,我们将a传递给了函数,在函数中,我们将该字典keyx的赋值为99,函数结束,在主函数中打印a的值。

执行后结果如下:

Python基础之值传递和引用传递详解

是不是感觉很诧异,同样的代码,为什么传递整形 和 传递 字典 , 所执行的效果不一样呢? 这是因为python机制就是如此,它在传递该值的时候,使用的是指针传递,所以值没有改变,我们将其称之为引用传递。

可以干预参数传递是值传递还是引用传递么

python不可以干预参数传递的类型,因为python不像cc++一样,可以传递形参,也可以传递指针类型。

python中,参数传递是由解释器实现的,所以说,普通开发者,没办法直接干预参数传递方式,但是可以曲线救国,善用return就是其中一条,例如我们将最开始的代码修改一下,不直接修改值,而是返回一个新的值,例如:

def modify_x(x):
   x = 99
   return x

x = 66
x = modify_x(x)
print("执行modify_x函数后的值:" , x)

我们执行后,结果为:

Python基础之值传递和引用传递详解

这并不是修改x的值,而是接收modify_x传递回来的新值。

探寻一下值传递底层是如何实现的

我们之前所述的值传递,都是对数据的拷贝,可是现实真的如此么? 我们可以写一个案例来看下:

def modify_x(x):
   print("函数中:",id(x))

x = 123
print("函数外:",id(x))
modify_x(x)

在上述代码中,有一个新的知识点是方法id,它可以查看变量的内存地址。在上述例子中,在主函数中定义一个整形x,值为123,在传递给函数前,使用id方法查看一下变量的内存地址。而后传递给函数modify_x,在该函数中,也使用id方法来查看一下形参x的地址。

若真如我们所猜想,那么2个内存地址应该不一致才对,我们运行下程序:

Python基础之值传递和引用传递详解

发现函数内,和函数外的地址都是一样的? 哎,这是怎么回事呢?

这是因为在python中,解释器为了优化性能,避免大量无用数据拷贝,所以在传递的时候,一开始全是传递的实参,只有当函数内修改了值后,才会新申请一个内存来存该值。细节可以查看这个例子:

def modify_x(x) :
   print("函数中1:",id(x))
   x = 456
   print("函数中2:",id(x))

x=123
print("函数外0:",id(x))
modify_x(x)

上述代码,我们在modify_x函数中,修改变量x前后都打印其内存地址,结果如下:

Python基础之值传递和引用传递详解

我们发现,在未修改之前,地址内存都是指向同一个地址,修改之后,内存地址也变了。

如果我们将x更换为引用传递的数据的话,就不会出现以下这种情况,可以看下面这个例子:

def modify x(x) :
   print("函数中1:",id(x))
   x[0] = 456
   print("函数中2:",id(x))

x = [123]
print("函数外0:",id(x))
modify_x(x)
print("最后的值:" , x)

上述代码,我们做了一个小小的改动,我们将整形数据x,更改为了列表类型,最后再打印一下x的值,查看变了没有,代码运行结果如下:

Python基础之值传递和引用传递详解

发现内存地址的值并没有改变,且x的值在函数中真的被修改了。

所以通过上述例子,可以说明,值传递的时候,再没有修改的时候,该变量地址还是指向原来的地址,当值被修改后,就会开辟一个新的内存地址用于存储该值。这样的话可以避免拷贝大量数据。

最后再总结一下,哪些类型是引用传递,哪些类型是值传递:

引用传递分别有 列表、字典、集合、自定义类实例等。

值传递分别有 字符串类型、元组、布尔类型、数值类型等。

来源:https://juejin.cn/post/7229361569221099578

标签:Python,值传递,引用传递
0
投稿

猜你喜欢

  • python 如何获取文件夹中的全部文件

    2022-09-10 16:48:11
  • python中remove函数的踩坑记录

    2022-10-25 18:32:50
  • SQL 分布式查询、插入递增列示例

    2024-01-21 01:49:39
  • [MySQL binlog]mysql如何彻底解析Mixed日志格式的binlog

    2024-01-16 23:34:05
  • pytorch-gpu安装的经验与教训

    2022-01-11 20:23:36
  • CSS选择符小讲

    2009-09-17 11:53:00
  • php环境配置 php5 MySQL5 apache2 phpmyadmin安装与配置图文教程

    2023-11-14 22:08:47
  • Django ORM 多表查询示例代码

    2021-07-25 05:22:02
  • tensorflow的ckpt及pb模型持久化方式及转化详解

    2022-12-10 17:32:08
  • Python中的特殊语法:filter、map、reduce、lambda介绍

    2021-04-26 12:39:57
  • Python Logging 日志记录入门学习

    2022-05-17 14:48:39
  • Firefox 3.5 新增加的支持(整理)

    2009-08-01 12:51:00
  • 基于Python实现模拟三体运动的示例代码

    2022-03-29 21:40:37
  • OpenCV4.1.0+VS2017环境配置的方法步骤

    2022-11-21 18:22:38
  • python os.path模块使用方法介绍

    2023-08-03 18:02:32
  • Python实战之手写一个搜索引擎

    2023-07-11 21:16:49
  • Python数据结构之双向链表详解

    2023-02-01 05:10:07
  • 通过分析SQL语句的执行计划优化SQL

    2011-10-24 20:03:20
  • mssqlserver恢复ldf文件数据的方法

    2024-01-22 11:06:54
  • 不用script仅用css编写无限级弹出菜单

    2008-04-24 14:03:00
  • asp之家 网络编程 m.aspxhome.com