深入浅析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 正则表达式操作指南
May 04 Python
python检测远程udp端口是否打开的方法
Mar 14 Python
Python数据类型详解(二)列表
May 08 Python
Python 模拟登陆的两种实现方法
Aug 10 Python
Python实现的随机森林算法与简单总结
Jan 30 Python
Python实现的拉格朗日插值法示例
Jan 08 Python
Django保护敏感信息的方法示例
May 09 Python
在Python中使用turtle绘制多个同心圆示例
Nov 23 Python
python代码xml转txt实例
Mar 10 Python
python 通过 pybind11 使用Eigen加速代码的步骤
Dec 07 Python
教你使用Pandas直接核算Excel中快递费用
May 12 Python
python神经网络Xception模型
May 06 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中设置、使用、删除Cookie的解决方法
2013/05/06 PHP
PHP获取栏目的所有子级和孙级栏目的ID号示例
2014/04/01 PHP
PHP实现可自定义样式的分页类
2016/03/29 PHP
Laravel路由设定和子路由设定实例分析
2016/03/30 PHP
PHP实现十进制数字与二十六进制字母串相互转换操作示例
2018/08/10 PHP
tp5框架基于Ajax实现列表无刷新排序功能示例
2020/02/10 PHP
extJs 下拉框联动实现代码
2010/04/09 Javascript
验证javascript中Object和Function的关系的三段简单代码
2010/06/27 Javascript
基于jquery的一个OutlookBar类,动态创建导航条
2010/11/19 Javascript
javascript实现页面内关键词高亮显示代码
2014/04/03 Javascript
微信小程序开发一键登录 获取session_key和openid实例
2016/11/23 Javascript
Angularjs 手写日历的实现代码(不用插件)
2017/10/18 Javascript
JS中使用react-tooltip插件实现鼠标悬浮显示框
2019/05/15 Javascript
Vue实现商品飞入购物车效果(电商项目)
2019/11/26 Javascript
js判断一个对象是数组(函数)的方法实例
2019/12/19 Javascript
vue中的使用token的方法示例
2020/03/10 Javascript
webstorm建立vue-cli脚手架的傻瓜式教程
2020/09/22 Javascript
python高并发异步服务器核心库forkcore使用方法
2013/11/26 Python
Python实现监控程序执行时间并将其写入日志的方法
2015/06/30 Python
Python脚本实现Web漏洞扫描工具
2016/10/25 Python
Python OpenCV中的resize()函数的使用
2019/06/20 Python
浅谈pytorch中的BN层的注意事项
2020/06/23 Python
python3中布局背景颜色代码分析
2020/12/01 Python
Python爬虫回测股票的实例讲解
2021/01/22 Python
用CSS3实现瀑布流布局的示例代码
2017/11/10 HTML / CSS
塔吉特百货公司官网:Target
2017/04/27 全球购物
请问如下代码执行后a和b的值分别是什么
2016/05/05 面试题
RIP版本1跟版本2的区别
2013/12/30 面试题
医学专业毕业生推荐信
2013/11/14 职场文书
后勤工作职责
2013/12/22 职场文书
初中音乐教学反思
2014/01/12 职场文书
公司合并协议书范本
2014/09/30 职场文书
客户答谢会致辞
2015/07/30 职场文书
应届毕业生的自我评价
2019/06/21 职场文书
用Python实现一个打字速度测试工具来测试你的手速
2021/05/28 Python
Nginx静态压缩和代码压缩提高访问速度详解
2022/05/30 Servers