深入浅析Python传值与传址


Posted in Python onJuly 10, 2018

1. 传值与传址的区别

传值就是传入一个参数的值,传址就是传入一个参数的地址,也就是内存的地址(相当于指针)。他们的区别是如果函数里面对传入的参数重新赋值,函数外的全局变量是否相应改变:用传值传入的参数是不会改变的,用传址传入就会。

def a(n):
  n[2] = 100
  print(n)
  return None
def b(n):
  n += 100
  print(n)
  return None
an = [1,2,3,4,5]
bn = 10
print(an)
a(an)
print(an)
print(bn)
b(bn)
print(bn)
[1, 2, 3, 4, 5]
[1, 2, 100, 4, 5]
[1, 2, 100, 4, 5]
10
110
10

在上面的例子中,an是一个list,将其作为实参传入函数a中,a对其第三个元素进行修改。a执行结束后再次打印an,发现里面的元素的确发生变化,这就是传址操作。bn代表一个数字,将其传入函数b,并做修改,b执行结束后再次打印bn,没有变化,这是传值操作。

2. Python中传值与传址的规律

Python是不允许程序员选择采用传值还是传址的。Python参数传递采用的是“传对象引用”的方式,实际上,这种方式相当于传值和传址的一种综合。

如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于传址。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于传值。所以python的传值和传址是根据传入参数的类型来选择的。

传值的参数类型:数字,字符串,元组

传址的参数类型:列表,字典

3. 内置函数id

内置函数id,负责显示一个变量或者数据在内存中的地址,有时可以用来检测所使用的对象是否为同一个,帮助区别传值与传址操作。

但是id在有些情况下比较特殊,注意下面的例子。

a = 100
b = 200 
print(id(a))
print(id(b))
c = a
print(id(c))
print(a is c)
a += 300
print(a)
print(c)
print(a is c)
print(id(a))
print(id(c))
1549495552
1549498752
1549495552
True
400
100
False
93638128
1549495552

为了提高内存利用效率,对于一些简单的对象,如一些数值较小的int对象,python采取重用对象内存的办法。如指向a=100,c=100时,由于100作为简单的int类型且数值小,python不会两次为其分配内存,而是只分配一次,然后将a与c同时指向已分配的对象。但是当a的值发生变化时,会单独为a重新分配一个新的内存。

4. list传值与传址

list类型使用简单的赋值操作,是传址。

a = [1,2,3,4,5]
b = a
print(a)
b[2] = 333
print(a)
print(b)
print(id(a))
print(id(b))
[1, 2, 3, 4, 5]
[1, 2, 333, 4, 5]
[1, 2, 333, 4, 5]
96142472
96142472

copy函数是浅拷贝,是传值。python2中,需要import copy模块,python3可直接使用。

a = [1,2,3,4,5]
b = a.copy()
print(a)
b[2] = 333
print(a)
print(b)
print(id(a))
print(id(b))
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, 333, 4, 5]
92990536
96202632

由于copy是浅拷贝,只拷贝一层的内容,当遇到下列情况时,copy不能实现完全的传值操作。

a = [1,2,3,[10,20,30]]
b = a.copy()
print(id(a))
print(id(b))
print(id(a[3]))
print(id(b[3]))
a[3][2] = 666
print(a)
print(b)
96141704
93355400
96141768
96141768
[1, 2, 3, [10, 20, 666]]
[1, 2, 3, [10, 20, 666]]

要解决这个问题,需要使用deepcopy。python3中,直接可以使用copy()方法,但deepcopy()还是需要导入copy模块。

import copy
a = [1,2,3,[10,20,30]]
b = copy.deepcopy(a)
print(id(a))
print(id(b))
print(id(a[3]))
print(id(b[3]))
a[3][2] = 666
print(a)
print(b)
96503944
93002376
96886024
93352712
[1, 2, 3, [10, 20, 666]]
[1, 2, 3, [10, 20, 30]]

5. tuple操作

tuple元组是不可修改的,指的是其元组内容不可改。

t1 = (1,2,3)
t1[1] = 100
---------------------------------------------------------------------------
TypeError                 Traceback (most recent call last)
<ipython-input-19-9caf76a526a9> in <module>()
   1 t1 = (1,2,3)
----> 2 t1[1] = 100
TypeError: 'tuple' object does not support item assignment

但是其所指向的内存地址是可变的。

