Python参数传递,既不是传值也不是传引用
面试的时候,有没有被问到Python传参是传引用还是传值这种问题?有没有听到过Python传参既不是传值也不是传引用这种说法?一个小小的参数默认值也可能让代码出现难以查找的bug?
如果你也遇到过上面的问题,不妨我们来探究下Python函数传递的种种。
万物皆对象
Python中有一个非常重要的概念——万物皆对象,无论是一个数字、字符串,还是数组、字典,在Python中都会以一个对象的形式存在。
a = 123
对于上面这行代码,在Python看来就是创建一个PyObject对象,值为123,然后定义一个指针a,a指向这个PyObject对象。
可变对象和不可变对象
Python中的对象分为两种类型,可变对象和不可变对象,不可变对象指tuple、str、int等类型的对象,可变对象指的是dict、list、自定义对象等类型的对象,我们用一段代码说明他们的区别。
a = [1, 2, 3]
print(id(a)) # 2587116690248
a += [4]
print(id(a)) # 2587116690248
b = 1
print(id(b)) # 2006430784
b += 1
print(id(b)) # 2006430816
上面代码中我们分别定义了一个可变对象和一个不可变对象,并且对他们进行修改,打印修改前后的对象标识可以发现,对可变对象进行修改,变量对其引用不会发生变化,对不可变对象进行修改,变量引用发生了变化。
上图是一个可变对象,当修改对象时,例如删除数组中的一个元素,实际上把其中一个元素从对象中移除,对象本身的标识是不发生变化的。
改变一个不可变对象时,例如给一个int型加2,语法上看上去是直接修改了i这个对象,但是如前面所说,i只是一个指向对象73的一个变量,Python会将这个变量指向的对象加2后,生成一个新的对象,然后再让i指向这个新的对象。
参数传递时的表现
了解了对象的原理后,我们就可以来尝试理解一下参数传递时他们的不同表现了。
a = [1, 2, 3]
print(id(a)) # 1437494204232
def mutable(a):
print(id(a)) # 1437494204232
a += [4]
print(id(a)) # 1437494204232
mutable(a)
b = 1
print(id(b)) # 2006430784
def immutable(b):
print(id(b)) # 2006430784
b += 1
print(id(b)) # 2006430816
immutable(b)
通过上面的代码可以看出,修改传进的可变参数时,会对外部对象产生影响,修改不可变参数时则不会影响。
概括地说,Python参数传递时,既不是传对象也不是传引用,之所以会有上述的区别,跟Python的对象机制有关,参数传递只是给对象绑定了一个新的变量(实际上是传递C中的指针)。
参数传递时的坑
理解了参数传递的逻辑,我们需要注意一下这种逻辑可能引发的问题。
def test(b=[]):
b += [1]
print(b)
test() # [1]
test() # [1, 1]
test() # [1, 1, 1]
上面的代码的输出,按照可变对象传参的逻辑,应该每次调用都输出1才对,而实际输出看上去好像默认参数好像只生效了一次。原因在于Python的函数也是对象(万物皆对象),这个对象只初始化一次,加上参数又是不可变对象,所以每次调用实际上都修改的是一个对象。
解决这个问题,推荐再参数传递可变对象时,默认值设置为None,在函数内部对None进行判断后再赋予默认值。
def test(b=None):
b = b or []
b += [1]
print(b)
test() # [1]
test() # [1]
test() # [1]
再看一段代码。
i = 1
def test(a=i):
print(a)
i = 2
test() # 1
由于参数默认值是在函数定义时而不是函数执行时确定的,所以这段代码test方法的参数默认值时1而不是2。厦工叉车
Python参数传递,既不是传值也不是传引用的更多相关文章
- C语言中传值和C++的传引用
在C语言中,传址其实也时传值的一种,首先地址其实也时可以看做是一个值来进行传递的. 在C++中有一种说法叫传引用,就是&变量名. 比如: /* * 传值 int a = 3; void fun ...
- Python学习笔记之函数参数传递 传值还是传引用
在学完Python函数那一章节时,很自然的的就会想到Python中函数传参时传值呢?还是传引用?或者都不是? 在回答上面的问题之前我们先来看看下面的代码: 代码1: def foo(var): v ...
- 传值与传引用(C++)
reference(引用) 是C++对C的一个扩充 int a; int &b = a;//声明b是一个整形的引用变量 C语言,函数的参数传递有2种形式:传值方式调用和传引用方式调用 传值方式 ...
- java 函数形参传值和传引用的区别
java方法中传值和传引用的问题是个基本问题,但是也有很多人一时弄不清. (一)基本数据类型:传值,方法不会改变实参的值. public class TestFun { public static v ...
- python函数的参数传递问题---传值还是传引用?
摘要:在python中,strings, tuples, 和numbers是不可更改的对象,而list,dict等则是可以修改的对象.不可更改对象的传递属于传值,可更改对象属于传引用.想要在函数中传递 ...
- Python参数传递(传值&传引用)
# 测试参数是传值还是传引用def test(arg): print("test before") print(id(arg)) arg[1]=30 # 测试可变对象 # arg[ ...
- python 参数传递 传值还是传引用
个人推测结论: 可变对象传引用,不可变对象传值 python里的变量不同于c中地址储值模型 a=100 b=100 print(id(a),id(b),a==b,a is b) #8790877986 ...
- python函数传参是传值还是传引用?
首先还是应该科普下函数参数传递机制,传值和传引用是什么意思? 函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题.基本的参数传递机制有两种:值传递和引用传 ...
- Python中参数是传值,还是传引用?
在 C/C++ 中,传值和传引用是函数参数传递的两种方式,在Python中参数是如何传递的?回答这个问题前,不如先来看两段代码. 代码段1: def foo(arg): arg = 2 print(a ...
随机推荐
- dede:channel二级导航currentstyle属性失效问题
dede:channel默认只作用在一级导航中,在调用下级导航(type='son')时,发现不起作用. 修改方法:修改 include/taglib/channel.lib.php 第133行.if ...
- 980. Unique Paths III
题目来源: https://leetcode.com/problems/unique-paths-iii/ 自我感觉难度/真实难度: 题意: 分析: 回溯法,直接DFS就可以了 自己的代码: clas ...
- 测试html报告 github python3版本
github源码下载地址:https://github.com/huilansame/HTMLTestRunner_PY3/archive/master.zip 解压后进入文件找到文件:HTMLTes ...
- NYOJ 36 LCS(最长公共子序列)
题目链接: http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=36 最长公共子序列 时间限制:3000 ms | 内存限制:65535 KB ...
- traefik-Ingress边缘路由器落地到微服务
1.理解Ingress 简单的说,ingress就是从kubernetes集群外访问集群的入口,将用户的URL请求转发到不同的service上.Ingress相当于nginx.apache等负载均衡方 ...
- STM32定时器输出PWM频率和步进电机控制速度计算
1.STM32F4系列定时器输出PWM频率计算 第一步,了解定时器的时钟多少: 我们知道AHP总线是168Mhz的频率,而APB1和APB2都是挂在AHP总线上的. (1)高级定时器timer1, t ...
- dpkg安装失败解决过程
终于好了.搞到转钟3点都没搞定,耽误不少时间. 执行sudo port install dpkg 报错如下Error: org.macports.build for port gmp return ...
- Go语言连接Oracle(就我这个最全)
综合参考了网上挺多的方案 倒腾了半天终于连接好了 Go都出来这么多年了 还没有个Oracle的官方驱动... 过程真的很蛋疼..一度想放弃直接连ODBC 首先交代一下运行环境和工具版本: WIN10 ...
- VIM - visual selection 模式下的简单操作
1. 概述 vim 的 visual selection 模式下的简单操作 2. visual selection 模式 概述 可视化选择 可视化选择 vim 的一种专门用来选择的模式 可以提供相对于 ...
- innodb_flush_log_at_trx_commit
innodb_flush_log_at_trx_commit innodb_buffer_pool_size如 果用Innodb,那么这是一个重要变量.相对于MyISAM来说,Innodb对于bu ...