第115天:Python 到底是值传递还是引用传递

简介: 第115天:Python 到底是值传递还是引用传递

我们平时写的 Python 程序中充斥着大量的函数,包括系统自带函数和自定义函数,当我们调用函数时直接将参数传递进去然后坐等接收返回值即可,简直不要太好用。那么你知道函数的参数是怎么传递的么,是值传递还是引用传递呢,什么又是值传递和引用传递呢?


这个问题对于很多初学者还是比较有难度的,看到这里你可以稍加停顿,自己思考一下,看看自己是否真正理解了。很多人只是知道概念但是让他说他又说不清楚,思考过后如果你还觉得模糊的话,往下仔细看,我今天就带着你深入剖析下函数的参数传递机制。


为了搞清楚函数的参数传递机制,你必须先彻底理解形参和实参。例如下面的 sayHello 函数,括号里面的 name 就是形参,而当调用函数时传递的 name 是实参。


def sayHello(name): # name 是形式参数    print("Hello %s" % name)
name = "hanmeimei" # name 是实际参数sayHello(name)
# 输出结果Hello hanmeimei


值传递 OR 引用传递


上面我们说了,当调用函数时我们会把实际参数传递给形式参数。而这个传递过程有两种,就是我们上文说的值传递和引用传递了。


顾名思义,所谓值传递就是指在传递过程中将实际参数的值复制一份传递给形式参数,这样即使在函数执行过程中对形式参数进行了修改,形式参数也不会有所改变,因为二者互不干扰。而引用传递是值将实际参数的引用传递给实际参数,这样二者就会指向同一块内存地址,在函数执行过程中对形式参数进行了修改,形式参数也会一并=被修改。

为了故事的顺利发展,我们先来看看 Python 中关于变量的赋值。



>>> a = 10>>> b = a>>> a = a + 10>>> a20>>> b10>>>


在上述的例子中,我们声明了一个变量 a,其值为 10,然后将 b 也指向 a,这是在内存中的布局是这样的,变量 a 和 b 会指向同一个对象 10,而不是给 b 重新生成一个新的对象。


image.png


由此可知,同一个对象是可以被多个对象引用的。


当执行完 a = a + 10 后,因为整数是不可变对象,所以并不会将 10 变成 20,而是生成一个新的对象 20 ,然后 a 会指向这个新的对象。b 还是指向旧对象 10。


image.png


所以,最后就是 a 为 20,而 b 为 10。


理解了上面的赋值过程之后,我们再来看看参数的传递。老规矩,还是直接看例子吧,代码是不会骗人的。


def swap(a, b):    a, b = b, a    print("in swap a = %d and b = %d " % (a, b))
a = 100b = 200swap(a, b)print("in main a = %d and b = %d " % (a, b))
## 输出结果in swap a = 200 and b = 100 in main a = 100 and b = 200


我们在函数 swap 中交换 a 和 b 的值,然后分别在主函数和 swap 函数中输出其结果,


由结果可知,swap 函数并不会改变实际参数 a,b 的值,因此我们可以得出结论,Python 函数参数是按照值传递的。


别急,不妨再看多一个例子。


def swap(list):    list.append(4)    print("in swap list is %s " % list)
list_x = [1, 2, 3]swap(list_x)print("in main list is %s " % list_x)
## 输出结果in swap list is [1, 2, 3, 4] in main list is [1, 2, 3, 4]


咦,值被改了,这不就是引用传递了么。于是,我们又得出结论,Python 函数参数是按照引用传递的。


这未免有点太不严谨了,事实上我们上面的第二个例子有点不太严谨,我稍微修改了下 swap 函数,咱们在看看测试结果。



def swap(list):    list = list + [4]    print("in swap list is %s " % list)
## 输出结果in swap list is [1, 2, 3, 4] in main list is [1, 2, 3]


我们只是更改了 swap 函数内一行代码,结果就完全不一样了。为了更好的理解其执行过程,我画了张图。


image.png


在第一个关于 list 的例子中,我们首先声明了一个列表,其中的元素为 [1,2,3],此时其内存布局如上图中的步骤一所示。list_x 指向内存地址为 OX7686934F 的区域。


当调用 swap 函数将 list_x 传递给形式参数 list 时,会将该地址直接传递过去,list 也会指向这个地址,如步骤二所示。


最后,由于列表是可变的,所以当 list 在向列表中添加元素时,list_x 自然会受到影响,因为二者指向的是同一块内存。


所以,这里也是值传递,只不过传递的值是对象的内存地址罢了。


第二个关于 list 的例子中,我们对 swap 函数进行了修改,其执行流程如下图所示。


image.png


在执行 swap 函数之前都与上面的例子毫无差别。在 swap 函数内部 list = list + [4] 表示新建一个末尾加入元素 4 的新的列表,并让 list 指向这个新的内存地址  OX7686936A。因为是生成了一个新的对象,与原对象无关,所以 list_x 不受影响。


