python深拷贝和浅拷贝之简单分析



title: python 深拷贝和浅拷贝

tags: python,copy,deepcopy

grammar_cjkRuby: true

---

python 深拷贝和浅拷贝

python的变量的赋值都是引用

把一个变量赋值给一个变量,不是拷贝这个对象,而是拷贝这个变量的引用

  1. 直接赋值

    传递的是这个变量的引用

  2. 浅拷贝

    拷贝的是这个变量的引用,会产生新的对象

    浅拷贝会产生一个新的对象,但是浅拷贝的内容还是原有对象的引用

    看下面的例子

浅拷贝
import copy
a = [1, 2, 3, 4 ,5]
b = copy.copy(a)
print id(a)
140637017675968
print id(b)
140637017452416
print [id(item) for item in a]
[30363992, 30363968, 30363944, 30363920, 30363896]
print [id(item) for item in b]
[30363992, 30363968, 30363944, 30363920, 30363896]

我们可以看到,copy.copy这个浅拷贝的操作,产生了一个新的对象

因此,id(a) ,id(b)是不同的

但是,浅拷贝对于所拷贝对象中的各个元素,只会使用这些元素的引用,并不会再继续产生新的对象

所以,两者各个元素的id是相同的

再看个浅拷贝的例子

import copy
a = [1, 2, 3, 4 ,5]
b = copy.copy(a)
print id(a)
140337638905904
print id(b)
140337638904824
a.append(6)
print a
[1, 2, 3, 4, 5, 6]
print id(a)
140337638905904
print b
[1, 2, 3, 4, 5]
print id(b)
140337638904824

可以看到,因为浅拷贝也是创建了一个新的对象,所以a 和 a的浅拷贝b,是两个不同的对象

所以给对象aj添加元素,并不会对b产生影响

再来看一个浅拷贝的例子 这个浅拷贝的例子对于其拷贝的对象也产生了影响,为什么呢?

import copy
 a = [1, 2, 3, [1]]
print id(a)
140063950885808
b = copy.copy(a)
print id(b)
140063949633512
print [id(item) for item in a]
[29266264, 29266240, 29266216, 140063949688416]
print [id(item) for item in b]
[29266264, 29266240, 29266216, 140063949688416]
a[3].append(2)
print a
[1, 2, 3, [1, 2]]
 print b
[1, 2, 3, [1, 2]]

可以看到,这个例子中,a对象和其拷贝产生的对象b

首先,浅拷贝,新建了一个对象b

a 和 b是两个不同的对象

由于浅拷贝,新建的对象b的各个元素其实是原对象a的各个元素的引用(这是和上一个例子不同的地方,上一个例子是原有对象新增了一个元素)

这个例子是原有对象对于其最后一个元素(也是列表类型)新增了一个元素

因为 a 和b 两个对象的各个元素其实是一样的(b的各个元素其实是a的各个元素的引用),所以a 的某个元素的变化会让b一样的变化

我们再看一个浅拷贝的例子

import copy
a = [1, 2, 3, [1]]
print id(a)
140063950885808
b = copy.copy(a)
print id(b)
140063949633512
print [id(item) for item in a]
[29266264, 29266240, 29266216, 140063949688416]
print [id(item) for item in b]
[29266264, 29266240, 29266216, 140063949688416]
a[3].append(2)
print a
[1, 2, 3, [1, 2]]
print b
[1, 2, 3, [1, 2]]
a[0] = 10
a
[10, 2, 3, [1, 2]]
b
[1, 2, 3, [1, 2]]
print [id(item) for item in a]
[29266048, 29266240, 29266216, 140063949688416]
print [id(item) for item in b]
[29266264, 29266240, 29266216, 140063949688416]

前面的操作都没毛病,怎么最后对于对象a的第一个元素的操作让a变化了,却没有影响到b呢?

这是因为操作的a的第一个元素是int类型,这是不可变对象,对于不可变对象的重新赋值本质上是新建一个新的对象

所以,其实这样操作后a的第一个元素对应的对象已经不是原来的对象了,当然不会影响到b

深拷贝
import copy
a = [1, 2, 3, 4, [1]]
b = copy.deepcopy(a)
print [id(item) for item in a]
[40378712, 40378688, 40378664, 40378640, 140313123501048]
print [id(item) for item in b]
[40378712, 40378688, 40378664, 40378640, 140313122753568]
a[4].append(2)
a
[1, 2, 3, 4, [1, 2]]
b
[1, 2, 3, 4, [1]]

在上面,我们可以看到,深拷贝,对于a 的 a[4] 即一个可变对象(list类型)而言,是产生了一个新的对象,而不是像浅拷贝一样,只是原对象元素的引用

因此,原对象的变化,不会引起拷贝对象的变化

总结:

对于浅拷贝,深拷贝来说,如果拷贝对象的元素是不可变类型(或者说不可变对象)

