Python的对象传递与Copy函数使用详解


Posted in Python onDecember 26, 2019

1、对象引用的传值或者传引用

Python中的对象赋值实际上是简单的对象引用。也就是说,当你创建一个对象,然后把它赋值给另一个变量的时候,Python并没有拷贝这个对象,而是拷贝了这个对象的引用。这种方式相当于值传递和引用传递的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“引用传递”来赋值。如果函数收到的是一个不可变变量(比如数字、字符串或者元祖)的引用,就不能直接修改原始对象--相当于通过“值传递”来赋值。

先看一个数字传递的例子:

>>> def test(a):
...     print id(a)
...     a = a + 1
...     print id(a)
...     return a
...
>>> b =19
>>> id(b)
38896272
>>> c = test(b)
38896272
38896260
>>> id(b)
38896272
>>> b
19

id函数可以获得对象的内存地址.

很明显从上面例子可以看出,将b变量作为参数传递给了test函数,传递了b的一个引用,把b的地址传递过去了,所以在函数内获取的变量a的地址跟变量b的地址是一样的,但是在函数内,对a进行赋值运算,a的值从19变成了20,实际上19和20所占的内存空间都还是存在的,赋值运算后,a指向20所在的内存。而b仍然指向19所在的内存,所以后面打印b,其值还是19.

另外,关于整数变量的id,所有在[-5,256]范围内的整数,python是提前分配好空间放在数组里初始化好的,所以两个变量如果是相同的小整数,对象都是最开始初始化的那一个,所以两个变量的id是一样的。

所有在[-5,256]范围外的整数的话,每次都会新建一个的,所以id会改变

>>> a = 256
>>> id(a)
43340980
>>> b = 256
>>> id(b)
43340980   # a和b的id相同
>>> a = 257
>>> id(a)
44621040
>>> b = 257
>>> id(b)
44620908   # a和b的id不同
>>> a = -5
>>> id(a)
43338160
>>> b = -5
>>> id(b)
43338160
>>> a = -6
>>> id(a)
44621184
>>> b = -6
>>> id(b)
44621112

再看一个列表传递的例子:

>>> def test(a):
...   print id(a)
...   a[0] = 100
...   print id(a)
...   return a
...
>>> b = [7,8,9,10]
>>> id(b)
46408088
>>> c = test(b)
46408088
46408088
>>> id(b)
46408088
>>> b
[100, 8, 9, 10]

从上面例子可以看出,将b变量作为参数传递给了test函数,传递了b的一个引用,把b的地址传递过去了,所以在函数内获取的变量a的地址跟变量b的地址是一样的,但是在函数内,对a进行赋值运算,a[0]的值从7变成了100,但是a的id并没有发生变化,还是和变量b的地址是一样的,所以后面打印b,b[0]的值也从7变成了100.

2、关于可变变量和不可变变量:

这里的可变不可变,是指内存中的那块内容(value)是否可以被改变

不可变变量:

number: int, float, str, 元组。--指它的部分(比如element,attribute不能改变)不能改变;并不是整体不可变。另外,Python所有变量皆对象。int也是一个对象。

>>> a = 10000
>>> id(a)
46573412
>>> a = 10000000
>>> id(a)
46573460   #数字变量重新赋值后,id发生了变化
>>> s = 'abc'
>>> s[1] = d   #字符串变量中的某一个元素不能进行改变
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> id(s)
39103328
>>> s = 'ttt'
>>> id(s)    #字符串变量进行重新赋值后,id发生了变化
46425368

从上面的例子中可以看出,数字变量、字符变量在重新赋值后,id都会发生变化,这是因为不可变变量的赋值是通过在内存中新申请一块区域,把新的值存储到该区域,然后改变不可变变量的引用,指向新的内存区域,从而改变了不可变变量的值。

可变变量

class, class instance;列表,dict,

例1.可变变量中元素的赋值

>>> list = [1,2,3]
>>> id(list)
45486568
>>> for i in list:
...   print id(i)
40207208
40207196
40207184
>>> list[0] = 0
>>> id(list)
45486568   # 变量的id并没有发生改变
>>> for i in list:
...   print id(i)
40207220    # 该元素的id发生了改变
40207196
40207184
例2.可变变量的赋值
>>> list = [1,2,3]
>>> id(list)
43783392
>>> list =[2,3,5] 
>>> id(list)  # 该变量的id发生了改变
44454296

从上面的例子可以看出,列表中的元素重新赋值,整个列表的id不会发生改变,但是该元素的id会发生该生。因为列表中存储的其实是对各个元素的引用,所以对该元素赋值的结果就是元素的引用发生了改变。

总之,无论是可变变量还是不可变变量,只要对整个变量进行赋值,Python都在内存中新申请一块区域,把新的值存储到该区域,然后改变不可变变量的引用,指向新的内存区域;如果可变变量中的元素进行赋值,支队导致该元素的变化,不会导致父对象的变化。

3、 深拷贝 Vs 浅拷贝

copy.copy() 浅拷贝

copy.deepcopy() 深拷贝

浅拷贝是新创建了一个跟原对象一样的类型,但是其内容是对原对象元素的引用。这个拷贝的对象本身是新的,但内容不是。如果原对象的元素包含不是基本数据结构,而是list、dict或者对象的话,那么原对象或者拷贝对象改变list、dict或者对象里面的内容的话,会导致二者同时发生改变。

