python中的可变与不可变、深拷贝和浅拷贝

个人猜想(很遗憾失败了)

在硬盘或者系统中存在一个字符集

如果存在硬盘中,那么硬盘出厂的时候他的字符集所占用的空间就已经确定了。

如果存在于系统的话,硬盘应该在出厂的时候为系统设置一个存储系统字符集的地方。在安装系统的时候,把这个字符集放入约定的内存空间中。

当然,这个字符集不管是存在硬盘还是系统自带,硬盘中的这片内存区域是不允许改变的。所以不可变类型的原因就找到了。

文心一言告诉我,确实存在一个字符集,但并不存在于硬盘中,而是存在系统中,用于处理数据

不过可以确定的是,这些不可变数据的创建及存储是有一定规律的

测试一下

使用python输出不可变类型的内存地址

结论:
经过多次运行,这个内存地址在一个时间段内输出的内容是相同的
应该是某种机制在保护,程序结束后并不释放内存空间
而是等待一段时间的下次调用,用来节省资源的消耗

但是结果的差值都为32

a=1
b=2
print("a=",id(a))
print("b=",id(b))

"""
a= 140731726750504
b= 140731726750536

"""

"""
a= 140731562451752
b= 140731562451784
"""

使用 C语言输出不可变类型的内存地址

测试了一下C语言的,发他的内存地址是固定不会变化的

于是我想起来C语言编译型语言,于是又重新创建了一个代码相同的文件,结果竟然是相同的

#include   
  
int main() {  
    int a = 1;  
    int b = 2;  
  
    printf("变量a的内存地址是:%d\n", &a);  
    printf("变量b的内存地址是:%d\n", &b);  
  
    return 0;  
}

//变量a的内存地址是:6422300
//变量b的内存地址是:6422296

尝试使用虚拟机的ubuntn系统下运行

python测试

结果显示差值为168,但是不会在一段时间内改变

a=1
b=2
print("a=",id(a))
print("b=",id(b))


"""
a= 10894368
b= 10894400
"""

C语言测试

发现每一次的结果都不同,但是每次都相差4,由此想到了系统架构是64还是32,一时间大量的疑问涌入脑中,好吧,时间有限,停止思考,疑问封存

什么是可变与不可变

可变不可变,是指内存中的那块内容(value)是否可以被改变

  • 可变类型(mutable),创建后可以继续修改对象的内容(值)

    字典、列表

    python中的可变与不可变、深拷贝和浅拷贝_第1张图片

  • 不可变类型(unmutable) ,一旦创建就不可修改的对象(值)

    数字, 字符串,元组

python中的可变与不可变、深拷贝和浅拷贝_第2张图片

什么是深拷贝和浅拷贝

 python中的copy 模块,可以实现拷贝功能

浅拷贝(就像快捷方式)

浅拷贝:引用(地址)拷贝,并没有产生新的空间。如果拷贝的是对象,原对象和copy对象都指向同一个内存空间,只拷贝父对象,不会拷贝对象的内部的子对象

  • 不会产生新的空间
  • 源对象和副本对象指向同一空间
  • 如果拷贝的是对象,子对象不会拷贝(不产生新的空间)

用法: copy.copy(变量) 会进行拷贝

深拷贝(真正的复制)

  • 会产生新的空间
  • 能够保持各自的独立性
  • 如果拷贝的是对象,子对象也会拷贝(产生新的空间)

深拷贝:会产生新的空间。如果拷贝的是对象,原对象和copy对象都指向不同的内存空间,会拷贝对象及其子对象(会产生新的空间)

用法:copy.deepcopy(变量名)

简单可变类型的拷贝

简单可变数据类型不管是深拷贝和浅拷贝,都会产生新的空间,而且保持各自的独立性

验证

浅拷贝

import copy

list1 = [2, 4, 6]
# 浅拷贝
list2 = copy.copy(list1)
print("list1=", list1, id(list1))
print("list2=", list2, id(list2))
list1.append(8)
print("list1=", list1, id(list1))
print("list2=", list2, id(list2))
# 测试结果
""""
list1= [2, 4, 6] 2366561172928
list2= [2, 4, 6] 2366558942976
list1= [2, 4, 6, 8] 2366561172928
list2= [2, 4, 6] 2366558942976
"""

深拷贝

import copy

list1=[2,4,6]
# 深拷贝
list2=copy.deepcopy(list1)

print("list1=", list1, id(list1))
print("list2=", list2, id(list2))
list1.append(8)
print("list1=", list1, id(list1))
print("list2=", list2, id(list2))
# 测试结果
"""
list1= [2, 4, 6] 2447599320576
list2= [2, 4, 6] 2447598755904
list1= [2, 4, 6, 8] 2447599320576
list2= [2, 4, 6] 2447598755904
"""

复杂可变类型的拷贝

复杂类型的内存地址是引用

list1 = [1, 3, 5]
list2 = [2, 4, 6]

list3 = [list1, list2]

print("list1=", list1, id(list1))
print("list2=", list2, id(list2))
print("list3=", list3, id(list3))
print("list3[0]=", list3[0], id(list3[0]))

"""
嵌套只是引用
list1= [1, 3, 5] 2090564943424
list2= [2, 4, 6] 2090564397632
list3= [[1, 3, 5], [2, 4, 6]] 2090562664192
list3[0]= [1, 3, 5] 2090564943424
"""

浅拷贝(对快捷方式创建快捷方式)

  • 复杂可变类型的 浅拷贝,实际上是引用拷贝,无法保持独立性

验证

import copy

list1 = [1, 3, 5]
list2 = [2, 4, 6]

list3 = [list1, list2]

# 已知,复杂类型的内存地址是引用
# 所以对复杂类型进行浅拷贝
list4 = copy.copy(list3)

list1.append(7)
print("list1=", list1, id(list1))
print("list3=", list3, id(list3))
print("list4=", list4, id(list4))
print("list4=[0]", list4[0], id(list4[0]))

"""运行结果:在浅拷贝结束后
对简单类型进行数据的添加
复杂类型的内容会改变,浅拷贝的内容也会发生改变
而浅拷贝的地址改变了
所以浅拷贝针对复杂类型最顶层
list1= [1, 3, 5, 7] 3144178450048
list3= [[1, 3, 5, 7], [2, 4, 6]] 3144178363904
list4= [[1, 3, 5, 7], [2, 4, 6]] 3144178364544
list4=[0] [1, 3, 5, 7] 3144178450048
"""

python中的可变与不可变、深拷贝和浅拷贝_第3张图片

深拷贝(真正的复制)

  • 复杂可变类型的 深拷贝,此时会产生新的内存空间

python中的可变与不可变、深拷贝和浅拷贝_第4张图片

验证

import copy

list1 = [1, 3, 5]
list2 = [2, 4, 6]

list3 = [list1, list2]

# 进行深拷贝
list4 = copy.deepcopy(list3)

list1.append(7)
print("list1=", list1, id(list1))
print("list3=", list3, id(list3))
print("list4=", list4, id(list4))
print("list4=[0]", list4[0], id(list4[0]))

"""运行结果:
深拷贝将复杂类型中的简单类型数据也进行了复制
实现了完全复制
list1= [1, 3, 5, 7] 1623394860736
list3= [[1, 3, 5, 7], [2, 4, 6]] 1623394774528
list4= [[1, 3, 5], [2, 4, 6]] 1623394775104
list4=[0] [1, 3, 5] 1623394775360
"""

简单不可变类型的拷贝(都是浅拷贝)

python中的可变与不可变、深拷贝和浅拷贝_第5张图片

验证

import copy


def copy_popy():
    tuple1=(1,3,5)

    # 浅拷贝
    tuple2=copy.copy(tuple1)

    print("tuple1=",tuple1,id(tuple1))
    print("tuple2=",tuple2,id(tuple2))

    """运行结果:
    tuple1= (1, 3, 5) 2239384263296
    tuple2= (1, 3, 5) 2239384263296
    """


tuple1=(1,3,5)
#深拷贝
tuple2=copy.deepcopy(tuple1)

print("tuple1=",tuple1,id(tuple1))
print("tuple2=",tuple2,id(tuple2))

"""运行结果
tuple1= (1, 3, 5) 2406599105152
tuple2= (1, 3, 5) 2406599105152
"""

复杂不可变类型的拷贝

复杂不可变类型的本质

import copy

list1=[1,3,5]
list2=[2,4,6]

tuple1=(list1,list2)

print("list1=",list1,id(list1))
print("tuple1=",tuple1,id(tuple1))
print("tuple1[0]=",tuple1[0],id(tuple1[0]))


"""运行结果
list1= [1, 3, 5] 2175399394816
tuple1= ([1, 3, 5], [2, 4, 6]) 2175399258432
tuple1[0]= [1, 3, 5] 2175399394816
"""

验证

浅拷贝

只关心最外层的数据类型是什么,如果是不可变类型,直接引用,没有办法保证数据的独立性

外层为不可变,内层为可变

python中的可变与不可变、深拷贝和浅拷贝_第6张图片

import copy

list1=[1,3,5]
list2=[2,4,6]

tuple1=(list1,list2)

# 进行浅拷贝
tuple2=copy.copy(tuple1)

print("list1=",list1,id(list1))
print("tuple1=",tuple1,id(tuple1))
print("tuple1[0]=",tuple1[0],id(tuple1[0]))
print("tuple2=",tuple2,id(tuple2))
print("tuple2[0]=",tuple2[0],id(tuple2[0]))


"""运行结果
list1= [1, 3, 5] 2384705011392
tuple1= ([1, 3, 5], [2, 4, 6]) 2384704858432
tuple1[0]= [1, 3, 5] 2384705011392


tuple2= ([1, 3, 5], [2, 4, 6]) 2384704858432
tuple2[0]= [1, 3, 5] 2384705011392
"""

外层为可变,内层为不可变
import copy

list1=(1,3,5)
list2=(2,4,6)

tuple1=[list1,list2]

# 进行浅拷贝
tuple2=copy.copy(tuple1)

print("list1=",list1,id(list1))
print("tuple1=",tuple1,id(tuple1))
print("tuple1[0]=",tuple1[0],id(tuple1[0]))
print("tuple2=",tuple2,id(tuple2))
print("tuple2[0]=",tuple2[0],id(tuple2[0]))


"""运行结果
list1= (1, 3, 5) 2192295467648
tuple1= [(1, 3, 5), (2, 4, 6)] 2192295837376
tuple1[0]= (1, 3, 5) 2192295467648

tuple2= [(1, 3, 5), (2, 4, 6)] 2192295274688
tuple2[0]= (1, 3, 5) 2192295467648
"""

深拷贝

这个数据是否有可变的数据类型,如果有它就会为可变类型开辟多个空间存储数据和地址,达到保证数据独立性的作用

python中的可变与不可变、深拷贝和浅拷贝_第7张图片

外层为可变类型
import copy

list1=(1,3,5)
list2=(2,4,6)

tuple1=[list1,list2]

# 进行深拷贝
tuple2=copy.deepcopy(tuple1)

print("list1=",list1,id(list1))
print("tuple1=",tuple1,id(tuple1))
print("tuple1[0]=",tuple1[0],id(tuple1[0]))
print("tuple2=",tuple2,id(tuple2))
print("tuple2[0]=",tuple2[0],id(tuple2[0]))


"""运行结果
list1= (1, 3, 5) 2050110790272
tuple1= [(1, 3, 5), (2, 4, 6)] 2050111160000
tuple1[0]= (1, 3, 5) 2050110790272


tuple2= [(1, 3, 5), (2, 4, 6)] 2050111074560
tuple2[0]= (1, 3, 5) 2050110790272
"""

外层为不可变类型 
import copy

list1 = [1, 3, 5]
list2 = [2, 4, 6]

tuple1 = (list1, list2)

# 进行深拷贝
tuple2 = copy.deepcopy(tuple1)

print("list1=", list1, id(list1))
print("tuple1=", tuple1, id(tuple1))
print("tuple1[0]=", tuple1[0], id(tuple1[0]))
print("tuple2=", tuple2, id(tuple2))
print("tuple2[0]=", tuple2[0], id(tuple2[0]))

"""运行结果
list1= [1, 3, 5] 2221492256448
tuple1= ([1, 3, 5], [2, 4, 6]) 2221492103488
tuple1[0]= [1, 3, 5] 2221492256448

tuple2= ([1, 3, 5], [2, 4, 6]) 2221492102912
tuple2[0]= [1, 3, 5] 2221492170816
"""
内外都不可变
import copy

list1 = (1, 3, 5)
list2 = (2, 4, 6)

tuple1 = (list1, list2)

# 进行深拷贝
tuple2 = copy.deepcopy(tuple1)

print("list1=", list1, id(list1))
print("tuple1=", tuple1, id(tuple1))
print("tuple1[0]=", tuple1[0], id(tuple1[0]))
print("tuple2=", tuple2, id(tuple2))
print("tuple2[0]=", tuple2[0], id(tuple2[0]))

"""运行结果
list1= (1, 3, 5) 2647937981056
tuple1= ((1, 3, 5), (2, 4, 6)) 2647938197824
tuple1[0]= (1, 3, 5) 2647937981056

tuple2= ((1, 3, 5), (2, 4, 6)) 2647938197824
tuple2[0]= (1, 3, 5) 2647937981056
"""

注意:只要是可变类型不管是深拷贝都会开辟新的空间 

切片拷贝(变量名[:])

切片拷贝,是一种浅拷贝,副本对象和原对象指向同一个空间

简单可变类型

list1 = [1, 3, 5]

list2 = list1[:]

print("list1=", list1, id(list1))
print("list2=", list2, id(list2))

list2.append(7)
print("list1=", list1, id(list1))
print("list2=", list2, id(list2))

"""运行结果
list1= [1, 3, 5] 1612210008768
list2= [1, 3, 5] 1612211181632

list1= [1, 3, 5] 1612210008768
list2= [1, 3, 5, 7] 1612211181632
"""

复杂不可变类型

list1 = [1, 3, 5]
list2 = [2, 4, 6]

tuple1=(list1,list2)

tuple2=tuple1[:]

print("list1=",list1,id(list1))
print("tuple1=",tuple1,id(tuple1))
print("tuple2=",tuple2,id(tuple2))
print("tuple1[0]=",tuple1[0],id(tuple1[0]))
print("tuple2[0]=",tuple2[0],id(tuple2[0]))
list1.append(7)
print("tuple2[0]=",tuple2[0],id(tuple2[0]))

"""运行结果得出,切片拷贝是浅拷贝
list1= [1, 3, 5] 2281363043008
tuple1= ([1, 3, 5], [2, 4, 6]) 2281364482816
tuple2= ([1, 3, 5], [2, 4, 6]) 2281364482816

tuple1[0]= [1, 3, 5] 2281363043008
tuple2[0]= [1, 3, 5] 2281363043008
tuple2[0]= [1, 3, 5, 7] 2281363043008
"""

字典拷贝 (字典名.copy())

字典提供一个copy()方法,也是浅拷贝,虽然地址发生改变,但是内部的对象仍然是链接状态

test_dict1={"age":[10,20,30]}

test_dict2=test_dict1.copy()

print("test_dict1=",test_dict1,id(test_dict1))
print("test_dict2=",test_dict2,id(test_dict2))
test_dict1["age"][0]=100

print("test_dict1=",test_dict1,id(test_dict1))
print("test_dict2=",test_dict2,id(test_dict2))

"""运行结果显示,字典拷贝为浅拷贝
test_dict1= {'age': [10, 20, 30]} 2561919905472
test_dict2= {'age': [10, 20, 30]} 2561921341312

test_dict1= {'age': [100, 20, 30]} 2561919905472
test_dict2= {'age': [100, 20, 30]} 2561921341312
"""

 

你可能感兴趣的:(python,开发语言)