来自python的【赋值、深拷贝和浅拷贝】

  • 在很多编程语言中,都有一个说法万物皆对象,即无论是Number、String、Function、都是作为对象进行处理。
  • 在python中,对象都拥有三个属性身份(ID)、类型(type)、值(value),接下来的赋值、深拷贝、浅拷贝与这三个属性有关。
  • 在python中,每个对象都会在内存中占有一块内存空间,该对象在内存中所在位置的地址就被称为引用。,类似域名解析。
  • 在进行拷贝时,要先对最外层数据进行判断,判断是可变对象还是不可变对象,这影响数据整体的ID值。
  • 大多数情况下,都是使用浅拷贝,速度快,占用空间少,拷贝效率高;深拷贝是递归拷贝。
  • 深拷贝作用:减少内存的使用,可以作为数据的清洗、修改等可以对原数据进行复制一份,避免丢失原数据

可变对象与不可变对象

可变对象list set dict 是可变对象,能够对可变对象中的数据进行改变。ID值一直不会改变,只改变Value值。,
不可变对象int float bool str tuple frozenset 是不可变对象。ID、Value、均不能更改,在python对不可变对象进行重新赋值,不叫做改变数据,叫做重新创建对象。当不可变对象的数据进行改变时,是重新开辟了内存空间,此时的ID值、Value值都已改变。当重新创建后,旧对象将会被丢弃,垃圾回收机制将会回收旧对象。

赋值概念

  • 在很多编程语言中,赋值是创建对象,并指向开辟的内存空间。在python中,·赋值只是对象引用的传递。什么意思呢?
  • 即:等号(=)左右两边数据的内存地址相同,即赋值后,ID值相同 , 当创建一个对象的时候,再赋值给另外一个变量的时候,并不是赋值给另一个变量而是把这个变量在地址空间的id地址值传递给另一个变量,简单的说就是拷贝了这个对象的引用
  • 简单来说,在python中,对赋值变量的内容进行改变,等式两边的数据都会收到牵连(牵一发而动全身), 在赋值运算中,可变数据与不可变数据对于赋值而言,没有区别,一旦改变,任何数据都会进行改变。 如下图所示:
    转载而来,侵删

浅拷贝概念

  • 浅拷贝只会对拷贝对象父级内容进行拷贝,并不会拷贝内部(多层次)的内容。如:[1,2,3,[5,6]],其中[5,6]中的数据就是内部数据。
  • 当拷贝数据内部是不可变数据时ID值不变,重新赋值将会重新开辟内存空间,从而导致ID值变化,在这种情况下,并不会影响到其他数据。
  • 当拷贝数据内部是可变数据时,ID值不变,与原数据中可变数据ID值一样,但是可以改变Value值,但ID值不变,所以会牵连同一个引用的所有数据进行改变
  • 简单可以理解为:在数据改变时,不可变数据重新开辟内存空间,ID值改变,不影响其他数据;可变数据与原本数据共享同一个地址,ID值不变,Value值改变,所有使用这一数据的内容全部改变。
  • 浅拷贝包括:对列表切片拷贝[:],调用对象的拷贝方法list.copy(),调用copy.copy
    在这里插入图片描述

深拷贝概念

  1. 深拷贝是对一个对象的所有层次内容的拷贝(递归),即内部和外部所有数据都会被拷贝,并且全部的数据都会赋予新的值,但是要看最外层的数据是可变还是不可变哦。
  2. 当拷贝数据内部是不可变数据时,ID值不变,重新赋值将会重新开辟内存空间,从而导致ID值变化,在这种情况下,并不会影响到其他数据。;
  3. 当拷贝数据内部是可变数据时,ID值改变,与原始数据无关,即无论怎么样改变,都不会互相改变数据。互不相干
  4. 深拷贝方法:copy.deepcopy()
    在这里插入图片描述

思路总结

  1. 在判断ID值是否改变时,先对父本对象的数据类型进行探讨。父本对象(初始数据)数据类型分为:可变数据对象、不可变数据对象 ,以此判断在赋值、浅拷贝、深拷贝中会如何改变。以下内容我能把我自己饶进去

    (1)当父本对象全是不可变对象时:
    	赋值语句:ID与原数值ID一样,是对原数据的引用。(但要注意,更改赋值,相当于重新开辟内存空间,所以,改变后ID值会改变,对于赋值而言,数据不会对应变化。)
    	浅拷贝:ID值不变。相当于引用,要注意重新赋值机制哦,此时还要研究内部数据是可变数据还是不可变数据。
    	深拷贝:ID值不变。相当于引用/但是要注意重新赋值哦,此时还要研究内部数据是可变数据还是不可变数据。
    (2)当副本对象全是可变对象时
    	赋值语句:ID值不变,因为是可变数据,改变Value时,id不会改变,因此会相互影响。
    	浅拷贝:整体ID值改变。此时还要研究内部数据是可变数据还是不可变数据。内部数据是不可变数据时,会进行重新创建对象,不会互相影响,内部数据是可变数据时,ID值不变,改变Value值时,互相影响。
    	深拷贝:整体ID值改变,此时还要研究内部数据是可变数据还是不可变数据。内部数据无论是可变还是不可变都不会影响。
    
  2. 叶式总结版:

  • 赋值是对数据的引用,无论外部数据、内部数据是可变数据还是不可变数据,ID值不会改变,一直与原始数据ID一样。但在不可变数据进行重新赋值的情况下,会重新开辟一个内存空间,此时被改变的数据id值变化,与其他ID值不一样,因此也不会导致别的数据。在可变数据情况下,value直接改变,不会影响ID值,所以会对赋值两边的数据都进行影响。(内外数据同理)
  • 浅拷贝:最外层是不可变数据,整体id值不变;最外层是可变数据而言,id值改变。此时再观测内部数据,内部数据为不可变数据时,整体id不变,但注意重新赋值机制;内部数据为可变数据时,ID不变,value值直接改变,因此会相互影响。
  • 深拷贝:最外层是不可变数据,整体id值不变。注意重新赋值机制;最外层是可变数据,id值改变,内部数据是不可变数据时,id值不变,注意重新赋值机制,当内部数据是可变数据时,id值改变,与原本数据互不相关。但凡原始数据中含有可变数据,进行深拷贝都会赋予新的ID值

测试

里面有些结果没有复制清楚,代码没有错得。

#  深浅拷贝测试
import copy

# 是否与最外层有关
# id长度好像和字节长度有关
# 不可变数据 number string tuple
a = 1;
b = 'hi';
c = ('1',2,2.3)
print(a,b,c) #1 hi ('1', 2, 2.3)
print(id(a)) #a : 10914496
print(id(b)) #140119479028456
print(id(c)) #140343330605744
# 赋值
d = a
print(id(a))
e =b
print(id(b))
f = c
print(id(f))
# 对于不可变数据 进行赋值 id量 保持不变

# 浅拷贝
print('浅拷贝')
d1 = copy.copy(a)
print(id(d1)) #10914496
e1 = copy.copy(b)
print(id(e1)) #140263909268368
f1 =copy.copy(c)
print(id(f1)) #140263879457528
# 浅拷贝 对于不可变数据而言 不赋予新地址 只是引用

# 深拷贝
print('deep')
d2 = copy.deepcopy(a) #10914496
print(id(d2))
e2 = copy.deepcopy(b)#140263909268368
print(id(e2))
f2 = copy.deepcopy(c)#140263879457528
print(id(f2))

# 深拷贝 对于不可变数据 也是直接引用 不改变地址
# 又因为是不可变数据 如果为重新赋值 是开辟了另一个存储空间 所以不会影响

a = 99
print(d,d1,d2) #1,1,1
print(id(a)) #10917632 此时的id改变 因为是重新开辟了空间
# 以上所有都是针对整体
b ='hello'
print(e,e1,e2)#hi hi hi 不影响 因为重新开辟空间

# 接下来进行可变数据 list dict set

aa = [1,2]
bb = {3,4}
cc =set('56')
print(aa,bb,cc,'old') #[1, 2] {3, 4} {'6', '5'}
print(id(aa))#140040007781448
print(id(bb)) #140040007563976
print(id(cc))#140040007674120

# 赋值对于可变数据
aa1 = aa
bb1 = bb
cc1 = cc
print(aa1,bb1,cc1,'new')#[1, 2] {3, 4} {'5', '6'}
# 赋值的id不变 无论可变不可变 都不会变 因为是直接引用
print(id(aa1)) #140040007781448
print(id(bb1))#140040007563976
print(id(cc1))#140040007674120

# 浅拷贝  所有的id都改变了
print('浅拷贝')
aa2 = copy.copy(aa) #140039976604936
bb2 = copy.copy(bb) #140679074708840
cc2 = copy.copy(cc)#140679074707272
print(id(aa2))
print(id(bb2))
print(id(cc2))

# 深拷贝 所有的id值改变
print('深拷贝')
aa3 = copy.deepcopy(aa)
bb3 = copy.deepcopy(bb)
cc3 = copy.deepcopy(cc)
print(id(aa3)) #140039976604488
print(id(bb3)) #140040007675016
print(id(cc3)) #140040007674344

