Python基础之值传递和引用传递详解
作者:真的不能告诉你我的名字 发布时间:2023-06-16 08:53:35
在python
中,向函数传递参数的类型有两种,一种是值传递,还有一种是引用传递,如果你恰恰好会一点c
基础,你可以理解为前者为传递形参,而后者传递指针。本篇文章将探究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
的值。
此结果执行后如下:
如上代码,我们传入的是形参,在函数中修改形参是不会改变原先的值的,这是因为函数运行时候会先进行压栈,运行过程中会产线局部信息等,恰恰好,我们传入的形参就是该类型的值,所以运行后会出栈,出栈后函数所在的内存也会被销毁,所以函数内的局部变量随着出栈也被销毁了。所以直接修改形参无效。
以上这个就是值传递。
那什么是引用传递呢?我们还是拿上面这个例子做比方,只不过传递的类型换一下,从数值类型更换为字典类型,如:
def modify_x(dict):
dict["x"] = 99
print("数中修改过后的值:" , dict)
a={
"x":66
}
modify_x(a)
print("执行modify_x函数后的值:", a)
如上代码,我们定义了一个字典a
,该字典有一个key
为x
,值为66
。在调用modify_x
函数中,我们将a
传递给了函数,在函数中,我们将该字典key
为x
的赋值为99
,函数结束,在主函数中打印a
的值。
执行后结果如下:
是不是感觉很诧异,同样的代码,为什么传递整形 和 传递 字典 , 所执行的效果不一样呢? 这是因为python
机制就是如此,它在传递该值的时候,使用的是指针传递,所以值没有改变,我们将其称之为引用传递。
可以干预参数传递是值传递还是引用传递么
python
不可以干预参数传递的类型,因为python
不像c
、c++
一样,可以传递形参,也可以传递指针类型。
在python
中,参数传递是由解释器实现的,所以说,普通开发者,没办法直接干预参数传递方式,但是可以曲线救国,善用return
就是其中一条,例如我们将最开始的代码修改一下,不直接修改值,而是返回一个新的值,例如:
def modify_x(x):
x = 99
return x
x = 66
x = modify_x(x)
print("执行modify_x函数后的值:" , x)
我们执行后,结果为:
这并不是修改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
中,解释器为了优化性能,避免大量无用数据拷贝,所以在传递的时候,一开始全是传递的实参,只有当函数内修改了值后,才会新申请一个内存来存该值。细节可以查看这个例子:
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
前后都打印其内存地址,结果如下:
我们发现,在未修改之前,地址内存都是指向同一个地址,修改之后,内存地址也变了。
如果我们将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
的值,查看变了没有,代码运行结果如下:
发现内存地址的值并没有改变,且x
的值在函数中真的被修改了。
所以通过上述例子,可以说明,值传递的时候,再没有修改的时候,该变量地址还是指向原来的地址,当值被修改后,就会开辟一个新的内存地址用于存储该值。这样的话可以避免拷贝大量数据。
最后再总结一下,哪些类型是引用传递,哪些类型是值传递:
引用传递分别有 列表、字典、集合、自定义类实例等。
值传递分别有 字符串类型、元组、布尔类型、数值类型等。
来源:https://juejin.cn/post/7229361569221099578


猜你喜欢
- 本文实例为大家分享了JS实现九宫格抽奖的具体代码,供大家参考,具体内容如下上代码:<div class="wrapper&q
- 以channel Attention Block为例子class CAB(nn.Module):def __init__(self, in_
- 何谓socket计算机,顾名思义即是用来做计算。因而也需要输入和输出,输入需要计算的条件,输出计算结果。这些输入输出可以抽象为I/O(inp
- 导语贪吃蛇,大家应该都玩过。当初第一次接触贪吃蛇的时候 ,还是我爸的数字手机,考试成绩比较好,就会得到一些小奖励,玩手机游戏肯定也在其中首位
- python编程中,我们在修改代码,遇到空格很多的情况下,我们要删除空格。本文小编整理了三种字符串去除空格的方法:方法一:使用字符串函数re
- Pycharm是一款很好用的python开发工具,开发Python爬虫和Python web方面都很不错这里我为大家提供了两种pycharm
- 三通道数组转成彩色图片 img=np.array(img1)img=img.reshape(3,img1.shap
- JS动态加载CSS 在可换主题的界面中具有很重要的意义,用户可以根据自己的浏览习惯选择自己喜欢的页面显示方式,下面详细说明。希望下面的方法对
- 介绍godep是解决包依赖的管理工具,目前最主流的一种,原理是扫描记录版本控制的信息,并在go命令前加壳来做到依赖管理godep 建议在 g
- 看例子: 数 据表 collect ( id, title ,info ,vtype) 就这4个字段,其中 title 用定长,info 用
- 要判断一个模块是否安装,非常简单,在终端中进入python,然后输入import 模块名。然后如果安装成功没有任何提示,直接显示下一行交互,
- 动态Web程序运行在Web容器之中,利用Web容器可以使用JDBC技术来实现数据库数据的CRUD操作,将数据表中的数据取出并结合JSP动态生
- 插值主要用于物理学数学中,逼近某一确定值的方法(1)插值是通过已知的离散数据求未知数据的方法。(2)与拟合不同,插值要求曲线通过所有的已知数
- 1、bootstrapBootstrap 是Twitter推出的一个用于前端开发的,一个用于 HTML、CSS 和 JS 开发的开源工具包,
- Beautiful Soup 库一般被称为bs4库,支持Python3,是我们写爬虫非常好的第三方库。因用起来十分的简便流畅。所以也被人叫做
- 上一文,介绍了vue.js动态添加、删除绑定的radio选项,本文介绍如何选中radio的某一项绑定的数据和上文的model是一致的,选中r
- python中注释在python中的注释一般分为单行注释、多行注释以及文档注释。注释描述在实际开发过程中,有效的代码注释不仅可以提升个人的工
- 也许已经有人发现可以这样写...CSS代码部分a.info { position:
- 在你自己安装了一个新的MySQL服务器后,你需要为MySQL的root用户指定一个目录(缺省无口令),否则如果你忘记这点,你将你的MySQL
- 今天我在练习python时,对字典里的键用sorted排序时发现并没有按照预期排序研究后发现字母大小写会影响排序首先创建一个字典,键里面的首