字典:(拓展–重要)字典核心底层原理
字典对象的核心是散列表,散列表是一个稀疏数组(总是有空白元素的数组),数组的每个单元叫做bucket。
每个bucket 有两部分:一个是键对象的引用,一个是值对象的引用。又因所有bucket 结构和大小一致,就可以通过偏移量来读取指定bucket。
将一个键值对放进字典的底层过程
创建一个空字典,假设字典a 对象创建完后,数组长度为8。
创建一个键值对"name"=“张三”,把这个键值对放到字典对象a中第一步需要计算键”name”的散列值。Python 中可以通过hash()来计算。
a = {}
a["name"]="张三"
bin(hash("name")) # '-0b1010111101001110110101100100101'
前假设数组长度为8,偏移量(索引)0-7可用二进制数000-111表示。此时可将散列值的最右边3位数字作为偏移量,即101=5。查看偏移量5对应的bucket 是否为空,为空则存放键值对,不为空则依次取右边3位作为偏移量,如100=4。再查看偏移量为4的bucket是否为空,直到找到为空的bucket 将键值对存放进去。当存放多个键值对散列表的拥挤接近2/3时,数组就会扩容(创造更大的数组,将原有内容拷贝到新数组中。)流程图如下:
根据键查找“键值对”的底层过程
调用a.get(“name”),根据键“name”查找到“键值对”,从而找到值对象。先计算“name”对象的散列值: ‘-0b1010111101001110110101100100101’。假设数组长度为8,拿计算出的散列值最右边3位数字作为偏移量,即101=5,查看偏移量5对应的bucket是否为空。如果为空则返回None,不为空则将这个bucket的键对象计算对应散列值,并和查找的散列值进行比较。如果相等则返回对应“值对象”,若不相等则再依次向前取数,重新计算偏移量并比较查找值的散列值。依次取完后仍然没有找到,则返None。流程图如下:
总结:
键必须可散列,数字、字符串、元组,都是可散列的。
自定义对象需要支持下面三点:
支持hash()函数
支持通过__eq__()方法检测相等性
若a==b为真,则hash(a)==hash(b)也为真
字典键查询速度很快
字典在内存中开销巨大,是以空间换时间的典型
往字典里面添加新建可能导致扩容,从而导致散列表中键的次序变化。因此,不要在遍历字典的同时进行字典的修改。
集合
集合无序可变,但元素不能重复。实际上集合底层是字典实现,集合的所有元素都是字典中的“键对象”,因此唯一且不能重复。
集合的创建
{}创建集合
使用{}创建集合对象,并可用add()方法添加元素
a = {1,2,3}
a.add(6)
print(a) # {1, 2, 3, 6}
set()创建集合
set()可将列表、元组等可迭代对象转成集合。如果原来数据存在重复数据,则自动去重只保留一个。
a = [1,3,5,7,3,5]
b = set(a)
print(b) # {1, 3, 5, 7}
集合的删除
remove()删除指定元素;clear()清空整个集合
a = {1,2,3,4,5}
a.remove(4)
print(a) # {1, 2, 3, 5}
a.clear()
print(a) # set()
集合特有操作
集合特有并集、交集、差集等运算
a = {1,3,7,'a','c','e'}
b = {1,2,3,'a','b'}
# 并集
a|b # {'e', 1, 2, 3, 'a', 7, 'c', 'b'}
a.union(b) # {'e', 1, 2, 3, 'a', 7, 'c', 'b'}
# 交集
a&b # {1, 3, 'a'}
a.intersection(b) # {1, 3, 'a'}
# 差集
a-b # {'e', 'c', 7}
b-a # {'b', 2}
b.difference(a) # {'b', 2}
控制语句
选择结构
选择结构通过判断条件是否成立,来决定执行哪个分支,可分为单分支、双分支、多分支。
单分支选择结构
if 语句单分支结构的语法形式如下:
if 条件表达式:
语句/语句块
num = input("请输入一个数字:")
if int(num)<10: # input从外部读取的是字符串类型,需要通过int()转换成整形,判断逻辑表达式
print(num)
条件表达式:可以是逻辑表达式、关系表达式、算术表达式等等。不能出现赋值操作符“=”,会报错。可用关系运算符“==”。
语句/语句块:可以是一条语句,也可以是多条语句。多条语句,缩进必须对齐一致。
条件表达式的值为False 的情况
经过判断为False,Fales值,None值
数值:0,0.0
空序列对象(空列表、空元祖、空集合、空字典、空字符串)
空range 对象、空迭代对象
a = [] # 空列表,是False
if a:
print( "空列表,False" )
b = "False" # 非空字符串,是True
if b:
print("非空字符串,是True")
c = False
if c:
print("False,是False")
c = None
if not c:
print("None,是False")
双分支选择结构
双分支结构的语法格式如下:
if 条件表达式:
语句1/语句块1
else:
语句2/语句块2
重点–三元条件运算符:
三元运算符,用在某些简单双分支赋值情况。三元条件运算符语法格式如下:
条件为真时的值 if 条件表达式 else 条件为假时的值
#普通双分支结构
num = input("输入一个数字:")
if int(num)<10:
print(num)
else:
print("数字大于等于10")
#简易三元条件结构
num = input("请输入一个数字:")
print( num if int(num)<10 else "数字大于等于10") # 真值 if 条件 else 假值
多分支选择结构
多分支结构,几个分支之间存在逻辑关系,不能随意颠倒顺序。
多分支选择结构的语法格式如下:
if 条件表达式1 :
语句1/语句块1
elif 条件表达式2:
语句2/语句块2
…
elif 条件表达式n :
语句n/语句块n
[else:
语句n+1/语句块n+1
]
x = int(input("请输入x坐标:"))
y = int(input("请输入y 坐标:"))
if (x == 0 and y == 0):
print("原点")
elif (x == 0):
print("y 轴")
elif (y == 0):
print("x 轴")
elif (x > 0 and y > 0):
print("第一象限")
elif (x < 0 and y > 0):
print("第二象限")
elif (x < 0 and y < 0):
print("第三象限")
else:
print("第四象限")
选择结构嵌套
选择结构可以嵌套,重点注意不同级别代码块的缩进量,因为缩进量决定了代码的从属关系。语法格式如下:
if 表达式1:
语句块1
if 表达式2:
语句块2
else:
语句块3
else:
if 表达式4:
语句块4
score = int(input("请输入一个在0-100 之间的数字:"))
grade = ""
if score > 100 or score < 0:
score = int(input("输入错误!请重新输入一个在0-100 之间的数字:"))
else:
if score >= 90:
grade = "A"
elif score >= 80:
grade = 'B'
elif score >= 70:
grade = 'C'
elif score >= 60:
grade = 'D'
else:
grade = 'E'
print("分数为{0},等级为{1}".format(score, grade))
# 应用字符串切片的方法
score = int(input("请输入一个在0-100 之间的数字:"))
degree = "ABCDE"
num = 0
if score > 100 or score < 0:
score = int(input("输入错误!请重新输入一个在0-100 之间的数字:"))
else:
num = score // 10
if num < 6:
num = 5
print("分数是{0},等级是{1}".format(score, degree[9 - num]))
分享到: