Python FAQ1:传值,还是传引用?
在C/C++中,传值和传引用是函数参数传递的两种方式。由于思维定式,从C/C++转过来的Python初学者也经常会感到疑惑:在Python中,函数参数传递是传值,还是传引用呢?
看下面两段代码:
def foo(arg):
arg = 5
print(arg) x = 1
foo(x) # 输出5
print(x) # 输出1
def foo(arg):
arg.append(3) x = [1, 2]
print(x) # 输出[1, 2]
foo(x)
print(x) # 输出[1, 2, 3]
看完第一段代码,会有人说这是值传递,因为函数并没有改变x的值;看完第二段代码,又会有人说这是传引用,因为函数改变了x的内容。
那么,Python中的函数到底是传值还是传引用呢?看下面的解释。
一、变量和对象
我们需要先知道Python中的“变量”与C/C++中“变量”是不同的。
在C/C++中,当你初始化一个变量时,就是声明一块存储空间并写入值。相当于把一个值放入一个盒子里:
int a = 1;
现在”a”盒子里放了一个整数1,当给变量a赋另外一个值时会替换盒子a里面的内容:
a = 2;
当你把变量a赋给另外一个变量时,会拷贝a盒子中的值并放入一个新的“盒子”里:
int b = a;
在Python中,一个变量可以说是内存中的一个对象的“标签”或“引用”:
a = 1
现在变量a指向了内存中的一个int型的对象(a相当于对象的标签)。如果给a重新赋值,那么“标签”a将会移动并指向另一个对象:
a = 2
原来的值为1的int型对象仍然存在,但我们不能再通过a这个标识符去访问它了(当一个对象没有任何标签或引用指向它时,它就会被自动释放)。如果我们把变量a赋给另一个变量,我们只是给当前内存中对象增加一个“标签”而已:
b = a
综上所述,在Python中变量只是一个标签一个标识符,它指向内存中的对象。故变量并没有类型,类型是属于对象的,这也是Python中的变量可以被任何类型赋值的原因。
二、可变对象与不可变对象
在Python的基本数据类型中,我们知道numbers、strings和tuples是不可更改的对象,而list、dict是可以修改的对象。那么可变与不可变有什么区别呢?看下面示例:
a = 1 # a指向内存中一个int型对象
a = 2 # 重新赋值
当将a重新赋值时,因为原来值为1的对象是不能改变的,所以a会指向一个新的int对象,其值为2。(如上面的图示)
lst = [1, 2] # lst指向内存中一个list类型的对象
lst[0] = 2 # 重新赋值lst中第一个元素
因为list类型是可以改变的,所以第一个元素变更为2。更确切的说,lst的第一个元素是int型,重新赋值时一个新的int对象被指定给第一个元素,但是对于lst来说,它所指的列表型对象没有变,只是列表的内容(其中一个元素)改变了。
好了,到这里我们就很容易解释本文开头的两段代码了:
def foo(arg):
arg = 5
print(arg) x = 1
foo(x) # 输出5
print(x) # 输出1
上面这段代码把x作为参数传递给函数,这时x和arg都指向内存中值为1的对象。然后在函数中arg = 5时,因为int对象不可改变,于是创建一个新的int对象(值为5)并且令arg指向它。而x仍然指向原来的值为1的int对象,所以函数没有改变x变量。
def foo(arg):
arg.append(3) x = [1, 2]
print(x) # 输出[1, 2]
foo(x)
print(x) # 输出[1, 2, 3]
这段代码同样把x传递给函数foo,那么x和arg都会指向同一个list类型的对象。因为list对象是可以改变的,函数中使用append在其末尾添加了一个元素,list对象的内容发生了改变,但是x和arg仍然是指向这一个list对象,所以变量x的内容发生了改变。
那么Python中参数传递是传值,还是传引用呢?准确的回答:都不是。之所以不是传值,因为没有产生复制,而且函数拥有与调用者同样的对象。而似乎更像是C++的传引用?但是有时却不能改变实参的值。只能这样说:对于不可变的对象,它看起来像C++中的传值方式;对于可变对象,它看起来像C++中的按引用传递。
附: Everything is Object in Python
Python使用对象模型来储存数据,任何类型的值都是一个对象。所有的python对象都有3个特征:身份、类型和值。
- 身份:每一个对象都有自己的唯一的标识,可以使用内建函数id()来得到它。这个值可以被认为是该对象的内存地址。
- 类型:对象的类型决定了该对象可以保存的什么类型的值,可以进行什么操作,以及遵循什么样的规则。type()函数来查看python 对象的类型。
- 值:对象表示的数据项。
>>> a = 1
>>> id(a)
140068196051520
>>> b = 2
>>> id(b)
140068196051552
>>> c = a
>>> id(c)
140068196051520
>>> c is a
True
>>> c is not b
True
运算符is、is not就是通过id()的返回值(即身份)来判定的,也就是看它们是不是同一个对象的“标签”。
(全文完)
Python FAQ1:传值,还是传引用?的更多相关文章
- python 参数传递 传值还是传引用
个人推测结论: 可变对象传引用,不可变对象传值 python里的变量不同于c中地址储值模型 a=100 b=100 print(id(a),id(b),a==b,a is b) #8790877986 ...
- python函数传参是传值还是传引用?
首先还是应该科普下函数参数传递机制,传值和传引用是什么意思? 函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题.基本的参数传递机制有两种:值传递和引用传 ...
- python传参是传值还是传引用
在此之前先来看看变量和对象的关系:Python 中一切皆为对象,数字是对象,列表是对象,函数也是对象,任何东西都是对象.而变量是对象的一个引用(又称为名字或者标签),对象的操作都是通过引用来完成的.例 ...
- python中给函数传参是传值还是传引用
首先还是应该科普下函数参数传递机制,传值和传引用是什么意思? 函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题.基本的参数传递机制有两种:值传递和引用传 ...
- Python的传值和传址与copy和deepcopy
1.传值和传址 传值就是传入一个参数的值,传址就是传入一个参数的地址,也就是内存的地址(相当于指针).他们的区别是如果函数里面对传入的参数重新赋值,函数外的全局变量是否相应改变,用传值传入的参数是不会 ...
- java集合中的传值和传引用
在学习java集合过程中发现了传值和传引用的区别: 我们来看下面两句话 ●java集合就像一种容器,我们可以把多个对象(实际上是对象的引用),丢进该容器.(来自疯狂java讲义) ●当使用Iterat ...
- Go语言的传值与传引用
Go语言里的传值与传引用大致与C语言中一致,但有2个特例,map和channel默认传引用,也就是说可以直接修改传入的参数,其他的情况如果不用指针的话,传入的都是参数的副本,在函数中修改不会改变调用者 ...
- java中的传值与传引用
java函数中的传值和传引用问题一直是个比较“邪门”的问题,其实java函数中的参数都是传递值的,所不同的是对于基本数据类型传递的是参数的一份拷贝,对于类类型传递的是该类参数的引用的拷贝,当在函数体中 ...
- java 函数形参传值和传引用的区别
java方法中传值和传引用的问题是个基本问题,但是也有很多人一时弄不清. (一)基本数据类型:传值,方法不会改变实参的值. public class TestFun { public static v ...
- JavaScript系列----数据类型以及传值和传引用
1.简单数据类型 在JavaScript中简单数据类型分为5种.分别为 Undefined, Null,Boolean,Number,String. Undefined类型Undefined类型只有一 ...
随机推荐
- poj1923 Fourier's Lines
思路: 记忆化搜索. n条直线的交点方案数 =(n-r)条平行线与r条直线交叉的交点数+r条直线本身的交点方案 =(n-r)*r+r条直线之间本身的交点方案数(0<r<=n) 于是可以枚举 ...
- Selenium基于Python web自动化基础二 -- 免登录、等待及unittest单元测试框架
一.免登录在进行测试的过程中难免会遇到登录的情况,给测试工作添加了工作量,本文仅提供一些思路供参考解决方式:手动请求中添加cookies.火狐的profile文件记录信息实现.人工介入.万能验证码.去 ...
- 全3D模具设计自动化解決方案
- 远程图形界面:VncServer与KDE桌面远程连接
强烈不建议putty+xming的工作方式,太慢了,且界面也不是特别友好. 原文:vncserver与KDE远程连接 建议:不过还是建议使用Xshell,使用 ...
- Java软件开发中迭代的含义
软件开发中,各个开发阶段不是顺序执行的,而各个阶段都进行迭代并行执行的,然后在进入下一个阶段的开发. 这样对于开发中的需求变化,及人员变动都能得到更好的适应. 软件开发过程汇总迭代模型如下图所示:
- 已集成 VirtIO驱动windows server 2012, 2008, 2003的ISO镜像下载
已集成 VirtIO驱动简体中文windows server 2012, 2008, 2003系统ISO镜像下载地址. 适用于上传自定义ISO并且使用 VirtIO驱动的kvm架构vps,vultr家 ...
- Filesystem Hierarchy Standard (Unix, Linux etc)
http://www.pathname.com/fhs/ /boot -- Static files of the boot loader Purpose: contains everything r ...
- (转) 淘淘商城系列——Redis集群的搭建
http://blog.csdn.net/yerenyuan_pku/article/details/72860432 本文我将带领大家如何搭建Redis集群.首先说一下,为何要搭建Redis集群.R ...
- CAD把当前图上数据保存为一个二进流对象(com接口VB语言)
主要用到函数说明: MxDrawXCustomFunction::WriteBinStreamEx 把当前图上数据保存为一个二进流对象,详细说明如下: 参数 说明 LPCTSTR pszPasswor ...
- UVA - 12661 Funny Car Racing (Dijkstra算法)
题目: 思路: 把时间当做距离利用Dijkstra算法来做这个题. 前提:该结点e.c<=e.a,k = d[v]%(e.a+e.b); 当车在这个点的1处时,如果在第一个a这段时间内能够通过且 ...