简而言之,弄清楚改变变量和重新赋值的区别就好了,第一个例子中我们改变了变量的值,所以当函数执行结束后所有指向该对象的变量都会受影响。而重新赋值相当于重新生成一个新的对象并在新的对象上做操作,因此旧对象不受影响。


如果我们要想在函数中改变对象,第一可以传入可变数据类型(列表,字典,集合),直接改变;第二还可以创建一个新的对象,修改后返回。建议用后者,表达清晰明了,不易出错。


总结


本文介绍了 Python 函数的参数传递机制。理解了参数的传递过程和底层实现细节,写代码时将会少犯一些不必要的低级错误。


最后,无论是值传递还是引用传递,我们只需关注函数内部是否会生成新的对对象即可。凡是对原对象操作的函数,都会影响传递的实际参数;凡是生成了新对象的操作,都不会影响传递的实际参数。


目录
相关文章
|
Python
python之函数的参数传递(引用传递和值传递),查看变量的内存地址的方法
python之函数的参数传递(引用传递和值传递),查看变量的内存地址的方法
|
存储 C++ Python
Python到底是引用传递还是值传递?网上大多数教程都讲错了
或许在很多人的直观印象中,变量是一个容器;给变量赋值,就像是往一个存储的容器中填入一个数据;再次赋值就是把容器中的数据换掉。
|
存储 C++ 开发者
python|基础|值传递和引用传递
python|基础|值传递和引用传递
147 0
|
2天前
|
存储 Python
Python编程入门:打造你的第一个程序
【10月更文挑战第39天】在数字时代的浪潮中,掌握编程技能如同掌握了一门新时代的语言。本文将引导你步入Python编程的奇妙世界,从零基础出发,一步步构建你的第一个程序。我们将探索编程的基本概念,通过简单示例理解变量、数据类型和控制结构,最终实现一个简单的猜数字游戏。这不仅是一段代码的旅程,更是逻辑思维和问题解决能力的锻炼之旅。准备好了吗?让我们开始吧!
|
2天前
|
机器学习/深度学习 人工智能 TensorFlow
人工智能浪潮下的自我修养:从Python编程入门到深度学习实践
【10月更文挑战第39天】本文旨在为初学者提供一条清晰的道路,从Python基础语法的掌握到深度学习领域的探索。我们将通过简明扼要的语言和实际代码示例,引导读者逐步构建起对人工智能技术的理解和应用能力。文章不仅涵盖Python编程的基础,还将深入探讨深度学习的核心概念、工具和实战技巧,帮助读者在AI的浪潮中找到自己的位置。
|
4天前
|
设计模式 算法 搜索推荐
Python编程中的设计模式:优雅解决复杂问题的钥匙####
本文将探讨Python编程中几种核心设计模式的应用实例与优势,不涉及具体代码示例,而是聚焦于每种模式背后的设计理念、适用场景及其如何促进代码的可维护性和扩展性。通过理解这些设计模式,开发者可以更加高效地构建软件系统,实现代码复用,提升项目质量。 ####
|
3天前
|
机器学习/深度学习 存储 算法
探索Python编程:从基础到高级应用
【10月更文挑战第38天】本文旨在引导读者从Python的基础知识出发,逐渐深入到高级编程概念。通过简明的语言和实际代码示例,我们将一起探索这门语言的魅力和潜力,理解它如何帮助解决现实问题,并启发我们思考编程在现代社会中的作用和意义。
|
2天前
|
机器学习/深度学习 数据挖掘 Python
Python编程入门——从零开始构建你的第一个程序
【10月更文挑战第39天】本文将带你走进Python的世界,通过简单易懂的语言和实际的代码示例,让你快速掌握Python的基础语法。无论你是编程新手还是想学习新语言的老手,这篇文章都能为你提供有价值的信息。我们将从变量、数据类型、控制结构等基本概念入手,逐步过渡到函数、模块等高级特性,最后通过一个综合示例来巩固所学知识。让我们一起开启Python编程之旅吧!
|
3天前
|
机器学习/深度学习 数据挖掘 开发者
Python编程入门:理解基础语法与编写第一个程序
【10月更文挑战第37天】本文旨在为初学者提供Python编程的初步了解,通过简明的语言和直观的例子,引导读者掌握Python的基础语法,并完成一个简单的程序。我们将从变量、数据类型到控制结构,逐步展开讲解,确保即使是编程新手也能轻松跟上。文章末尾附有完整代码示例,供读者参考和实践。
|
4天前
|
人工智能 数据挖掘 程序员
Python编程入门:从零到英雄
【10月更文挑战第37天】本文将引导你走进Python编程的世界,无论你是初学者还是有一定基础的开发者,都能从中受益。我们将从最基础的语法开始讲解,逐步深入到更复杂的主题,如数据结构、面向对象编程和网络编程等。通过本文的学习,你将能够编写出自己的Python程序,实现各种功能。让我们一起踏上Python编程之旅吧!