在python中,对象赋值实际上是对象的引用。当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用。以下分两个思路来分别理解浅拷贝和深拷贝:
(1)利用切片操作和工厂方法list方法拷贝
(2)利用copy中的deepcopy方法进行拷贝
1、利用切片操作和工厂方法list方法拷贝
代码场景:有一个小伙jack,tom通过切片操作拷贝jack,anny通过工厂方法拷贝jack。
|
1
2
3
|
>>> jack
=
[
'jack'
, [
'age'
,
20
]]
>>> tom
=
jack[:]
>>> anny
=
list
(jack)
|
来看下三者的id值:
|
1
2
|
>>>
print
id
(jack),
id
(tom),
id
(anny)
144846988
144977164
144977388
|
从id值来看,三者是不同的对象。为tom和anny重新命名为各自的名称:
|
1
2
3
4
|
>>> tom[
0
]
=
'tom'
>>> anny[
0
]
=
'anny'
>>>
print
jack, tom, anny
[
'jack'
, [
'age'
,
20
]] [
'tom'
, [
'age'
,
20
]] [
'anny'
, [
'age'
,
20
]]
|
从这里来看一切正常,可是anny只有18岁,重新为anny定义岁数。
|
1
2
3
|
>>> anny[
1
][
1
]
=
18
>>>
print
jack, tom, anny
[
'jack'
, [
'age'
,
18
]] [
'tom'
, [
'age'
,
18
]] [
'anny'
, [
'age'
,
18
]]
|
这时候奇怪的事情发生了,jack、tom、anny的岁数都发生了改变,都变成了18了。jack、tom、anny他们应当都是不同的对象,怎么会互相影响呢?看下jack,tom,anny的内部元素每个元素id:
|
1
2
3
4
5
6
|
>>> [
id
(x)
for
x
in
jack]
[
3073896320L
,
3073777580L
]
>>> [
id
(x)
for
x
in
tom]
[
144870744
,
3073777580L
]
>>> [
id
(x)
for
x
in
anny]
[
144977344
,
3073777580L
]
|
恍然大悟,原来jack、tom、anny的岁数元素指向的是同一个元素。修改了其中一个,当然影响其他人了。那为什么修改名称没影响呢?原来在python中字符串不可以修改,所以在为tom和anny重新命名的时候,会重新创建一个’tom’和’anny’对象,替换旧的’jack’对象。
2、利用copy中的deepcopy方法进行拷贝
为了让他们之间不互相影响,用deepcopy来试试
|
1
2
3
4
|
>>> jack
=
[
'jack'
, [
'age'
,
'20'
]]
>>>
import
copy
>>> tom
=
copy.deepcopy(jack)
>>> anny
=
copy.deepcopy(jack)
|
根据第一个思路进行重命名,重定岁数操作:
|
1
2
3
4
5
6
7
|
>>> tom[
0
]
=
'tom'
>>> anny[
0
]
=
'anny'
>>>
print
jack, tom, anny
[
'jack'
, [
'age'
,
'20'
]] [
'tom'
, [
'age'
,
'20'
]] [
'anny'
, [
'age'
,
'20'
]]
>>> anny[
1
][
1
]
=
18
>>>
print
jack, tom, anny
[
'jack'
, [
'age'
,
'20'
]] [
'tom'
, [
'age'
,
'20'
]] [
'anny'
, [
'age'
,
18
]]
|
这时候他们之间就不会互相影响了。打印出每个人的内部元素每个id:
|
1
2
3
4
5
6
|
>>> [
id
(x)
for
x
in
jack]
[
139132064
,
3073507244L
]
>>> [
id
(x)
for
x
in
tom]
[
139137464
,
139132204
]
>>> [
id
(x)
for
x
in
anny]
[
139141632
,
139157548
]
|
他们的内部元素也都指向了不同的对象。
3、 以上讨论基于List中的List对象进行,那么对于自定义class呢,下面有一段代码供参考:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import
copy
class
test:
i
=
12
def
__init__ (
self
):
self
.i
=
15
if
__name__
=
=
'__main__'
:
t
=
test()
t1
=
test()
a
=
[]
a.append(t)
a.append(t1)
b
=
a.copy()
c
=
copy.deepcopy(a)
print
(a[
0
].i,a[
1
].i,b[
0
].i,b[
1
].i,c[
0
].i,c[
1
].i)
t.i
=
14
t1.i
=
16
print
(a[
0
].i,a[
1
].i,b[
0
].i,b[
1
].i,c[
0
].i,c[
1
].i)
|
运行结果:
|
1
2
|
15 15 15 15 15 15
14 16 14 16 15 15
|
通过对自定义class的object测试发现,浅拷贝只是对List中对象的引用的拷贝,深拷贝则按照对象进行完整拷贝。
小结:
思路一:利用切片操作和工厂方法list方法拷贝就叫浅拷贝,只是拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。
思路二:利用copy中的deepcopy方法进行拷贝就叫做深拷贝,外围和内部元素都进行了拷贝对象本身,而不是引用。
但是对于数字,字符串和其他原子类型对象等,没有被拷贝的说法,即便是用深拷贝,查看id的话也是一样的,如果对其重新赋值,也只是新创建一个对象,替换掉旧的而已。
原文地址:
文章转载自:[169IT-最新最全的IT资讯]
本文标题:python中的深拷贝(deepcopy)和浅拷贝(copy)介绍及代码参考
本文详细解析Python中的深拷贝与浅拷贝的区别,并通过代码示例展示了如何使用切片操作、工厂方法及copy模块实现不同类型的拷贝。
731

被折叠的 条评论
为什么被折叠?



