Python函数中参数是传递值还是引用详解


Posted in Python onJuly 02, 2019

在 C/C++ 中,传值和传引用是函数参数传递的两种方式,在Python中参数是如何传递的?回答这个问题前,不如先来看两段代码。

代码段1:

def foo(arg):
arg = 2
print(arg)
a = 1
foo(a) # 输出:2
print(a) # 输出:1

看了代码段1的同学可能会说参数是值传递。

代码段2:

def bar(args):
args.append(1)
b = []
print(b)# 输出:[]
print(id(b)) # 输出:4324106952
bar(b)
print(b) # 输出:[1]
print(id(b)) # 输出:4324106952

看了代码段2,这时可能又有人会说,参数是传引用,那么问题来了,参数传递到底是传值还是传引用或者两者都不是?为了把这个问题弄清楚,先了解 Python 中变量与对象之间的关系。

变量与对象

Python 中一切皆为对象,数字是对象,列表是对象,函数也是对象,任何东西都是对象。而变量是对象的一个引用(又称为名字或者标签),对象的操作都是通过引用来完成的。例如,[]是一个空列表对象,变量 a 是该对象的一个引用

a = []
a.append(1)

在 Python 中,「变量」更准确叫法是「名字」,赋值操作 = 就是把一个名字绑定到一个对象上。就像给对象添加一个标签。

a = 1

Python函数中参数是传递值还是引用详解

整数 1 赋值给变量 a 就相当于是在整数1上绑定了一个 a 标签。

a = 2

Python函数中参数是传递值还是引用详解

整数 2 赋值给变量 a,相当于把原来整数 1 身上的 a 标签撕掉,贴到整数 2 身上。

b = a

Python函数中参数是传递值还是引用详解

把变量 a 赋值给另外一个变量 b,相当于在对象 2 上贴了 a,b 两个标签,通过这两个变量都可以对对象 2 进行操作。

变量本身没有类型信息,类型信息存储在对象中,这和C/C++中的变量有非常大的出入(C中的变量是一段内存区域)

函数参数

Python 函数中,参数的传递本质上是一种赋值操作,而赋值操作是一种名字到对象的绑定过程,清楚了赋值和参数传递的本质之后,现在再来分析前面两段代码。

def foo(arg):
arg = 2
print(arg)
a = 1
foo(a) # 输出:2
print(a) # 输出:1

Python函数中参数是传递值还是引用详解

在代码段1中,变量 a 绑定了 1,调用函数 foo(a) 时,相当于给参数 arg 赋值 arg=1,这时两个变量都绑定了 1。在函数里面 arg 重新赋值为 2 之后,相当于把 1 上的 arg 标签撕掉,贴到 2 身上,而 1 上的另外一个标签 a 一直存在。因此 print(a) 还是 1。

再来看一下代码段2

def bar(args):
args.append(1)
b = []
print(b)# 输出:[]
print(id(b)) # 输出:4324106952
bar(b)
print(b) # 输出:[1]
print(id(b)) # 输出:4324106952

Python函数中参数是传递值还是引用详解

执行 append 方法前 b 和 arg 都指向(绑定)同一个对象,执行 append 方法时,并没有重新赋值操作,也就没有新的绑定过程,append 方法只是对列表对象插入一个元素,对象还是那个对象,只是对象里面的内容变了。因为 b 和 arg 都是绑定在同一个对象上,执行 b.append 或者 arg.append 方法本质上都是对同一个对象进行操作,因此 b 的内容在调用函数后发生了变化(但id没有变,还是原来那个对象)

最后,回到问题本身,究竟是是传值还是传引用呢?说传值或者传引用都不准确。非要安一个确切的叫法的话,叫传对象(call by object)。如果作为面试官,非要考察候选人对 Python 函数参数传递掌握与否,与其讨论字面上的意思,还不如来点实际代码。

show me the code

def bad_append(new_item, a_list=[]):
a_list.append(new_item)
return a_list

这段代码是初学者最容易犯的错误,用可变(mutable)对象作为参数的默认值。函数定义好之后,默认参数 a_list 就会指向(绑定)到一个空列表对象,每次调用函数时,都是对同一个对象进行 append 操作。因此这样写就会有潜在的bug,同样的调用方式返回了不一样的结果。