t1 = (1,2,3)
t2 = (5,6,7)
print(id(t1))
t1 += t2
print(t1)
print(id(t1))
print(id(t2))
t2 *= 3
print(t2)
print(id(t2))
96151520
(1, 2, 3, 5, 6, 7)
93048552
94080672
(5, 6, 7, 5, 6, 7, 5, 6, 7)
93656912

并不是起初的t1和t2所指向的元组内容发生了变化,而是新分配了两个元组内存,t1和t2所指向的内存发生改变。

总结

Python 相关文章推荐
使用 Python 获取 Linux 系统信息的代码
Jul 13 Python
Python中基本的日期时间处理的学习教程
Oct 16 Python
基于Python Shell获取hostname和fqdn释疑
Jan 25 Python
微信 用脚本查看是否被微信好友删除
Oct 28 Python
详解Python各大聊天系统的屏蔽脏话功能原理
Dec 01 Python
python和pygame实现简单俄罗斯方块游戏
Feb 19 Python
python调用webservice接口的实现
Jul 12 Python
Python数组拼接np.concatenate实现过程
Apr 18 Python
Keras自动下载的数据集/模型存放位置介绍
Jun 19 Python
Python更改pip镜像源的方法示例
Dec 01 Python
Python如何导出导入所有依赖包详解
Jun 08 Python
python数据处理之Pandas类型转换
Apr 28 Python
Python+OpenCV目标跟踪实现基本的运动检测
Jul 10 #Python
python3读取excel文件只提取某些行某些列的值方法
Jul 10 #Python
python读取excel指定列数据并写入到新的excel方法
Jul 10 #Python
python 常用的基础函数
Jul 10 #Python
使用pandas批量处理矢量化字符串的实例讲解
Jul 10 #Python
python opencv实现运动检测
Jul 10 #Python
python中单下划线_的常见用法总结
Jul 10 #Python
You might like
PHP中在数据库中保存Checkbox数据(2)
2006/10/09 PHP
在PHP中执行系统外部命令
2006/10/09 PHP
php中存储用户ID和密码到mysql数据库的方法
2013/02/06 PHP
php实现根据url自动生成缩略图的方法
2014/09/23 PHP
使用array_map简单搞定PHP删除文件、删除目录
2014/10/29 PHP
js资料prototype 属性
2007/03/13 Javascript
模仿JQuery sortable效果 代码有错但值得看看
2009/11/05 Javascript
jQuery实用基础超详细介绍
2013/04/11 Javascript
JavaScript中几个重要的属性(this、constructor、prototype)介绍
2013/05/19 Javascript
Nodejs学习笔记之Global Objects全局对象
2015/01/13 NodeJs
Js为表单动态添加节点内容的方法
2015/02/10 Javascript
jQuery on()方法使用技巧详解
2015/04/16 Javascript
jQuery+formdata实现上传进度特效遇到的问题
2016/02/24 Javascript
jQuery ajax方法传递中文时出现中文乱码的解决方法
2016/07/25 Javascript
有关suggest快速删除后仍然出现下拉列表的bug问题
2016/12/02 Javascript
bootstrap table分页模板和获取表中的ID方法
2017/01/10 Javascript
React props和state属性的具体使用方法
2018/04/12 Javascript
element vue Array数组和Map对象的添加与删除操作
2018/11/14 Javascript
vue实现滑动到底部加载更多效果
2020/10/27 Javascript
vue路由守卫,限制前端页面访问权限的例子
2019/11/11 Javascript
VUE动态生成word的实现
2020/07/26 Javascript
基于jquery实现彩色投票进度条代码解析
2020/08/26 jQuery
用python删除java文件头上版权信息的方法
2014/07/31 Python
python使用socket向客户端发送数据的方法
2015/04/29 Python
matlab中实现矩阵删除一行或一列的方法
2018/04/04 Python
Python 寻找局部最高点的实现
2019/12/05 Python
Python实现列表中非负数保留,负数转化为指定的数值方式
2020/06/04 Python
python用Tkinter做自己的中文代码编辑器
2020/09/07 Python
python 密码学示例——凯撒密码的实现
2020/09/21 Python
机电一体化专业应届生求职信
2013/11/27 职场文书
法定代表人资格证明书
2014/09/11 职场文书
2014年最新个人对照检查材料范文
2014/09/25 职场文书
领导班子个人对照检查剖析材料
2014/09/29 职场文书
公司慰问信范文
2015/03/23 职场文书
导游词之四川熊猫基地
2020/01/13 职场文书
Docker官方工具docker-registry案例演示
2022/04/13 Servers