👏作者简介:大家好,我是爱敲代码的小王,CSDN博客博主,Python小白
📕系列专栏:python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发
📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀
🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
🍂博主正在努力完成2023计划中:以梦为马,扬帆起航,2023追梦人
🔥🔥🔥 python入门到实战专栏:从入门到实战
🔥🔥🔥 Python爬虫开发专栏:从入门到实战
🔥🔥🔥 Python办公自动化专栏:从入门到实战
🔥🔥🔥 Python数据分析专栏:从入门到实战
🔥🔥🔥 Python前后端开发专栏:从入门到实战
目录
生成器推导式创建元组
字典
字典元素添加、修改、删除
序列解包
字典核心底层原理(重要)
集合
生成器推导式创建元组
1 、从形式上看,生成器推导式与列表推导式类似,只是生成器推导式使用小括号。
2 、列表推导式直接生成列表对象,生成器推导式生成的不是列表也不是元组,而是一个生成器对象。
3、我们可以通过生成器对象,转化成列表或者元组。也可以使用生成器对象的 __next__() 方法进行遍历,或者直接作为迭代器对象来使用。不管什么方式使用,元素访问结束后,如果需要重新访问其中的元素,必须重新创建该生成器对象。
【操作】生成器的使用测试
#列表推导式: [0, 2, 4, 6, 8]
#a = [x*2 for x in range(5)]
#print(a)
s = (x*2 for x in range(5))
print(s) #<generator object <genexpr> at 0x0000021C80BE2880>
b = tuple(s)
print(b) #(0, 2, 4, 6, 8)
c = tuple(s)
print(c) #()
s2 = (x for x in range(3))
print(s2.__next__()) #0
print(s2.__next__()) #1
print(s2.__next__()) #2
print(s2.__next__()) #报错:StopIteration
元组总结
1 、元组的核心特点是:不可变序列。
2 、元组的访问和处理速度比列表快。
3 、与整数和字符串一样,元组可以作为字典的键,列表则永远不能作为字典的键使用。
实时效果反馈
1. 如下代码,如下说法正确的是:
s = (x*2 for x in range(5))
A s是一个元组
B s是一个列表
C s是一个生成器对象,只能被迭代一次
D s是一个生成器对象,可以被反复迭代多次
字典
字典是“键值对”的无序可变序列,字典中的每个元素都是一个“键值 对”,包含:“键对象”和“值对象”。可以通过“键对象”实现快速获取、 删除、更新对应的“值对象”。
一个典型的字典的定义方式:
a = {'name':'gaoqi', 'age':18, 'job':'programmer'}
列表中我们通过“下标数字”找到对应的对象。字典中通过“键对象”找到对应的“值对象”。
1 “键”是任意的不可变数据,比如:整数、浮点数、字符串、元组。
2 但是:列表、字典、集合这些可变对象,不能作为“键”。
3 并且“键”不可重复。
4 “值”可以是任意的数据,并且可重复。
字典的创建
1 、我们可以通过{}、dict()来创建字典对象。
a = {'name':'gaoqi','age':18,'job':'programmer '}
b = dict(name='gaoqi',age=18,job='programmer')
a = dict([("name","gaoqi"),("age",18)])
c = {} #空的字典对象
d = dict() #空的字典对象
2、 通过zip()创建字典对象
k = ['name','age','job']
v = ['gaoqi',18,'teacher']
d = dict(zip(k,v))
print(d) #{'name': 'gaoqi', 'age': 18, 'job': 'techer'}
3 、通过fromkeys创建值为空的字典
f = dict.fromkeys(['name','age','job'])
print(f) #结果:{'name': None, 'age': None, 'job': None}
实时效果反馈
1. 关于字典,如下说法错误的是:
A 字典是“键值对”的有序可变序列
B 字典中的“值对象”可以是任意类型
C 列表对象不可以作为字典的“键对象”
D 元组对象可以作为字典的“键对象”
字典元素的访问
为了测试各种访问方法,我们这里设定一个字典对象:
a = {'name':'gaoqi','age':18,'job':'programmer'}
1 、通过 [键] 获得“值”。若键不存在,则抛出异常。
a = {'name':'gaoqi','age':18,'job':'programmer '}
b = a['name']
print(b)
2、通过get()方法获得“值”。❤️推荐使用。优点是:指定键不存在, 返回None;也可以设定指定键不存在时默认返回的对象。推荐 使用get()获取“值对象”
a = {'name':'gaoqi','age':18,'job':'programmer '}
b = a.get('name')
c = a.get('gender', '不存在')
print(b)
print(c)
3、 列出所有的键值对
a = {'name':'gaoqi','age':18,'job':'programmer '}
b = a.items()
print(b) #dict_items([('name', 'gaoqi'),('age', 18), ('job', 'programmer')])
4 、列出所有的键,列出所有的值
a = {'name':'gaoqi','age':18,'job':'programmer'}
k = a.keys()
v = a.values()
print(k) #dict_keys(['name', 'age','job'])
print(v) #dict_values(['gaoqi', 18,'programmer'])
5、 len() 键值对的个数
a = {'name':'gaoqi','age':18,'job':'programmer '}
num = len(a)
print(num) #3
6 、检测一个“键”是否在字典中
a = {'name':'gaoqi','age':18,'job':'programmer '}
print("name" in a) #True
实时效果反馈
1. 如下代码,如下说法正确的是:
a = {'name':'gaoqi','age':18,'job':'programmer'}
c = a.get('gender', '一个男人')
A 会报错
B 变量 c 是 None
C 变量 c 是 一个男人
D 变量 c 是 空字符串
字典元素添加、修改、删除
1、 给字典新增“键值对”。如果“键”已经存在,则覆盖旧的键值对; 如果“键”不存在,则新增“键值对”
a = {'name':'gaoqi','age':18,'job':'programmer '}
a['address']='西三旗1号院'
a['age']=16
print(a)
#{'name': 'gaoqi', 'age': 16, 'job': 'programmer', 'address': '西三旗1号院'}
2、 使用 update() 将新字典中所有键值对全部添加到旧字典对象上。如 果 key 有重复,则直接覆盖
a = {'name':'gaoqi','age':18,'job':'programmer '}
b = {'name':'gaoxixi','money':1000,'gender':'男的'}
a.update(b)
print(a)
#{'name': 'gaoxixi', 'age': 18, 'job': 'programmer', 'money': 1000, 'gender': '男的'}
3 、字典中元素的删除,可以使用 del() 方法;或者 clear() 删除所有键值 对; pop() 删除指定键值对,并返回对应的“值对象”
a = {'name':'gaoqi','age':18,'job':'programmer '}
del(a['name'])
print(a) #{'age': 18, 'job': 'programmer'}
age = a.pop('age')
print(age) #18
4 、popitem() :随机删除和返回该键值对。字典是“无序可变序列”, 因此没有第一个元素、最后一个元素的概念; popitem 弹出随机的项,因为字典并没有"最后的元素"或者其他有关顺序的概念。若想一个接一个地移除并处理项,这个方法就非常有效(因为不用首先获取键的列表)
a = {'name':'gaoqi','age':18,'job':'programmer '}
r1 = a.popitem()
r2 = a.popitem()
r3 = a.popitem()
print(a) #{}
实时效果反馈
1. 如下代码,说法正确的是:
a = {'name':'gaoqi','age':18,'job':'programmer'}
a['address']='西三旗1号院'
a['age']=16
A 字典a中会有两个age键值对: age:18, age:16
B 字典a中只有一个age: age:18
C 字典a中只有一个age: age:16
D 会报错。
序列解包
序列解包可以用于元组、列表、字典。序列解包可以让我们方便的对多个变量赋值。
x,y,z=(20,30,10)
(a,b,c)=(9,8,10)
[m,n,p]=[10,20,30]
序列解包用于字典时,默认是对“键”进行操作; 如果需要对键值对操作,则需要使用items();如果需要对“值”进行操作,则需要使用 values();
s = {'name':'gaoqi','age':18,'job':'teacher'}
name,age,job=s #默认对键进行操作
print(name) #name
name,age,job=s.items() #对键值对进行操作
print(name) #('name', 'gaoqi')
name,age,job=s.values() #对值进行操作
print(name) #gaoqi
实时效果反馈
1. 如下代码,如下说法正确的是:
s = {'name':'gaoqi','age':18,'job':'teacher'}
a,b,c=s
A 变量a的值是s
B 变量a的值是字符串"name"
C 变量a的值是字符串"gaoqi"
D 会报错
表格数据使用字典和列表存储和访问
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(len(tb)): # i -->0,1,2
print(tb[i].get("salary"))
#打印表的所有数据
for i in range(len(tb)):
print(tb[i].get("name"),tb[i].get("age"),tb[i].get("salary"),tb[i].get("city"))
实时效果反馈
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[2].get("city"))
A "city":"深圳"
B 上海
C 北京
D 深圳
字典核心底层原理(重要)
字典对象的核心是散列表。散列表是一个稀疏数组(总是有空白元素的数组),数组的每个单元叫做 bucket 。每个 bucket 有两部分:一 个是键对象的引用,一个是值对象的引用。
由于,所有 bucket 结构和大小一致,我们可以通过偏移量来读取指定 bucket 。
将一个键值对放进字典的底层过程
a = {}
a["name"]="xiao"
假设字典a对象创建完后,数组长度为8:
我们要把”name”=”gaoqi”这个键值对放到字典对象a中,首先第一步需要计算键”name”的散列值。Python中可以通过hash()来计算。
>>> bin(hash("name"))
'-0b1010111101001110110101100100101'
由于数组长度为8,我们可以拿计算出的散列值的最右边3位数字作为偏移量,即“101”,十进制是数字5。我们查看偏移量5,对应的 bucket是否为空。如果为空,则将键值对放进去。如果不为空,则 依次取右边3位作为偏移量,即“100”,十进制是数字4。再查看偏移量为4的bucket是否为空。直到找到为空的bucket将键值对放进去。流程图如下:
扩容
1、python会根据散列表的拥挤程度扩容。“扩容”指的是:创造更大的数组,将原有内容拷贝到新数组 中。
2 、接近2/3时,数组就会扩容。
根据键查找“键值对”的底层过程
明白了,一个键值对是如何存储到数组中的,根据键对象取到值对象,理解起来就简单了。
>>> a.get("name")
'tong'
当调用a.get(“name”),就是根据键“name”查找到“键值对”,从而找到值对象“gaoqi”。 我们仍然要首先计算“name”对象的散列值:
>>> bin(hash("name"))
'-0b1010111101001110110101100100101'
和存储的底层流程算法一致,也是依次取散列值的不同位置的数 字。 假设数组长度为8,我们可以拿计算出的散列值的最右边3位数 字作为偏移量,即 101 ,十进制是数字5。我们查看偏移量5,对应的 bucket 是否为空。如果为空,则返回 None 。如果不为空,则将这个 bucket 的键对象计算对应散列值,和我们的散列值进行比较,如果相等。则将对应“值对象”返回。如果不相等,则再依次取其他几位 数字,重新计算偏移量。依次取完后,仍然没有找到。则返回 None 。流程图如下:
用法总结:
1 字典在内存中开销巨大,典型的空间换时间。
2 键查询速度很快
3 往字典里面添加新键值对可能导致扩容,导致散列表中键的 次序变化。因此,不要在遍历字典的同时进行字典的修改
4 键必须可散列
4.1 数字、字符串、元组,都是可散列的
4.2 自定义对象需要支持下面三点:(面向对象章节中再展开说)
4.2.1 支持 hash() 函数
4.2.2 支持通过 __eq__() 方法检测相等性
4.2.3 若 a==b 为真,则 hash(a)==hash(b) 也为真
集合
集合是无序可变,元素不能重复。实际上,集合底层是字典实现, 集合的所有元素都是字典中的“键对象”,因此是不能重复的且唯一 的。
集合创建和删除
1、使用{}创建集合对象,并使用add()方法添加元素
a = {3,5,7}
a.add(9) #{9, 3, 5, 7}
2、 使用set(),将列表、元组等可迭代对象转成集合。如果原来数据 存在重复数据,则只保留一个
a = ['a','b','c','b']
b = set(a) #{'b', 'a', 'c'}
3、 remove()删除指定元素;clear()清空整个集合
a = {10,20,30,40,50}
a.remove(20) #{10, 50, 40,30}
集合相关操作
像数学中概念一样,Python对集合也提供了并集、交集、差集等运算。我们给出示例:
>>> a = {1,3,'sxt'}
>>> b = {'he','it','sxt'}
>>> a|b #并集
{1, 3, 'sxt', 'he', 'it'}
>>> a&b #交集
{'sxt'}
>>> a-b #差集
{1, 3}
>>> a.union(b) #并集
{1, 3, 'sxt', 'he', 'it'}
>>> a.intersection(b) #交集
{'sxt'}
>>> a.difference(b) #差集
{1, 3}
实时效果反馈
1. 关于集合,如下说法正确的是:
A 集合是有序可变,元素不能重复
B 集合底层是字典,集合的所有元素都是字典中的“键对象”,因此 不能重复
C 集合是无序可变,元素可以重复
D 集合底层是列表