百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Python里参数是值传递还是引用传递?

off999 2024-12-03 00:17 27 浏览 0 评论

Python就是把一些参数从一个函数传递到另一个函数,从而使其执行相应的任务。但是你有没有想过,参数传递的底层是如何工作的,原理又是怎样的呢?

实际工作中,很多人会遇到这样的场景:写完了代码,一测试,发现结果和自己期望的不一样,于是开始一层层地 debug。花了很多时间,可到最后才发现,是传参过程中数据结构的改变,导致了程序的“出错”。

比如,我将一个列表作为参数传入另一个函数,期望列表在函数运行结束后不变,但是往往“事与愿违”,由于某些操作,它的值改变了,那就很有可能带来后续程序一系列的错误。

因此,了解 Python 中参数的传递机制,具有十分重要的意义,这往往能让我们写代码时少犯错误,提高效率。今天我们就一起来学习一下,Python 中参数是如何传递的。

什么是值传递和引用传递

如果你接触过其他的编程语言,比如 C/C++,很容易想到,常见的参数传递有 2 种:值传递和引用传递。所谓值传递,通常就是拷贝参数的值,然后传递给函数里的新变量。这样,原变量和新变量之间互相独立,互不影响。比如,我们来看下面的一段 C++ 代码:

#include <iostream>
using namespace std;
 
// 交换2个变量的值
void swap(int x, int y) {
    int temp;
    temp = x; // 交换x和y的值
    x = y;
    y = temp;
    return;
}

int main () {
    int a = 1;
    int b = 2;
    cout << "Before swap, value of a :" << a << endl;
    cout << "Before swap, value of b :" << b << endl;
    swap(a, b); 
    cout << "After swap, value of a :" << a << endl;
    cout << "After swap, value of b :" << b << endl;
    return 0;
}

Before swap, value of a :1
Before swap, value of b :2
After swap, value of a :1
After swap, value of b :2

这里的 swap() 函数,把 a 和 b 的值拷贝给了 x 和 y,然后再交换 x 和 y 的值。这样一来,x 和 y 的值发生了改变,但是 a 和 b 不受其影响,所以值不变。这种方式,就是我们所说的值传递。

所谓引用传递,通常是指把参数的引用传给新的变量,这样,原变量和新变量就会指向同一块内存地址。如果改变了其中任何一个变量的值,那么另外一个变量也会相应地随之改变。

还是拿我们刚刚讲到的 C++ 代码为例,上述例子中的 swap() 函数,如果改成下面的形式,声明引用类型的参数变量:

void swap(int& x, int& y) {
   int temp;
   temp = x; // 交换x和y的值
   x = y;
   y = temp;
   return;
}

那么输出的便是另一个结果:

Before swap, value of a :1
Before swap, value of b :2
After swap, value of a :2
After swap, value of b :1

原变量 a 和 b 的值被交换了,因为引用传递使得 a 和 x,b 和 y 一模一样,对 x 和 y 的任何改变必然导致了 a 和 b 的相应改变。

不过,这是 C/C++ 语言中的特点。那么 Python 中,参数传递到底是如何进行的呢?它们到底属于值传递、引用传递,还是其他呢?

在回答这个问题之前,让我们先来了解一下,Python 变量和赋值的基本原理。

a = 1
b = a
a = a + 1

这里首先将 1 赋值于 a,即 a 指向了 1 这个对象,如下面的流程图所示:

接着 b = a 则表示,让变量 b 也同时指向 1 这个对象。这里要注意,Python 里的对象可以被多个变量所指向或引用。

最后执行 a = a + 1。需要注意的是,Python 的数据类型,例如整型(int)、字符串(string)等等,是不可变的。所以,a = a + 1,并不是让 a 的值增加 1,而是表示重新创建了一个新的值为 2 的对象,并让 a 指向它。但是 b 仍然不变,仍然指向 1 这个对象。

因此,最后的结果是,a 的值变成了 2,而 b 的值不变仍然是 1。

通过这个例子你可以看到,这里的 a 和 b,开始只是两个指向同一个对象的变量而已,或者你也可以把它们想象成同一个对象的两个名字。简单的赋值 b = a,并不表示重新创建了新对象,只是让同一个对象被多个变量指向或引用。

同时,指向同一个对象,也并不意味着两个变量就被绑定到了一起。如果你给其中一个变量重新赋值,并不会影响其他变量的值。

明白了这个基本的变量赋值例子,我们再来看一个列表的例子:

l1 = [1, 2, 3]
l2 = l1
l1.append(4)
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]

同样的,我们首先让列表 l1 和 l2 同时指向了[1, 2, 3]这个对象。

由于列表是可变的,所以 l1.append(4) 不会创建新的列表,只是在原列表的末尾插入了元素 4,变成[1, 2, 3, 4]。由于 l1 和 l2 同时指向这个列表,所以列表的变化会同时反映在 l1 和 l2 这两个变量上,那么,l1 和 l2 的值就同时变为了[1, 2, 3, 4]。

另外,需要注意的是,Python 里的变量可以被删除,但是对象无法被删除。比如下面的代码:

arr = [1, 2, 3]
del arr

del arr 删除了 arr 这个变量,从此以后你无法访问 arr,但是对象[1, 2, 3]仍然存在。Python 程序运行时,其自带的垃圾回收系统会跟踪每个对象的引用。如果[1, 2, 3]除了 arr 外,还在其他地方被引用,那就不会被回收,反之则会被回收。

由此可见,在 Python 中:

1、变量的赋值,只是表示让变量指向了某个对象,并不表示拷贝对象给变量;而一个对象,可以被多个变量所指向。

2、可变对象(列表,字典,集合等等)的改变,会影响所有指向该对象的变量。

3、对于不可变对象(字符串、整型、元组等等),所有指向该对象的变量的值总是一样的,也不会改变。但是通过某些操作(+= 等等)更新不可变对象的值时,会返回一个新的对象。

4、变量可以被删除,但是对象无法被删除。

Python 函数的参数传递

从上述 Python 变量的命名与赋值的原理讲解中,相信你能举一反三,大概猜出 Python 函数中参数是如何传递了吧?

这里首先引用 Python 官方文档中的一段说明:

“Remember that arguments are passed by assignment in Python. Since assignment just creates references to objects, there’s no alias between an argument name in the caller and callee, and so no call-by-reference per Se.”

准确地说,Python 的参数传递是赋值传递 (pass by assignment),或者叫作对象的引用传递(pass by object reference)。Python 里所有的数据类型都是对象,所以参数传递时,只是让新变量与原变量指向相同的对象而已,并不存在值传递或是引用传递一说。比如,我们来看下面这个例子:

def my_func1(b):
  b = 2

a = 1
my_func1(a)
a
1

这里的参数传递,使变量 a 和 b 同时指向了 1 这个对象。但当我们执行到 b = 2 时,系统会重新创建一个值为 2 的新对象,并让 b 指向它;而 a 仍然指向 1 这个对象。所以,a 的值不变,仍然为 1。

那么对于上述例子的情况,是不是就没有办法改变 a 的值了呢?答案当然是否定的,我们只需稍作改变,让函数返回新变量,赋给 a。这样,a 就指向了一个新的值为 2 的对象,a 的值也因此变为 2。

def my_func2(b):
  b = 2
  return b

a = 1
a = my_func2(a)
a
2

不过,当可变对象当作参数传入函数里的时候,改变可变对象的值,就会影响所有指向它的变量。比如下面的例子:

def my_func3(l2):
  l2.append(4)

l1 = [1, 2, 3]
my_func3(l1)
l1
[1, 2, 3, 4]

这里 l1 和 l2 先是同时指向值为[1, 2, 3]的列表。不过,由于列表可变,执行 append() 函数,对其末尾加入新元素 4 时,变量 l1 和 l2 的值也都随之改变了。但是,下面这个例子,看似都是给列表增加了一个新元素,却得到了明显不同的结果。

def my_func4(l2):
  l2 = l2 + [4]

l1 = [1, 2, 3]
my_func4(l1)
l1
[1, 2, 3]

为什么 l1 仍然是[1, 2, 3],而不是[1, 2, 3, 4]呢?

要注意,这里 l2 = l2 + [4],表示创建了一个“末尾加入元素 4“的新列表,并让 l2 指向这个新的对象。这个过程与 l1 无关,因此 l1 的值不变。当然,同样的,如果要改变 l1 的值,我们就得让上述函数返回一个新列表,再赋予 l1 即可:

def my_func5(l2):
  l2 = l2 + [4]
  return l2

l1 = [1, 2, 3]
l1 = my_func5(l1)
l1
[1, 2, 3, 4]

这里你尤其要记住的是,改变变量和重新赋值的区别:

1、my_func3() 中单纯地改变了对象的值,因此函数返回后,所有指向该对象的变量都会被改变;

2、但 my_func4() 中则创建了新的对象,并赋值给一个本地变量,因此原变量仍然不变。

至于 my_func3() 和 my_func5() 的用法,两者虽然写法不同,但实现的功能一致。不过,在实际工作应用中,我们往往倾向于类似 my_func5() 的写法,添加返回语句。这样更简洁明了,不易出错。

总结

今天,我们一起学习了 Python 的变量及其赋值的基本原理,并且解释了 Python 中参数是如何传递的。和其他语言不同的是,Python 中参数的传递既不是值传递,也不是引用传递,而是赋值传递,或者是叫对象的引用传递。

需要注意的是,这里的赋值或对象的引用传递,不是指向一个具体的内存地址,而是指向一个具体的对象。

1、如果对象是可变的,当其改变时,所有指向这个对象的变量都会改变。

2、如果对象不可变,简单的赋值只能改变其中一个变量的值,其余变量则不受影响。

清楚了这一点,如果你想通过一个函数来改变某个变量的值,通常有两种方法。一种是直接将可变数据类型(比如列表,字典,集合)当作参数传入,直接在其上修改;第二种则是创建一个新变量,来保存修改后的值,然后将其返回给原变量。在实际工作中,我们更倾向于使用后者,因为其表达清晰明了,不易出错。

(此处已添加圈子卡片,请到今日头条客户端查看)

