python深拷贝与浅拷贝

python 的拷贝有内置的库,我们可以直接引用,但是什么时候使用深拷贝?什么时候使用浅拷贝呢?

基本概念

  • 直接赋值:其实就是对象的引用(别名)。
  • 浅拷贝(copy):拷贝对象,不会拷贝对象的内部的子对象。
  • 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了对象及其子对象。

copy 的实质?

探讨 copy 之前,我们需要先知道不同数据类型,它究竟是怎样保存数据的。总得来说,所有的数据类型,它保存数据的格式分为两大类,可变数据类型和不可变数据类型这两类,至于这两类的区别我在其他文章已经分析过了,想了解的可以去看看。

对于不可变数据类型

str='abc'
id(str) # 25432288

num=123
id(num) # 1457499984

对于不可变数据类型,只有对当前值的引用。

对于可变数据类型

list1 = [1, 2, 3, [4, 5, 6]]
id(list1) # 32476104
id(list1[0]) # 1457498032
id(list1[1]) # 1457498048
id(list1[3]) # 32323560
id(list1[3][0]) # 1457498080

由上面的例子可以看到

  1. 可变数据类型,它内部存的都是引用;
  2. 可变数据类型的内部,还可以嵌套可变数据类型,这样多层嵌套,每一层都是对值的引用。

copy 做了什么?

浅拷贝

import copy

# 对不可变数据
str1 = 'abc'
print(id(str1)) # 24715488
str2 = copy.copy(str1)
print(id(str2)) # 24715488
str1 = 'ddd'
print(str1, str2) # ddd abc

# 对可变数据类型
list1 = [1, 2, [3, 4]]
print(id(list1)) # 26216264
print(id(list1[0])) # 1457498032
print(id(list1[2])) # 25659592
list2 = copy.copy(list1)
print(id(list2)) # 26216296
print(id(list2[0])) # 1457498032
print(id(list2[2])) # 25659592
list2[2][0] = 5
print(list1[2], list2[2]) # [1, 2, [5, 4]]  [1, 2, [5, 4]]
  • 浅拷贝对不可变数据类型,直接将新变量的指针指向拷贝的数据在内存中的位置。由于浅拷贝对象,每一次的修改,就是重新创建内存,将指针指向新的内存,所以拷贝前后的数据互不关联。

  • 对可变数据类型,它会在内存中,重新创建一个地址,然后它内部的存储的数据,则是引用的内存中的地址。

    • 如果第一层是不可变数据类型,那么跟重新赋值一样,改变它,就是改变了这个地址,拷贝后的数据与拷贝前的数据完全无关,
    • 如果第一层是可变数据类型,那么去改变这个可变数据类型内部的数据,由于当前地址没有改变,所以拷贝前后的两个数据,他们内部第一层中的可变数据类型指向的是同一个地址,所以改变后,他们同步出现了变化。

深拷贝

str1 = 'abc'
print(id(str1)) # 2300527486600
str2 = copy.deepcopy(str1)
print(id(str2)) # 2300527486600
str1 = 'ddd'
print(str1, str2) # ddd abc

list1 = [1, 2, [3, 4]]
print(id(list1)) # 2300533954888
print(id(list1[0])) # 1951990224
print(id(list1[2])) # 2300533956168
list2 = copy.deepcopy(list1)
print(id(list2)) # 2300533955400
print(id(list2[0])) # 1951990224
print(id(list2[2])) # 2300533955976
list2[2][0] = 5
print(list1, list2) # [1, 2, [3, 4]]  [1, 2, [5, 4]]
  • 对不可变数据类型,深拷贝与浅拷贝没有什么差别,都是将变量指向值的地址;
  • 对可变数据类型,深拷贝则与浅拷贝完全不同,首先,对于自身,同样的创建一个新的地址,只有对内部不同;
    • 内部是不可变数据类型,与浅拷贝一致,均是引用了一个地址;
    • 内部是可变数据类型,则重新创建一个新的地址,与原数据彻底分开。

总结:

  • 对于不可变数据类型,浅拷贝与深拷贝没有什么区别;
  • 对于可变数据类型,如果内部只有一层数据,也就是说没有可变数据类型的结构,浅拷贝与深拷贝没有什么区别;
  • 对与多层可变数据类型的,则需要使用深拷贝。

你可能感兴趣的:(python,python)