则无论浅拷贝,深拷贝,对原有对象的改变,都不会影响到拷贝的对象的这个元素

因为,不可变类型的更改,其实是新建了一个对象,自然不会影响到原有对象

当被拷贝对象含有可变类型的元素的时候,对于原有对象的这个可变类型的元素的更改:

浅拷贝,会影响到被拷贝对象

深拷贝,不会影响到被拷贝对象,因为深拷贝对于不可变类型的元素,是产生了一个新的对象来复制这个元素的

所以,如果希望复制一份原有对象,不被影响,需要使用深拷贝

原文地址:https://www.cnblogs.com/haozike/p/python_copy_and_deepcopy.html

时间: 2024-11-06 02:33:32

python深拷贝和浅拷贝之简单分析的相关文章

完全理解python深拷贝和浅拷贝

import copya = [1, 2, 3, 4, ['a', 'b']]  #原始对象b = a  #赋值,传对象的引用c = copy.copy(a)  #对象拷贝,浅拷贝d = copy.deepcopy(a)  #对象拷贝,深拷贝a.append(5)  #修改对象aa[4].append('c')  #修改对象a中的['a', 'b']数组对象print 'a = ', aprint 'b = ', bprint 'c = ', cprint 'd = ', d 输出结果:a = 

Python 深拷贝和浅拷贝

Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介绍一下这些概念之间的差别. 对象赋值 直接看一段代码: will=["Will",28,["Python","C#","JavaScript"]] wilber=will print id(will) print will print [id(x) for x in will] print id

Python深拷贝和浅拷贝

1. Python引用计数[ http://blog.chinaunix.net/uid-26602509-id-3506965.html ] 1.1 引用计数机制 引用计数是计算机编程语言中的一种内存管理技术,是指将资源(可以是对象.内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的过程.使用引用计数技术可以实现自动资源管理的目的.同时引用计数还可以指使用引用计数技术回收未使用资源的垃圾回收算法. 当创建一个对象的实例并在堆上申请内存时,对象的引用计数就为1,在其他对象

python 深拷贝和浅拷贝之可变和不可变对象总结

了解深拷贝和浅拷贝之前先要理解可变与不可变对象 python只允许使用引用传递,有可变对象和不可变对象,可变对象:list,dict.不可变对象有:int,string,float,tuple Python int,string,float,tuple不可变举栗子: def int_object(): i = 89 j = 89 print(id(89)) print('i id:' + str(id(i))) print('j id:' + str(id(j))) print(i is j)

python 深拷贝与浅拷贝

浅拷贝的方式有: lst=[1,2,3] (1)直接赋值: lst_cp = lst (2)for循环遍历生成:lst_cp= [i for i in lst] (3)copy模块下,copy.copy仍为浅拷贝 深拷贝的方式 (1)借助copy模块 >>> import copy >>> lst_cp = copy.deepcopy(lst) 以上方法的测试: 注意:因为string类型是不可变类型,所以修改string元素时会新创建一个地址空间放置数据 (1)直接赋

Python 深拷贝和浅拷贝的区别

python的复制,深拷贝和浅拷贝的区别    在python中,对象赋值实际上是对象的引用.当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用 一般有三种方法,        alist=[1,2,3,["a","b"]] (1)直接赋值,传递对象的引用而已,原始列表改变,被赋值的b也会做相同的改变 >>> b=alist        >>> print b        

python深拷贝与浅拷贝

浅拷贝:b=copy.copy(a),对引用的拷贝,只拷贝父对象,所以id(b)不等于id(a),但对象内部资源依然引用,内部id(b[0])等于id(a[0]),id(b[4])等于id(a[4]) 深拷贝:c=copy.deepcopy(a),对对象资源的拷贝,id(c)不等于id(a),内部id(c[0])等于id(a[0]),id(c[4])不等于id(a[4]) 注意:因为数字是不可变量,所以数字的id不变,无论深拷贝还是浅拷贝,id(b[0]).id(c[0])都等于id(a[0])

python深拷贝和浅拷贝的区别

首先深拷贝和浅拷贝都是对象的拷贝,都会生成一个看起来相同的对象,他们本质的区别是拷贝出来的对象的地址是否和原对象一样,也就是地址的复制还是值的复制的区别. 深拷贝和浅拷贝需要注意的地方是可变元素的拷贝,在浅拷贝时:拷贝出来的新对象的地址和原对象是不一样的,但是新对象里面的可变元素(如列表)的地址和原对象里的可变元素的地址是相同的,也就是说浅拷贝它拷贝的是浅层次的数据结构(不可变元素),对象里的可变元素作为深层次的数据结构并没有被拷贝到新地址里面去,而是和原对象里的可变元素指向同一个地址,所以在新

图解Python深拷贝和浅拷贝

Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介绍一下这些概念之间的差别. 对象赋值 直接看一段代码: will = ["Will", 28, ["Python", "C#", "JavaScript"]] wilber = will print id(will) print will print [id(ele) for ele in wi