深入浅析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实例分享:快速查找出被挂马的文件
Jun 08 Python
python中的lambda表达式用法详解
Jun 22 Python
Python编程之基于概率论的分类方法:朴素贝叶斯
Nov 11 Python
pandas.DataFrame选取/排除特定行的方法
Jul 03 Python
python遍历文件夹,指定遍历深度与忽略目录的方法
Jul 11 Python
在python中使用xlrd获取合并单元格的方法
Dec 26 Python
Python configparser模块操作代码实例
Jun 08 Python
python基本算法之实现归并排序(Merge sort)
Sep 01 Python
PyCharm 光标变成黑块的解决方式
Feb 06 Python
【超详细】八大排序算法的各项比较以及各自特点
Mar 31 Python
python xlwt模块的使用解析
Apr 13 Python
Python first-order-model实现让照片动起来
Jun 25 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
用 Composer构建自己的 PHP 框架之构建路由
2014/10/30 PHP
PHP+APACHE实现网址伪静态
2015/02/22 PHP
php操作redis缓存方法分享
2015/06/03 PHP
Laravel使用支付宝进行支付的示例代码
2017/08/16 PHP
PHP实现可添加水印与生成缩略图的图片处理工具类
2018/01/16 PHP
详解PHP多个进程配合redis的有序集合实现大文件去重
2019/03/06 PHP
laravel实现图片上传预览,及编辑时可更换图片,并实时变化的例子
2019/11/14 PHP
jquery.tmpl JQuery模板插件
2011/10/10 Javascript
JavaScript高级程序设计 阅读笔记(十二) js内置对象Math
2012/08/14 Javascript
jquery实现table鼠标经过变色代码
2013/09/25 Javascript
一个简单的动态加载js和css的jquery代码
2014/09/01 Javascript
JavaScript实现查找字符串中第一个不重复的字符
2014/12/29 Javascript
jQuery获取剪贴板内容的方法
2016/06/16 Javascript
微信和qq时间格式模板实例详解
2016/10/21 Javascript
jQuery 移动端拖拽(模块化开发,触摸事件,webpack)
2016/10/28 Javascript
Angularjs渲染的 using 指令的星级评分系统示例
2017/11/09 Javascript
深入浅析JS中的严格模式
2018/06/04 Javascript
浅谈从React渲染流程分析Diff算法
2018/09/08 Javascript
微信小程序实现单列下拉菜单效果
2019/04/25 Javascript
jquery.pager.js实现分页效果
2019/07/29 jQuery
手把手教你实现 Promise的使用方法
2020/09/02 Javascript
[04:52]DOTA2亚洲邀请赛附加赛 TOP10精彩集锦
2015/01/29 DOTA
[54:10]完美世界DOTA2联赛PWL S2 Magma vs FTD 第二场 11.29
2020/12/03 DOTA
Python 返回汉字的汉语拼音
2009/02/27 Python
Python基于datetime或time模块分别获取当前时间戳的方法实例
2019/02/19 Python
Python简直是万能的,这5大主要用途你一定要知道!(推荐)
2019/04/03 Python
python中删除某个元素的方法解析
2019/11/05 Python
keras中的loss、optimizer、metrics用法
2020/06/15 Python
如何Tkinter模块编写Python图形界面
2020/10/14 Python
保护环境建议书300字
2014/05/13 职场文书
工作疏忽检讨书500字
2014/10/26 职场文书
放假通知范文
2015/04/14 职场文书
地道战观后感400字
2015/06/04 职场文书
大学生饮品店创业计划书范文
2019/07/10 职场文书
Redis IP地址的绑定的实现
2021/05/08 Redis
总结Python常用的魔法方法
2021/05/25 Python