一、字典
(一)字典简介
- 字典是“键值对”的无序可变序列。可以通过键对象实现快速获取、删除、更新对应的值对象。
- “键”是任意不可变数据:
整数、浮点数、字符串、元组
,但是列表、字典、集合
这些可变对象不能作为“键”,并且“键”不可重复。
(二)字典的创建(3种)
- 通过
{}、dict()
创建字典对象
# 方法一
dictname = {"key"/key:"value"/value,...}
# 方法二
dictname = dict(key="value"/value,...)
# 方法三 列表和元组共同创建字典对象,键值对以元组的形式放在列表里
dictname = dict([("key"/key,"value"/value),("key"/key,"value"/value),...])
# 创建空的字典对象
dictname = {}
dictname = dict()
-
通过
zip()
创建字典对象
-
通过
fromkeys
创建值为空None的字典对象
# 列表里是所有的key
dictname = dict.fromkeys(["key",...])
(三)字典元素的访问
- 通过【键】获得“值”,若键不存在,则抛出异常。
dictname["key"]
- 通过
get()
方法获得“值”,推荐使用。优点是:指定键不存在,返回None;也可以设定指定键不存在时默认返回的对象。推荐使用get()
获取“值对象”
dictname.get("key",[default object])
- 列出所有的键值对(遍历)
# 列出所有的键值对,键值对以元组形式存在列表种返回
dictname.items()
- 列出所有的键,列出所有的值
# 列出所有的键
dictname.keys()
# 列出所有的值
dictname.values()
len()
键值对的个数
b = dict(name="Cairo",age=18,job="programmer")
len(b)
3
- 检测一个“键”是否在字典中
b = dict(name="Cairo",age=18,job="programmer")
"name" in b
True
(四)字典元素添加、修改、删除
- 给字典新增“键值对”,如果“键”已经存在,则覆盖旧的键值对;如果“键”不存在,则新增键值对。
dic = {'name': 'Cairo', 'age': 18, 'job': 'programmer'}
dic["name"] = "Quinn"
dic["name"]
'Quinn'
dic["sex"] = "female"
dic["sex"]
'female'
dic
{'name': 'Quinn', 'age': 18, 'job': 'programmer', 'sex': 'female'}
- 使用update()将新字典中所有键值对全部添加到旧字典对象上。如果key有重复,则直接覆盖。
dic
{'name': 'Quinn', 'age': 18, 'job': 'programmer', 'sex': 'female'}
dic1 = {'name': 'Lisa', 'age': 20, 'job': 'programmer'}
# dic覆盖dic1,用后者覆盖前者
dic1.update(dic)
dic1
{'name': 'Quinn', 'age': 18, 'job': 'programmer', 'sex': 'female'}
- 字典中元素的删除,可以使用del()方法;或者clear()删除所有键值对;pop()删除指定键值对,并返回对应的“值对象”。
del element["key"]
dictname.clear()
dictname.pop("key")
popitem()
:随机删除和返回该键值对。字典是“无序可变序列”,因此没有第一个元素,最后一个元素的概念;popitem弹出随机的项,因为字典并没有“最后的元素”或者其他有关顺序的概念。若想一个接一个地移除并处理项,这个方法就非常有效(因为不用首先获取键的列表)
dictname.popitem()
(五)序列解包
序列解包可以用于元组、列表、字典。序列解包可以让我们方便的对多个变量赋值。
x,y,z = (10,20,30)
x
10
(a,b,c) = (10,20,30)
a
10
[a,b,c] = [1,2,4]
a
1
序列解包应用于字典时,默认对“键”进行操作;如果需要对键值对进行操作,则需要使用items()
;如果需要对“值”进行操作,则需要使用values()
键值对返回的是一个元组,如果要访问具体的键or值,可以通过name[0]\name[1]
来访问
(六)表格数据使用字典和列表存储,并实现访问
r1 = {"name":"高小一","age":18,"salary":30000,"city":"北京"}
r2 = {"name":"高小二","age":19,"salary":20000,"city":"上海"}
r3 = {"name":"高小五","age":20,"salary":10000,"city":"深圳"}
tb = [r1,r2,r3]
# 获得第二行人的薪资
print(tb[1].get("salary"))
# 打印表中所有的薪资
for i in range(3):
print(tb[i].get("salary"))
# 打印表中所有的数据
for i in range(3):
print(tb[i].get("name"),tb[i].get("age"),tb[i].get("salary"),tb[i].get("city"))
(七)字典底层的核心原理
字典对象的核心是散列表。散列表是一个稀疏数组(总是有空白元素的数组),数组每个单元叫做bucket。每个bucket有两部分:一个是键对象,一个是值对象的引用。
由于所有bucket结构和大小一致,我们可以通过偏移量来读取指定bucket。
将一个键值对放进字典的底层过程
假设字典对象dic创建完后,数组长度为8:
- 首先计算对应的key值的hashcode,通过
hash()
计算,计算出name的hashcode - 由于数组的长度为8,所以可以用计算出的散列值的后3位,将其作为偏移量,查看对应的bucket是否为空,如果不为空,依次向左取3位作为偏移量,直到找到为空的bucket为止。
【注】Python会根据散列表的拥挤程度扩容(创建更大的数组,将原数组拷贝到新数组中),接近2/3时,数组就会扩容。
根据键查找“键值对”的底层过程
- 计算对应的key的hashcode
- 依次从右向左取3位到字典对象dic中查找相应位置存储的值是否是key的hashcode,如果是则取出对应位置的值,否则继续向左取出3位进行比对,如果最后没有的话,返回
None
用法总结
- 键必须可散列
【1】数字、字符串、元组都是可散列的
【2】自定义对象要支持以下3点:支持hash
函数;支持通过__eq__()
方法检测相等性;若a==b
为真,则hash(a)==hash(b)
也为真。 - 字典在内存中开销巨大,典型的空间换时间
- 键查询速度很快
- 往字典里添加新建可能导致扩容,导致散列表中的键的次序变化。因此不要在遍历字典的同时进行字典的修改。
【不要边遍历边修改,先遍历再修改不要一起操作】
二、集合
集合是无序可变,元素不能重复。实际上,集合底层是字典实现,集合的所有元素都是字典的key对象,因此是不能重复的 。
(一)集合创建和删除
-
使用{}创建集合对象,并使用add()方法添加元素
-
使用set(),将列表、元组等可迭代对象转成集合。如果原来数据存在重复数据,则只保留一个
-
remove()删除指定元素;clear()清空整个集合
(二)集合相关操作
和数学中一样的交并补
a = {1,2,'sxt'}
b = {"he","is","sxt"}
# 并运算
a|b
{1, 2, 'sxt', 'is', 'he'}
a.union(b)
{1, 2, 'sxt', 'is', 'he'}
# 交运算
a&b
{'sxt'}
a.intersection(b)
{'sxt'}
# 差集
a-b
{1, 2}
a.difference(b)
{1, 2}
第4章 控制语句
控制语句是代码的组织方式。
一、选择结构
选择结构通过判断条件是否成立,来决定执行哪个分支。选择结构有多种形式,分为:单分 支、双分支、多分支。流程图如下:
(一)单分支选择结构
if 语句单分支结构的语法形式如下:
if 条件表达式:
语句/语句块
其中:
- 条件表达式:可以是逻辑表达式、关系表达式、算术表达式等等。
- 语句/语句块:可以是一条语句,也可以是多条语句。多条语句,缩进必须对齐一致。
num = int(input("please input the number:"))
if num<10:
print(num)
(二)条件表达式详解
- 在选择和循环结构中,条件表达式的值为 False 的情况如下:
False、0、0.0、空值 None、空序列对象(空列表、空元组、空集合、空字典、空字符串)、空 range 对象、空迭代对象
。 其他情况,均为 True。这么看来,Python 所有的合法表达式都可以看做条件表达式,甚至包括函数调用的表达式。 - 在Python中,条件表达式中不允许出现赋值操作符“=”,如果出现会报错:(在Java/C++中不会报错)
(三)双分支选择结构
双分支结构的语法格式如下:
if 条件表达式 :
语句 1/语句块 1
else:
语句 2/语句块 2
(四)三元条件运算符
用来在某些简单双分支赋值的情况。
条件为True时的值 if (条件表达式) else 条件为False时的值
(五)多分支选择结构
多分支选择结构的语法格式如下: 【多分支结构,几个分支之间是有逻辑关系的,不能随意颠倒次序】
if 条件表达式 1 :
语句 1/语句块 1
elif 条件表达式 2:
语句 2/语句块 2
...
elif 条件表达式 n :
语句 n/语句块 n
[else:语句 n+1/语句块 n+1 ]
【操作】输入一个学生的成绩,将其转化成简单描述:不及格(小于 60)、及格(60-79)、良 好(80-89)、优秀(90-100)。
# 方法一 使用完整的条件表达
# 每个分支都使用了独立的、完整的判断,顺序可以随意移动,而不影响程序的运行顺序
score = int(input("请输入分数"))
grade = ''
if(score<60): grade = "不及格"
if(60<=score<80): grade = "及格"
if(80<=score<90): grade = "良好"
if(90<=score<=100): grade = "优秀"
print("分数是{0},等级是{1}".format(score,grade))
# 方法二 使用多分支结构
# 多分支结构,几个分支之间是有逻辑关系的,不能随意颠倒顺序
score = int(input("请输入分数"))
grade = ''
if score<60 : grade = "不及格"
elif score<80 : grade = "及格"
elif score<90 : grade = "良好"
elif score<=100: grade = "优秀"
print("分数是{0},等级是{1}".format(score,grade))
(六)选择结构嵌套
选择结构可以嵌套,使用时一定要注意控制好不同级别代码块的缩进量,因为缩进量决定了代码的从属关系。
语法格式如下:
if 表达式 1:
语句块 1
if 表达式 2:
语句块 2
else:
语句块 3
else:
if 表达式 4:
语句块 4
【操作】输入一个分数。分数在 0-100 之间。90 以上是 A,80 以上是 B,70 以上是 C,60 以上是 D。60 以下是 E。(下标和字母对应)
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]))
二、循环结构
循环结构用来重复执行一条或多条语句。表达这样的逻辑:如果符合条件,则反 复执行循环体里的语句。在每次执行完后都会判断一次条件是否为 True,如果 为 True 则重复执行循环体里的语句。图示如下:
循环体里面的语句至少应该包含改变条件表达式的语句,以使循环趋于结束;否 则,就会变成一个死循环。
(一)while循环
while 循环的语法格式如下:
while 条件表达式:
循环体语句
【操作】利用 while 循环,计算 1-100 之间数字的累加和;计算 1-100 之间偶数的累加和, 计算 1-100 之间奇数的累加和。
sum = 0
sum1 = 0
sum2 = 0
i=1
# for i in range(1,101):
while i < 101:
sum += i
if i&1 == 0:
sum2 += i
else:
sum1 += i
print("所有数字累加和={}".format(sum))
print("所有偶数累加和={}".format(sum2))
print("所有奇数累加和={}".format(sum1))