python里面如何拷贝一个对象

  • 赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个;

  • 浅拷贝(copy.copy()),创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另一个也会被改变);

  • 深拷贝(copy.deepcopy()),创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另一个不会改变)

赋值

代码:

zty = ["Zty", 111, ["Python", "C#", "JavaScript"]]
zty2 = zty

print(id(zty))
print(zty)
print([id(ele) for ele in zty])
print(id(zty2))
print(zty2)
print([id(ele) for ele in zty2])

zty[0] = "zty222"
zty[2].append("CSS")
print('----------------------')
print(id(zty))
print(zty)
print([id(ele) for ele in zty])
print(id(zty2))
print(zty2)
print([id(ele) for ele in zty2])

输出:

32436936
['Zty', 111, ['Python', 'C#', 'JavaScript']]
[32408776, 496204704, 32437320]
32436936
['Zty', 111, ['Python', 'C#', 'JavaScript']]
[32408776, 496204704, 32437320]
----------------------
32436936
['zty222', 111, ['Python', 'C#', 'JavaScript', 'CSS']]
[32441992, 496204704, 32437320]
32436936
['zty222', 111, ['Python', 'C#', 'JavaScript', 'CSS']]
[32441992, 496204704, 32437320]

可以理解为,Python中,对象的赋值都是进行对象引用(内存地址)传递
由于will和wilber指向同一个对象,所以对zty的任何修改都会体现在zty2上
这里需要注意的一点是,str是不可变类型,所以当修改的时候会替换旧的对象,产生一个新的地址
比如

In [12]: a = 5

In [13]: id(a)
Out[13]: 496201312

In [14]: b = a

In [15]: id(b)
Out[15]: 496201312

In [16]: a = 3

In [17]: id(a)
Out[17]: 496201248

In [18]: b
Out[18]: 5

In [19]: id(b)
Out[19]: 496201312

在这个例子中 zty is zty2 zty[i] is zty[i]

浅拷贝

代码

import copy
zty = ["Zty", 111, ["Python", "C#", "JavaScript"]]

zty2 = copy.copy(zty)

print(id(zty))
print(zty)
print([id(ele) for ele in zty])
print(id(zty2))
print(zty2)
print([id(ele) for ele in zty2])

zty[0] = "zty222"
zty[2].append("CSS")
print('----------------------')
print(id(zty))
print(zty)
print([id(ele) for ele in zty])
print(id(zty2))
print(zty2)
print([id(ele) for ele in zty2])

输出

41230984
['Zty', 111, ['Python', 'C#', 'JavaScript']]
[40731848, 496204704, 41230792]
41232264
['Zty', 111, ['Python', 'C#', 'JavaScript']]
[40731848, 496204704, 41230792]
----------------------
41230984
['zty222', 111, ['Python', 'C#', 'JavaScript', 'CSS']]
[40765064, 496204704, 41230792]
41232264
['Zty', 111, ['Python', 'C#', 'JavaScript', 'CSS']]
[40731848, 496204704, 41230792]

在这个例子中 使用一个叫做zty的变量,指向一个list类型的对象
然后调用copy模块的浅拷贝函数copy(),对zty指向的对象进行浅拷贝,然后浅拷贝生成的新对象赋值给zty2变量

浅拷贝会创建一个新的对象,但是,对于对象中的元素,浅拷贝就只会使用原始元素的引用(内存地址)

也就是说 zty is not zty2, zty[i] is zty2[i]

但是对zty进行修改时 因为zty[0]的类型是 str 不可变 zty对应的list的第一个元素会使用一个新的对象, 而zty2[0]引用的还是会使用原始元素的引用
而zty[2]的类型还是一个list 可变 当zty[2]做了修改,并不会产生新的对象 所以修改zty[2]时 相应的修改也会反映到zty2[2]上

深拷贝

代码

import copy
zty = ["Zty", 111, ["Python", "C#", "JavaScript"]]

zty2 = copy.deepcopy(zty)

print(id(zty))
print(zty)
print([id(ele) for ele in zty])
print(id(zty2))
print(zty2)
print([id(ele) for ele in zty2])

zty[0] = "zty222"
zty[2].append("CSS")
print('----------------------')
print(id(zty))
print(zty)
print([id(ele) for ele in zty])
print(id(zty2))
print(zty2)
print([id(ele) for ele in zty2])

输出

41427592
['Zty', 111, ['Python', 'C#', 'JavaScript']]
[40928456, 496204704, 41427400]
41428872
['Zty', 111, ['Python', 'C#', 'JavaScript']]
[40928456, 496204704, 41428808]
----------------------
41427592
['zty222', 111, ['Python', 'C#', 'JavaScript', 'CSS']]
[40961672, 496204704, 41427400]
41428872
['Zty', 111, ['Python', 'C#', 'JavaScript']]
[40928456, 496204704, 41428808]

在这个例子中 通过copy模块里面的深拷贝函数deepcopy(),对zty指向的对象进行深拷贝,然后深拷贝生成的新对象赋值给zty2变量

深拷贝也会创建一个新的对象

但是,对于对象中的元素,深拷贝都会重新生成一份,而不是简单的使用原始元素的引用(内存地址)

当对zty进行修改的时候,不会影响zty2

特殊情况说明

  • 对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有拷贝这一说
    也就是说,对于这些类型,”obj is copy.copy(obj)” 、”obj is copy.deepcopy(obj)”
  • 如果元祖变量只包含原子类型对象,则不能深拷贝

发表评论

电子邮件地址不会被公开。