1.不可变类型VS可变类型
一般的基本数据类型都是不可变类型,一般的组合数据类型或者自定义数据类型都是可变数据类型 python中的一切都是对象,可以通过id()函数查询对象在内存中的地址数据,可变类型是在定义过数据类型之后,修改 变量的数据,内存地址不会发生变化,不可变数据类型是在定义了数据之后,修改变量的数据,变量不会修改原来 内存地址的数据而是会指向新地址,原有的数据保留,这样更加方便程序中基本数据的利用率。
nums = [12, 13, 15, 18, 20, "hello", ["world", "python"]]
a = 20
print(id(a), id(nums[4]))
b = "hello"
print(id(b), id(nums[5]))
c = ["world", "python"]
print(id(c), id(nums[6]))
print(id(nums[6][0]), id(c[0]))
可变类型
对象在内存地址中存储的数据可变
a = list()
print(id(a))
print(a)
a.append("hello")
print(id(a))
print(id(a[0]))
print(a)
不可变类型
不可变类型,在同一个代码块中进行多次使用时会将该类型的对象,直接创建在常量区,在任意引用时候的时候直接赋值内存地址因为不可变类型的对象数据不会发生变化,所以内存中存储一份即可!优化程序执行效率一般情况下,可变类型的对象会创建在堆内存中;不可变类型的对象会创建在常量区内存中
整数类型:-5~256:在解释器加载时,已经自动分配了这些数字的内存 超出-5~256范围的整数,在一个代码块中申请一次内存
代码块
交互模式:一行命令就是一个代码块 IDE模式~工具开发:一个模块就是一个代码块
python中的最小运行单元是代码块,代码块的最小单元是一行代码,需要注意的是在交互模式下,每行命令都是一个独立的代码块,每个代码块都会独立的申请一次内存。-5 ~ 256之间的数据自动缓存,字符串自动缓存,超出范围的数据重新申请内存。
2.深拷贝与浅拷贝
import copy
a = [1, 2, 3, 4, 5, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
print("a=", a, " id(a)=", id(a), " id(a[1])=", id(a[1]), " id(a[5])=", id(a[5]))
print("b=", b, " id(b)=", id(b), " id(b[1])=", id(b[1]), " id(b[5])=", id(b[5]))
print("c=", c, " id(c)=", id(c), " id(c[1])=", id(c[1]), " id(c[5])=", id(c[5]))
print("d=", d, " id(d)=", id(d), " id(d[1])=", id(d[1]), " id(d[5])=", id(d[5]))
a[1] = 1
a.append(6)
a[5].append('c')
print("a=", a, " id(a)=", id(a), " id(a[1])=", id(a[1]), " id(a[5])=", id(a[5]))
print("b=", b, " id(b)=", id(b), " id(b[1])=", id(b[1]), " id(b[5])=", id(b[5]))
print("c=", c, " id(c)=", id(c), " id(c[1])=", id(c[1]), " id(c[5])=", id(c[5]))
print("d=", d, " id(d)=", id(d), " id(d[1])=", id(d[1]), " id(d[5])=", id(d[5]))
print(id(a[0]))
结果:
a= [1, 2, 3, 4, 5, ['a', 'b']] id(a)= 1719814853184 id(a[1])= 1719806552400 id(a[5])= 1719814830912
b= [1, 2, 3, 4, 5, ['a', 'b']] id(b)= 1719814853184 id(b[1])= 1719806552400 id(b[5])= 1719814830912
c= [1, 2, 3, 4, 5, ['a', 'b']] id(c)= 1719814831104 id(c[1])= 1719806552400 id(c[5])= 1719814830912
d= [1, 2, 3, 4, 5, ['a', 'b']] id(d)= 1719812294848 id(d[1])= 1719806552400 id(d[5])= 1719814940480
a= [1, 1, 3, 4, 5, ['a', 'b', 'c'], 6] id(a)= 1719814853184 id(a[1])= 1719806552368 id(a[5])= 1719814830912
b= [1, 1, 3, 4, 5, ['a', 'b', 'c'], 6] id(b)= 1719814853184 id(b[1])= 1719806552368 id(b[5])= 1719814830912
c= [1, 2, 3, 4, 5, ['a', 'b', 'c']] id(c)= 1719814831104 id(c[1])= 1719806552400 id(c[5])= 1719814830912
d= [1, 2, 3, 4, 5, ['a', 'b']] id(d)= 1719812294848 id(d[1])= 1719806552400 id(d[5])= 1719814940480
1719806552368
可以看到,引用在所有层面上的内存都同步于原列表。 深浅拷贝对于不可类型(也就是index为1的值)都不重新申请内存;对于内层的可变类型(也就是index为0的列表)浅拷贝直接借用,深拷贝自己申请一份内存;对于最外层的可变类型深浅拷贝都自己申请一份内存。 总结:浅拷贝只拷贝一层,深拷贝拷贝所有层。深浅拷贝都只对可变类型有用。
|