深入浅析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 相关文章推荐
Django框架中处理URLconf中特定的URL的方法
Jul 20 Python
通过数据库对Django进行删除字段和删除模型的操作
Jul 21 Python
python基础教程之分支、循环简单用法
Jun 16 Python
TensorFlow安装及jupyter notebook配置方法
Sep 08 Python
python实现协同过滤推荐算法完整代码示例
Dec 15 Python
基于Pandas读取csv文件Error的总结
Jun 15 Python
python Pexpect 实现输密码 scp 拷贝的方法
Jan 03 Python
Python字典的基本用法实例分析【创建、增加、获取、修改、删除】
Mar 05 Python
python傅里叶变换FFT绘制频谱图
Jul 19 Python
django rest framework vue 实现用户登录详解
Jul 29 Python
python sqlite的Row对象操作示例
Sep 11 Python
python实现上传文件到linux指定目录的方法
Jan 03 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部分常见问题总结
2006/10/09 PHP
php adodb连接mssql解决乱码问题
2009/06/12 PHP
浅析PHP绘图技术
2013/07/03 PHP
php.ini中的request_order推荐设置
2015/05/10 PHP
使用PHP uniqid函数生成唯一ID
2015/11/18 PHP
PHP的RSA加密解密方法以及开发接口使用
2018/02/11 PHP
Jquery ui css framework
2010/06/28 Javascript
jquery下利用jsonp跨域访问实现方法
2010/07/29 Javascript
js 时间格式与时间戳的相互转换示例代码
2013/12/25 Javascript
JS 打印界面的CSS居中代码适用所有浏览器
2014/03/19 Javascript
jQuery定义背景动态切换效果的方法
2015/03/23 Javascript
Bootstrap框架下下拉框select搜索功能
2020/03/26 Javascript
BootStrap 图标icon符号图标glyphicons不正常显示的快速解决办法
2016/12/08 Javascript
JavaScript省市级联下拉菜单实例
2017/02/14 Javascript
很棒的vue弹窗组件
2017/05/24 Javascript
AngularJs的UI组件ui-Bootstrap之Tooltip和Popover
2018/07/13 Javascript
Javascript实现时间倒计时功能
2018/11/17 Javascript
微信小程序实现点击图片放大预览
2019/10/21 Javascript
微信小程序绑定手机号获取验证码功能
2019/10/22 Javascript
浅谈Vue.js之初始化el以及数据的绑定说明
2019/11/14 Javascript
[01:01:13]2018DOTA2亚洲邀请赛 4.5 淘汰赛 Mineski vs VG 第三场
2018/04/06 DOTA
[01:35:53]完美世界DOTA2联赛PWL S3 Magma vs GXR 第二场 12.13
2020/12/17 DOTA
python常规方法实现数组的全排列
2015/03/17 Python
Python使用matplotlib实现在坐标系中画一个矩形的方法
2015/05/20 Python
pandas计数 value_counts()的使用
2019/06/24 Python
如何基于python操作excel并获取内容
2019/12/24 Python
Python3 用什么IDE开发工具比较好
2020/11/28 Python
CSS3实现超慢速移动动画效果非常流畅无卡顿
2014/06/15 HTML / CSS
css3中新增的样式使用示例附效果图
2014/08/19 HTML / CSS
幼儿园门卫岗位职责
2014/02/14 职场文书
初中教师业务学习材料
2014/05/12 职场文书
专项法律服务方案
2014/06/11 职场文书
物理系毕业生自荐书
2014/06/13 职场文书
2014年世界艾滋病日宣传活动总结
2014/11/18 职场文书
新人入职感言
2015/07/31 职场文书
python实现剪贴板的操作
2021/07/01 Python