10.python-深拷贝和浅拷贝

python-深拷贝和浅拷贝

变量: 存储对象的引用

对象:会分配一块内存空间,存储实际数据

引用:变量指向对象,理解为指针

变量存储在栈内存,对象存储在堆内存。

Python数据类型分为可变数据类型和不可变数据类型。

  • 可变数据类型包括:List(列表)、Dictionary(字典)、Set(集合)
  • 不可变数据类型包括:String(字符串)、Number(数字)、Tuple(元组)

赋值

Python 的赋值语句并不是创建一个新对象,只是创建了一个共享原始对象引用的新变量

不可变对象的赋值

a = 1
b = a

print(a, b)

a += 2
print(a, b)

print("a id:", id(a))
print("b id:", id(b))

# 输出结果
1 1
3 1
a id: 4564097808
b id: 4564097776
  • 修改变量 a 的值,不会同步修改变量 b 的值
  • 因为赋值操作 a += 2 后,变量 a 存储的对象引用已经改变了

可变对象的赋值

当其中一个内数据改变后,另一个也改变了

a = [1, 2, 3]
b = a

print(a, b)

a[1] = 22
print(a, b)

print("a id:", id(a))
print("b id:", id(b))


# 输出结果
[1, 2, 3] [1, 2, 3]
[1, 22, 3] [1, 22, 3]
a id: 4567683136
b id: 4567683136
  • 修改 a 变量的值,会同步修改变量 b 的值,因为变量 a、b 指向的对象是可变对象,所以它们保存的对象引用都是一样的

浅拷贝

浅拷贝会创建一个新对象,该新对象存储原始元素的引用

  • (1)不拷贝子对象的内容,只拷贝子对象的引用
  • (2)可以使用Python内置函数copy()

浅拷贝的三种形式

切片-可变序列

lst = [1,2,[3,4]]

list1=[1,2,3]
list2=list1[:]

切片是属于浅拷贝,修改数据时,会对原先的造成污染

对于不可变数据类型(元组、字符串):

元组 使用 tuple()和切片操作符:

字符串 使用 str()和切片操作符:

都不是浅拷贝,没有开辟新内存来存储原对象对子对象的引用

列表的切片是浅拷贝(创建新的内存空间),元组的切片是赋值(不会创建新的内存空间)

切片操作符不能用于字典和集合完成浅拷贝

工厂函数-构造器

使用数据类型本身构造器

lst1 = list(lst)

#列表list
list1=[1,2,3]
list2=list(list1)
 
#set
set1=([1,2,3])
set2=set(set1)
 
#字典dict
dict1={1:[1,'w'],2:33}
dict2=dict(dict1)

copy.copy()

list1=[1,2,3]
list2=list1.copy()

import copy  #需要先导入copy模块
 
list1=[1,2,3]
list2=copy.copy(list1)

浅拷贝的原对象的数据改变

浅拷贝在拷贝时,只会copy一层,在内存中开辟一个空间,存放这个copy的列表。更深的层次并没有copy,即第二层用的都是同一个内存。

list1=[(1,2),3,[4,5]]
list2=list1.copy()
list1.append(31)
print(list1)
print(list2)
[(1, 2), 3, [4, 5], 31]
[(1, 2), 3, [4, 5]]
    
    
list1=[(1,2),3,[4,5]]
list2=list1.copy()
list2.append(31)
print(list1)
print(list2)
[(1, 2), 3, [4, 5]]
[(1, 2), 3, [4, 5], 31]
 
list1=[(1,2),3,[4,5]]
list2=list1.copy()
list1[0]+=(31,31)
print(list1)
print(list2)
[(1, 2,31,31), 3, [4, 5]]
[(1, 2), 3, [4, 5]]
 
list1=[(1,2),3,[4,5]]
list2=list1.copy()
list1[2]+=[31,31]
print(list1)
print(list2)
[(1, 2), 3, [4, 5,31,31]]
[(1, 2), 3, [4, 5,31,31]]

深拷贝

  • (1)会连子对象的内存全部拷贝一份,对子对象的修改不会影响源对象
  • (2)可以使用Python内置函数deepcopy()
import copy
list_01 = ["11","22"]
list_02 = ["33",list_01]
list_03 = copy.deepcopy(list_02)
print(id(list_01))

print(id(list_02))

print(id(list_03))

print(id(list_02[1]))
print(id(list_03[1]))

list_01.append("44")

print(list_01)
print(list_02)
print(list_03)

['33', ['11', '22', '44']]
['33', ['11', '22']]

通过深拷贝即使嵌套的列表具有更深的层次,也不会产生任何影响,因为深拷贝拷贝出来的对象根本就是一个全新的对象,不再与原来的对象有任何的关联。

总结

  1. 浅拷贝花费时间少,占用内存少,只拷贝顶层数据,拷贝效率高。
  2. 对不可变对象拷贝时,浅拷贝和深拷贝的作用是一致的,不开辟新空间,相当于赋值操作。
  3. 可变对象浅拷贝时,只拷贝第一层中的引用,如果元素是可变对象,并且被修改,那么拷贝的对象也会发生变化。
  4. 可变对象深拷贝时,会逐层进行拷贝,遇到可变类型,就开辟一块内存复制下来,不论哪一层元素被修改,拷贝的对象都不会发生改变。

不可变对象可以直接赋值,可变对象只有一层时,建议浅拷贝,如果可变对象是多层,建议深拷贝。

posted @ 2023-02-03 18:39  贝壳里的星海  阅读(177)  评论(0编辑  收藏  举报