# 改变数据
aa[0]=99
print(aa1,aa2,aa3) #[99, 2] [1, 2] [1, 2]
print(id(aa[0]))#10917632
print(id(aa1[0]))#10917632
print(id(aa2[0]))#10914496
print(id(aa3[0]))#10914496
aa2[0]='hh'
print(aa,aa1,aa2,aa3) # ?? 深拷贝不变吗 id值不是一样的吗
print(id(aa2[0]))#140709965624072 # 因为是重新赋值 所以改变
print(id(aa3[0]))#10914496

# 接下来 外部是不可变数据 内部是可变/不可变数据
# 1. 外不变 内不变 全部都是不变的,那么= shallow deep 都是引用
# 但是内部不可变数据改变 都是重新开辟数据 所以不影响
print('other')
aaa = (1,2,3)
bbb = aaa
ccc = copy.copy(aaa)
ddd = copy.deepcopy(aaa)
print(id(aaa),id(bbb),id(ccc),id(ddd)) #139916514522312 139916514522312 139916514522312 139916514522312
# 此时id都相同
# 改变不可变数据
aaa = (88,88,88)
print(aaa,bbb,ccc,ddd) #(88, 88, 88) (1, 2, 3) (1, 2, 3) (1, 2, 3)
# 都不影响因为开辟了新的空间 不改变数据的id值保持不变
print(id(aaa),id(bbb),id(ccc),id(ddd)) #140363400709320 140363400709248 140363400709248 140363400709248

#2. 外部不可变,内部可变数据
print('out')
aaa1 = (1,2,[3,4])
bbb1 = aaa1
ccc1 = copy.copy(aaa1)
ddd1 = copy.deepcopy(aaa1)
print(id(aaa1),id(bbb1),id(ccc1),id(ddd1))
#外部是不可变数据 所以 赋值 浅拷贝 的整体id都是不会改变的
# 内部可变id
print(id(aaa1[2]),id(bbb1[2]),id(ccc1[2]),id(ddd1[2]))
#139935664776584 139935664776584 139935664776584 139935664776712
# 赋值 、 浅拷贝、 id值都是一样的 又因为可以在不改变id的情况下 改值
# 所以 修改一个数据 其余的数据都 会被改变
# 深拷贝会对可变数据以及含有可变数据的内容 进行id的改变
aaa1[2][1] = "hello" # 赋值改变 浅拷贝改变 深拷贝不变
print(aaa1,bbb1,ccc1,ddd1)
#(1, 2, [3, 'hello']) (1, 2, [3, 'hello']) (1, 2, [3, 'hello']) (1, 2, [3, 4])

# 外部可变 内部不可变
aaa2 = [1,2,3,4]
bbb2 = aaa2
ccc2 = copy.copy(aaa2)
ddd2 = copy.deepcopy(aaa2)
# 外部可变 赋值的id值一样 浅拷贝的id值 改变  深拷贝id值改变
print(id(aaa2),id(bbb2),id(ccc2),id(ddd2))
#140218844694088 140218844694088 140218844693960 140218844694152
# 修改内部数据 赋值改变 浅拷贝 深拷贝 不变
aaa2[1] ='hello' # 相当于重新赋值 id改变
print(aaa2,bbb2,ccc2,ddd2) #[1, 'hello', 3, 4] [1, 'hello', 3, 4] [1, 2, 3, 4] [1, 2, 3, 4]
print(id(aaa2[1]),id(bbb2[1]),id(ccc2[1]),id(ddd2[1]))
#139847079476672 139847079476672 10914528 10914528

#外部可变 内部可变
aaa3 = [1,2,[3,4]]
bbb3 = aaa3
ccc3 = copy.copy(aaa3)
ddd3 = copy.deepcopy(aaa3)
print(id(aaa3),id(bbb3),id(ccc3),id(ddd3))
#140053889018760 140053889018760 140053889018696 140053889018632
#赋值的id值一样 浅拷贝的id值 改变  深拷贝id值改变
print(id(aaa3[2]),id(bbb3[2]),id(ccc3[2]),id(ddd3[2]))
#140053889018824 140053889018824 140053889018824 140053889018568
# 内部 深拷贝id改变  浅拷贝不变 所以数据会变
aaa3[2][1]='666'
print(aaa3,bbb3,ccc3,ddd3)#[1, 2, [3, '666']] [1, 2, [3, '666']] [1, 2, [3, '666']] [1, 2, [3, 4]]
print(id(aaa3[2]),id(bbb3[2]),id(ccc3[2]),id(ddd3[2]))
#140484554124232 140484554124232 140484554124232 140484554123976
# id没有改变 

写在最后,可能过段时间,我又不记得了,但是,这次我真的明白了!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值