深入浅析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中的内存泄漏
Apr 23 Python
python字符串中的单双引
Feb 16 Python
Python 多进程和数据传递的理解
Oct 09 Python
Python实现简单石头剪刀布游戏
Jan 20 Python
Python中dict和set的用法讲解
Mar 28 Python
解决pycharm运行程序出现卡住scanning files to index索引的问题
Jun 27 Python
Python学习笔记之列表和成员运算符及列表相关方法详解
Aug 22 Python
Python3 无重复字符的最长子串的实现
Oct 08 Python
python运用pygame库实现双人弹球小游戏
Nov 25 Python
PyTorch 随机数生成占用 CPU 过高的解决方法
Jan 13 Python
Python中的np.argmin()和np.argmax()函数用法
Jun 02 Python
opencv用VS2013调试时用Image Watch插件查看图片
Jul 26 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警告Cannot use a scalar value as an array的解决方法
2012/01/11 PHP
PHP模板引擎smarty详细介绍
2015/05/26 PHP
php实现在多维数组中查找特定value的方法
2015/07/29 PHP
linux下php上传文件注意事项
2016/06/11 PHP
PHP中FTP相关函数小结
2016/07/15 PHP
php使用pthreads v3多线程实现抓取新浪新闻信息操作示例
2020/02/21 PHP
基于Jquery的淡入淡出的特效基础练习
2010/12/13 Javascript
jquery实现滑动图片自己测试的例子
2013/11/05 Javascript
node.js开机自启动脚本文件
2014/12/24 Javascript
js+ajax实现获取文件大小的方法
2015/12/08 Javascript
Javascript中indexOf()和lastIndexOf应用方法实例
2016/08/24 Javascript
简单理解js的冒泡排序
2016/12/19 Javascript
JS百度地图搜索悬浮窗功能
2017/01/12 Javascript
JS实现京东首页之页面顶部、Logo和搜索框功能
2017/01/12 Javascript
BootStrap Fileinput插件和Bootstrap table表格插件相结合实现文件上传、预览、提交的导入Excel数据操作步骤
2017/08/07 Javascript
vue router-link传参以及参数的使用实例
2017/11/10 Javascript
vue实现学生录入系统之添加删除功能
2018/07/11 Javascript
图文讲解用vue-cli脚手架创建vue项目步骤
2019/02/12 Javascript
js设计模式之代理模式及订阅发布模式实例详解
2019/08/15 Javascript
js中addEventListener()与removeEventListener()用法案例分析
2020/03/02 Javascript
Python中的面向对象编程详解(上)
2015/04/13 Python
Python中.py文件打包成exe可执行文件详解
2017/03/22 Python
Python实现的堆排序算法原理与用法实例分析
2017/11/22 Python
解决pandas使用read_csv()读取文件遇到的问题
2018/06/15 Python
Python中pandas dataframe删除一行或一列:drop函数详解
2018/07/03 Python
Python实现求两个数组交集的方法示例
2019/02/23 Python
解决python web项目意外关闭,但占用端口的问题
2019/12/17 Python
浅析Python 多行匹配模式
2020/07/24 Python
CSS3感应鼠标的背景闪烁和图片缩放动画效果
2014/05/14 HTML / CSS
瑞典Happy Socks美国官网:购买色彩斑斓的快乐袜子
2016/10/19 全球购物
如何写一封打动人心的求职信
2014/02/17 职场文书
五四青年节的活动方案
2014/08/20 职场文书
社区个人对照检查材料(群众路线)
2014/09/26 职场文书
公司费用报销管理制度
2015/08/04 职场文书
浅谈PHP7中的一些小技巧
2021/05/29 PHP
mysql定时自动备份数据库的方法步骤
2021/07/07 MySQL