深拷贝则是对原对象的完全拷贝,包含对象里面的子对象的拷贝,因此拷贝对象和原对象二者是完全独立,任何一方的改变对另外一方都不会产生任何的影响。

>>> import copy
>>> list = [1, 2, [3, 4]]
>>> copy_list = copy.copy(list)
>>> deepcopy_list = copy.deepcopy(list)
>>>
>>> id(list)
44454296
>>> id(copy_list)
44515736
>>> id(deepcopy_list)
44455736
>>>
>>> for k in list:
...   print id(k)
43338088 43338076 44430120
>>> for k in copy_list:
...   print id(k)
43338088 43338076 44430120  # copy对象的内容和原对象完全一样
>>> for k in deepcopy_list:
...   print id(k)
43338088 43338076 44457456  # deepcopy对象的内容和原对象有区别:列表元素的id不一样;数字元素id一样,原因是所有相同数字的变量的引用都是一样的。
>>> 
>>> list[2][0] = 30
>>> list
[1, 2, [30, 4]]
>>> copy_list
[1, 2, [30, 4]]   # 原对象的子对象中的元素发生改变后,会导致copy对象发生同样的改变  
>>> deepcopy_list
[1, 2, [3, 4]]    #原对象的子对象中的元素发生改变后,不会导致deepcopy对象发生同样的改变

以上这篇Python的对象传递与Copy函数使用详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python写的一个squid访问日志分析的小程序
Sep 17 Python
python获取远程图片大小和尺寸的方法
Mar 26 Python
Python实现将不规范的英文名字首字母大写
Nov 15 Python
python:pandas合并csv文件的方法(图书数据集成)
Apr 12 Python
python 巧用正则寻找字符串中的特定字符的位置方法
May 02 Python
python字典值排序并取出前n个key值的方法
Oct 17 Python
pytorch查看torch.Tensor和model是否在CUDA上的实例
Jan 03 Python
pytorch VGG11识别cifar10数据集(训练+预测单张输入图片操作)
Jun 24 Python
PyTorch中Tensor的数据类型和运算的使用
Sep 03 Python
python实现人工蜂群算法
Sep 18 Python
opencv+pyQt5实现图片阈值编辑器/寻色块阈值利器
Nov 13 Python
总结三种用 Python 作为小程序后端的方式
May 02 Python
Python pandas库中的isnull()详解
Dec 26 #Python
python dataframe NaN处理方式
Dec 26 #Python
python实现大战外星人小游戏实例代码
Dec 26 #Python
Python数据存储之 h5py详解
Dec 26 #Python
Python 使用 prettytable 库打印表格美化输出功能
Dec 26 #Python
Python实现图片识别加翻译功能
Dec 26 #Python
opencv resize图片为正方形尺寸的实现方法
Dec 26 #Python
You might like
PHP下使用CURL方式POST数据至API接口的代码
2013/02/14 PHP
PHP实现的观察者模式实例
2017/06/21 PHP
解析JavaScript中instanceof对于不同的构造器或许都返回true
2013/12/03 Javascript
js实现超简单的展开、折叠目录代码
2015/08/28 Javascript
js实现拖拽效果(构造函数)
2015/12/14 Javascript
Bootstrap每天必学之轮播(Carousel)插件
2016/04/25 Javascript
jQuery+HTML5+CSS3制作支持响应式布局时间轴插件
2016/08/10 Javascript
json数据处理及数据绑定
2017/01/25 Javascript
js中获取键盘按下键值event.keyCode、event.charCode和event.which的兼容性详解
2017/03/15 Javascript
JS实现队列的先进先出功能示例
2017/05/10 Javascript
[js高手之路]寄生组合式继承的优势详解
2017/08/28 Javascript
在Vue项目中使用d3.js的实例代码
2018/05/01 Javascript
微信小程序实现留言板
2018/10/31 Javascript
解决layui数据表格排序图标被超出的表头挤出去的问题
2019/09/19 Javascript
javascript-hashchange事件和历史状态管理实例分析
2020/04/18 Javascript
vue项目在webpack2实现移动端字体自适配功能
2020/06/02 Javascript
查找Vue中下标的操作(some和findindex)
2020/08/12 Javascript
再也不怕 JavaScript 报错了,怎么看怎么处理都在这儿
2020/12/09 Javascript
Python笔记(叁)继续学习
2012/10/24 Python
pandas数值计算与排序方法
2018/04/12 Python
python去除拼音声调字母,替换为字母的方法
2018/11/28 Python
在python3中使用shuffle函数要注意的地方
2020/02/28 Python
Python限制内存和CPU使用量的方法(Unix系统适用)
2020/08/04 Python
详解Open Folder as PyCharm Project怎么添加的方法
2020/12/29 Python
利用SVG和CSS3来实现一个炫酷的边框动画
2015/07/22 HTML / CSS
使用postMessage让 iframe自适应高度的方法示例
2019/10/08 HTML / CSS
NFL官方在线商店:NFLShop
2020/07/29 全球购物
商务英语毕业生自荐信范文
2013/11/08 职场文书
大学生专科学习生活的自我评价
2013/12/07 职场文书
信息技术课后反思
2014/04/27 职场文书
综合素质自我评价怎么写
2014/09/14 职场文书
乡镇党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
服务行业标语口号
2015/12/26 职场文书
小学教师暑期培训心得体会
2016/01/09 职场文书
jdbc使用PreparedStatement批量插入数据的方法
2021/04/27 MySQL
python利用while求100内的整数和方式
2021/11/07 Python