赞
踩
Python学习——深入理解python变量
starry • 2020 年 04 月 09 日
1. 变量&赋值
Python中的变量不同于java、C语言中,后者的变量一旦创建就要说明号变量类型,不可改变;前者则不同,变量随着所赋值的类型改变而改变,原因是在于Python解释器比较高级,在编译的时候先查看所赋值类型再确定变量类型。
1.1 赋值
因此,Python变量其实是一个标签,不占内存,赋值操作完成以下两件事:为所赋的值开辟空间,确定一个唯一的id
将变量作为标签,和这个id绑定(也可以认为指向这个id)
1.2 辨析id()、is 、==id()是求常量的地址标识,一般print(A)打印的是id对应的内存内容,只有用id(A)才能求A指向的id
A is B就是比较A和B对应的id是否一致,返回值为True或False,A或B可以用常量代替
== 则是比较id对应的实际内容是否一致
1.3 B = A
实际上就是将变量A对应的id和B绑定
1.4 重新赋值
相当于重新开辟一个新空间,设置id后,将变量与此id绑定,但是注意1.2中B绑定的id原来的那个,因为B绑定的是id而不是A本身,A没有实际内存,无法指向。m = 1
s = l
m = 2
print(m is s) # False
2. 常量池
和Java类似,Python也有常量池,但是不同的是Python是小整数常量池和字符串常量池。常量池是为了节约空间,相同的内容不用重复开辟空间,在第一次被赋值的时候开辟
python只有小整数[-5, 256]才有常量池,字符串需要满足:仅仅包括下划线、数字、字母,且不能超过20个字符
常量池的存在导致一旦小整数或者字符串在常量池中建立,那么在整个程序中,给不同变量赋相同的小整数或字符串,那么它们对应的id相同,即此小整数id。非常量池的值被赋值时会重复赋值\# 非pycharm等高级IDE
m = 256
n = 256
print(m is n) #True
m = 257
n = 257
print(m is n) #False
PS. 这里有个大坑,就是其实常量池的范围还要视编译器而已,在IDLE范围见上,但是pycharm、VScode较高级的IED中,大整数和较长、带有特殊字符的字符串都是有常量池的\# pycharm等高级IDE
m = 256
n = 256
print(m is n) #True
m = 257
n = 257
print(m is n) #True
3. 浅复制和深复制
浅复制即顶层复制,只复制原结构的最高层内容,有id的部分不会继续复制下去;深复制为递归复制,只要有id就一直寻找到最终内容,将原结构完全复制下来。
举个例子:A = [1,[2,3],4]
B = A[:] # 对A浅复制
A[1][1] = -3
A[0] = -1
print(A) # [-1, [2, -3], 4]
print(B) # [1, [2, -3], 4]
可以认为A、B是二维数组,也就是A[1]和B[1]存的是id/地址,浅赋值只把A[1]也就是[2,3]的id给了B[1],[2, 3]在内存中有自己的空间,对A1操作就会改变B1,print的作用是将所有数组的内容展现出来,虽然B指向内容本身没改变,因为B指向重新开辟的空间,但是print结果会变。以下是深复制,[2,3]也重新开辟了空间:import copy
A = [1,[2,3],4]
B = copy.deepcopy(A)
A[1][1] = -3
A[0] = -1
print(A) # [-1, [2, -3], 4]
print(B) # [1, [2, 3], 4]浅复制有:没有限制条件的分片表达式(L[:])、字典 copy 方法、有些内置函数,例如 list,能够生成拷贝 list(L)
深复制有:copy标准库模块能够生成完整拷贝——deepcopy
4. 可变量
python中的可变量为list类型,即赋值后可以修改;整数、浮点、tuple等为不可变量,一旦赋值,不能修改,当然如果像tuple中内嵌了list,虽然list内容可修改,但是tuple内容本身没变,毕竟只存了list的id。
以下重点讨论字典类型中的key值不能说可变类型的原因:
python字典使用了hash表的数据结构实现,可以将查询更新表的时间代价由O(n)降到O(1):系统先初始化一个固定k个空间大小的hash表H;
建立词典时,先计算h = hash(key), 如果H[h%k]为空,则在此处存放key和value;
如果不为空,则公开寻址,常用的是线性寻址,即往(h+1)%k的方向寻找,直到找到为空的位置;
当表空间不够时,会自动扩容,即增大k,不过前面的位置要重新计算再插入;
表建立后,查询、更新则是先利用hash函数计算key对应的hash值,再求位置,计算法同上,直至找到,如果遍历完找不到则会报错。
假设key值不固定,即为list类型,计算hash值时,如果是基于内容计算(如tuple就是),由于list内容可变,那么当内容变化了,则key值对应的索引通常也会变化(hash性质);如果是基于id,则由于list类型并非存于常量池(见下代码),所以建表的list的id和查询的id不一致,key值不一致就无法对应。print([1,2] is [1,2]) #False
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。