>>> print bad_append('one')
['one']
>>> print bad_append('one')
['one', 'one']

Python函数中参数是传递值还是引用详解

而正确的方式是,把参数默认值指定为None

def good_append(new_item, a_list=None):
if a_list is None:
a_list = []
a_list.append(new_item)
return a_list

Python函数中参数是传递值还是引用详解

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
使用python检测主机存活端口及检查存活主机
Oct 12 Python
Python语法快速入门指南
Oct 12 Python
django静态文件加载的方法
May 20 Python
对python3 中方法各种参数和返回值详解
Dec 15 Python
对Python发送带header的http请求方法详解
Jan 02 Python
Laravel+Dingo/Api 自定义响应的实现
Feb 17 Python
eclipse创建python项目步骤详解
May 10 Python
Django urls.py重构及参数传递详解
Jul 23 Python
python入门之基础语法学习笔记
Feb 08 Python
Python用5行代码实现批量抠图的示例代码
Apr 14 Python
基于Python的自媒体小助手---登录页面的实现代码
Jun 29 Python
pandas使用函数批量处理数据(map、apply、applymap)
Nov 27 Python
Python 运行.py文件和交互式运行代码的区别详解
Jul 02 #Python
python 函数中的内置函数及用法详解
Jul 02 #Python
使用python serial 获取所有的串口名称的实例
Jul 02 #Python
Python中那些 Pythonic的写法详解
Jul 02 #Python
python 中如何获取列表的索引
Jul 02 #Python
python 缺失值处理的方法(Imputation)
Jul 02 #Python
Python 读取串口数据,动态绘图的示例
Jul 02 #Python
You might like
浅析PHP水印技术
2007/02/14 PHP
Yii框架获取当前controlle和action对应id的方法
2014/12/03 PHP
typecho插件编写教程(一):Hello World
2015/05/28 PHP
PHP图像识别技术原理与实现
2016/10/27 PHP
PHP/ThinkPHP实现批量打包下载文件的方法示例
2017/07/31 PHP
php 广告点击统计代码(php+mysql)
2018/02/21 PHP
javascript 继承实现方法
2009/08/26 Javascript
简约JS日历控件 实例代码
2013/07/12 Javascript
5款JavaScript代码压缩工具推荐
2014/07/07 Javascript
详谈jQuery中的this和$(this)
2014/11/13 Javascript
node.js中的buffer.Buffer.isEncoding方法使用说明
2014/12/14 Javascript
移动端jQuery修正Web页面滑动时div问题的两则实例
2016/05/30 Javascript
JS作为值的函数用法示例
2016/06/20 Javascript
微信小程序商品到详情的实现
2017/06/27 Javascript
浅谈箭头函数写法在ReactJs中的使用
2017/08/22 Javascript
将jquery.qqFace.js表情转换成微信的字符码
2017/12/01 jQuery
对vue.js中this.$emit的深入理解
2018/02/23 Javascript
原生JS进行前后端同构
2018/04/22 Javascript
JavaScript实现单图片上传并预览功能
2019/09/30 Javascript
[55:23]VGJ.T vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
Python struct.unpack
2008/09/06 Python
Python版的文曲星猜数字游戏代码
2013/09/02 Python
Python找出文件中使用率最高的汉字实例详解
2015/06/03 Python
[机器视觉]使用python自动识别验证码详解
2019/05/16 Python
学习python分支结构
2019/05/17 Python
Python3列表List入门知识附实例
2020/02/09 Python
python实现低通滤波器代码
2020/02/26 Python
高考考python编程是真的吗
2020/07/20 Python
CSS3 选择器 基本选择器介绍
2012/01/21 HTML / CSS
CSS实现圆形放大镜狙击镜效果 只有圆圈里的放大
2012/12/10 HTML / CSS
html5+css3之制作header实例与更新
2020/12/21 HTML / CSS
英国著名的茶叶品牌:Whittard of Chelsea
2016/09/22 全球购物
Spartoo比利时:欧洲时尚购物网站
2017/12/06 全球购物
建筑实习自我鉴定
2013/10/18 职场文书
观看《周恩来的四个昼夜》思想汇报
2014/09/12 职场文书
JMeter对MySQL数据库进行压力测试的实现步骤
2022/01/22 MySQL