相关推荐

itunes备份文件(itunes备份文件把c盘爆满了)
  • itunes备份文件(itunes备份文件把c盘爆满了)
  • itunes备份文件(itunes备份文件把c盘爆满了)
  • itunes备份文件(itunes备份文件把c盘爆满了)
  • itunes备份文件(itunes备份文件把c盘爆满了)
ghost系统之家win10(windows ghost)

Ghost备份系统Win10可以通过使用Ghost软件来完成。首先,需要下载和安装Ghost软件。然后,将系统文件和数据备份到外部硬盘或其他存储设备中。接下来,打开Ghost软件,选择备份选项,并按照...

免费cad制图软件(电脑版cad免费怎么下载)

迅捷cad编辑器永久免费版全面支持图纸的编辑功能,软件体积小巧功能强大,他支持几乎所有主流的图片格式,让用户不会出现无法打开图纸的困扰,也不会让用户收到领域的困扰,包括电气、机械、建筑等等领域的cad...

笔记本电脑没声音是什么原因

笔记本电脑没有声音的原因是:1.声音是否被调到最小了。2.音频是否被禁用了。3.声卡驱动是不是有问题。4.如果电脑既没有声音也没有小喇叭的图标,则表示电脑的音频设备未启用。笔记本电脑没有声音的原因是:...

melogin路由器设置登录入口(192.168.1.1直接进入)

melogincn路由器的设置步骤如下第一、路由器线路连接1、请把你的.水星双频路由器上的WAN接口,用网线连接到猫的网口。如果你家宽带没有用到猫,就把入户的宽带网线,插在路由器的WAN口。2、把你的...

如何优化电脑性能
如何优化电脑性能

可以通过以下几个步骤来提高电脑运行速度和游戏流畅度:1.清理垃圾文件和无用程序,可以使用系统自带的清理工具或第三方软件;2.关闭开机自启动项,只保留必要的程序开机启动;3.升级硬件,比如增加内存、更换硬盘等;4.优化系统设置,如关闭不必要的...

2026-01-02 06:51 off999

ie8以上版本浏览器(ie8及以上版本浏览器)

浏览器IE8版本以上的意思就是当浏览的网页不支持低版本的IE浏览器,就会提示需要版本较高的IE8以上的版本才可以打开浏览网页。IE浏览器是美国微软公司推出的一款网页浏览器,原名MicrosoftIn...

适合电脑的应用商店(电脑最好的应用商店)

1.MicrosoftToDo推荐理由:微软出品,必属精品2.Microsoft便笺推荐理由:又是一款微软官方出品的良心免费应用,相比MicrosoftToDo,Microsoft便笺更加...

家里无线网连上不能用(家里无线网不能使用)

WiFi连上但不能使用可能有多种原因。以下是一些常见问题和解决方法:1.路由器问题:首先要确认路由器是否正常工作。可以尝试重启路由器,等待几分钟后再次连接并测试。2.网络设置问题:检查设备上的网络...

低价香港服务器(香港服务器推荐性价比)

香港最好的服务器是双向cn2+移动+联通三线优化直连的,性能配置都非常高,而且速度还非常稳定。 香港服务器的使用方法:1、首先需要选择一个服务商进行购买服务器;2、购买成功后,可在本地计算机...

免费360清理大师官方版(华为自带清理软件)

挺好用的。它可以清除你手机的里面的垃圾,检测和修复软件安全性。还有一些漏洞垃圾,你可以试着对比和使用,功效和针对性比较强。您杀毒没有效果的原因可能是您的安全软件版本过旧导致的,建议您使用最新版的腾讯手...

万能解压器安卓版(万能解压器官方下载)

是一款手机文件的助手。万能解压器手机版。专注于快速解压和压缩的文件管理工具!支持ZIP,RAR,7Z,TAR,ZIPX,GZIP,JAR等压缩和解压文件格式。是超好用、超便捷的解压软件!支持在手机上将...

cad看图(cad看图王)

以下是一些CAD看图的方法和技巧:1.放大/缩小:使用滚轮或放大镜工具可以方便地放大或缩小绘图。2.平移:使用平移工具可以在不改变视角的情况下将绘图向上、向下、向左或向右移动。3.旋转:使用旋转...

联想笔记本电脑装系统教程(联想笔记本装系统教程win10)
  • 联想笔记本电脑装系统教程(联想笔记本装系统教程win10)
  • 联想笔记本电脑装系统教程(联想笔记本装系统教程win10)
  • 联想笔记本电脑装系统教程(联想笔记本装系统教程win10)
  • 联想笔记本电脑装系统教程(联想笔记本装系统教程win10)
dell笔记本售后服务电话是多少
dell笔记本售后服务电话是多少

以下为dell售后服务点A:戴尔笔记本电脑维修点地址:上海市长宁区长宁路1027号兆丰广场5层 B:戴尔笔记本电脑维修点地址:上海市徐汇区漕溪北路45号 C:戴尔笔记本电脑维修点地址:上海市徐汇区漕溪路250号银海大厦1...

2026-01-02 02:03 off999

取消回复欢迎 发表评论: