一、id is ==
# id
# s = 'Jason'
# print(id(s)) # id的值是随机的
#
# l1 = [1, 2, 3]
# l2 = [1, 2, 3]
# print(l1 == l2) # 结果为True,== 比较的是两边的值是否相等
# is 判断的是内存地址是否相同
l1 = [1, 2, 3]
l2 = [1, 2, 3]
print(l1 is l2) # 结果为false,因为l1和l2分别创建了两个内存地址
s1 = 'Jason'
s2 = 'Jason'
print(s1 is s2) # 结果为True,因为字符串只占一个内存地址
"""
id相同,值肯定相同;
值相同,id不一定相同
"""
二、代码块
Python程序是由代码块构造的。块是一个python程序的文本,它是作为一个单元执行的。
代码块:一个模块,一个函数,一个类,一个文件等都是一个代码块。
作为交互方式(cmd进入python解释器)输入的每个命令都是一个代码块。
两个机制:同一个代码块下,有一个机制;不同代码块下,遵循另一个机制。
1. 同一个代码块下的缓存机制:
在同一个代码块下遇到初始化对象的命令时,会将初始化的变量和值放在一个字典中,在遇到新的变量时,先到字典中去查找有没有相同的值,如果有,则重复使用该值。
-
优点:提升性能,节省内存
-
适用对象
int(float):任何数字在同一代码块下都会复用。
i1 = 1 i2 = 1 i3 = 1 print(i1 is i2 is i3) # 结果为True
str:
- 非乘法得到的字符串都满足代码块的缓存机制:
s1 = '三上悠亚 aloha !@#*(' s2 = '三上悠亚 aloha !@#*(' s3 = '三上悠亚 aloha !@#*(' print(s1 is s2 is s3) # 结果为True
- 乘数为1时,任何字符串满足代码块的缓存机制:
s1 = '三上悠亚 aloha !@#*(' * 1 s2 = '三上悠亚 aloha !@#*(' * 1 s3 = '三上悠亚 aloha !@#*(' * 1 print(s1 is s2 is s3) # 结果为True
- 乘数>=2时:字符串仅包含大小写字母,数字,下划线,相乘之后总长度<=20,满足代码块的缓存机制:
s1 = '三上悠亚 aloha !@#*(' * 2 s2 = '三上悠亚 aloha !@#*(' * 2 s3 = '三上悠亚 aloha !@#*(' * 2 print(s1 is s2 is s3) # 结果为False s1 = 'Aloha_' * 3 s2 = 'Aloha_' * 3 s3 = 'Aloha_' * 3 print(s1 is s2 is s3) # 结果为True
bool:True和False在字典中会以1,0方式存在,并且复用
2. 不同代码块下的缓存机制:小数据池
在不同代码块下 数字-5~256 和一定规则的字符串可以复用。
优点:提升性能,节省内存
三、集合(set)
-
集合是一种可迭代的、无序的、不能包含重复元素的数据结构
-
集合是一种容器型数据类型
-
集合中的元素都是不可变的(可哈希)元素,而集合本身是可变的数据类型。
即集合中不能有列表(list)、字典(dict)、集合(set),可以放数字(int)、字符串(str)、布尔值(bool)
-
集合的作用:1.列表去重
2.关系测试:交集、并集、差集
- 利用集合的特性给列表去重, 但是不能保持原来的顺序
list1 = [1, 2, 2, 2, 2, 3, 3, 3, 'jason', 'jason']
set1 = set(list1)
list1 = list(set1)
print(list1)
- 集合增删改查
#集合的创建
set1 = {1, 3, 'jason', True, False}
print(set1)
set1 = {'jason', 'carly', 'aloha'}
# 增
# add()
set1.add('sb')
print(set1)
# update()迭代增加
set1.update('abc')
print(set1)
# 删
# remove()按照元素删除
set1.remove('aloha')
print(set1)
# pop()随机删除
set1.pop()
print(set1)
# clear()清空集合
set1.clear()
print(set1)
# del 删除集合
del set1
# 改(变相改值,先删再加)
- 集合的交集、并集、差集、反交集
set1 = {1, 2, 3, 4, 5}
set2 = {3, 4, 5, 6, 7}
# 交集
print(set1 & set2)
print(set1.intersection(set2))
# 并集
print(set1 | set2)
print(set1.union(set2))
# 差集
print(set1 - set2)
print(set2 - set1)
print(set1.difference(set2))
print(set2.difference(set2))
# 反交集
print(set1 ^ set2)
print(set1.symmetric_difference(set2))
- 集合的子集、超集
set1 = {1, 2, 3}
set2 = {1, 2, 3, 4, 5, 6}
# 子集
print(set1 < set2)
print(set1.issubset(set2))
# 超集
print(set2 > set1)
print(set2.issuperset(set1))
四、深浅拷贝
1.赋值运算
赋值运算让两个列表的内存地址一样, 即id相同,因此不管是修改list1,还是修改list2,另一个列表也会随之改变
list1 = [1, 2, 3, [11, 22, 33]]
list2 = list1
print(id(list1) == id(list2))
# 结果为True,此时list1 和list2 的id是一样的
list1.insert(-1, 666)
list2.pop(1)
list1[-1].append(888)
list2[-1].append(999)
print(list1)
print(list2) # list1 和 list2 结果一样
2.浅copy
list1 = [1, 2, [11, 22]]
list2 = list1.copy()
print(list1 == list2) # True
print(id(list1) == id(list2)) # False
# 浅copy: 值相同,但是id不同
list1被创建的时候,内存中被创建了1,2和[11, 22]这三个元素,
我们可以理解成这三个元素放在了内存的某个空间里。
假设list1的id为11111111,则它的三个槽位分别指向这个空间里的1,2,[11, 22]
此时list1浅copy得到了id为22222222的list2,
list2的三个槽位也是分别指向这个空间里的1,2,[11, 22]
# 情况一、如果我们在list1这个列表进行修改,比如追加一个元素,删除一个元素,甚至是清空list1,仅仅是对id为11111111的list1进行了修改,而放在该空间中的1,2,[11, 22]并没有变化。
# 此时list2中的各个槽位指向的仍是该空间中的1,2,[11, 22],因此list2不会改变。
list1 = [1, 2, [11, 22]]
list2 = list1.copy()
list1.append(3)
print(list1) # 结果为[1, 2, [11, 22], 3]
print(list2) # 结果为[1, 2, [11, 22]]
# 情况二、如果我们对list1中的[11, 22]进行修改,此时对应在内存中的[11, 22]也会改变。
# 而list2中的[11, 22]也是指向内存中的[11, 22], 内存中的[11, 22]改变了,因此list2中的[11, 22]也随之改变
list1 = [1, 2, [11, 22]]
list2 = list1.copy()
list1[2].append(666)
print(list1)
print(list2)
3.深copy 需要导入copy模块
import copy
list1 = [1, 2, [11, 22]]
list2 = copy.deepcopy(list1)
print(list1 == list2)
print(id(list1) == id(list2))
# 和浅copy一样,值相同,内存地址不同
list1被创建的时候,内存中被创建了1,2,[11, 22]这三个元素, 我们可以理解成这三个元素放在内存的空间一里面
假设list1的id为11111111,则它的三个槽位分别指向空间一里面的1,2,[11, 22]
此时list1深copy得到了id为22222222的list2,与浅copy不同的是,此时内存中在一次创建了1,2,[11, 22]这三个元素,并放在了内存的空间二里面
此时list2的三个槽位分别指向空间二里面的1,2,[11, 22]
此时对list1进行修改,无论怎么修改,list2始终不变,因为list1和list2此时没有任何的关联
import copy
list1 = [1, 2, [11, 22]]
list2 = copy.deepcopy(list1)
list1.append(3)
list1[2].append(666)
print(list1) # 结果为[1, 2, [11, 22, 666], 3]
print(list2) # 结果为[1, 2, [11, 22]]
注意:前面理解说两个空间里都有 1,2,[11, 22],这是标准的深copy情形。
但是python做了优化,为了节省内存空间,在python中,int(float) 、str、bool这种不可变的数据类型在内存中只存在一个,因为他们的id都是一样的。