数据结构
0. 数据结构
数据结构指计算机中数据存储的方式。
0.1 序列(sequence)
序列(sequence) :python中最基本的一种数据结构,用于保存有序的数据。序列中所有的数据都有唯一的位置(索引),序列按照数据添加的顺序分配索引。
序列分为两大类:可变序列,不可变序列
- 可变序列:序列中的元素可以改变,包括:列表list、
- 不可变序列:序列中的元素不可以改变,包括:字符串str,元组tuple,
序列的通用操作:索引或切片查找、s.count(x)、 s.index(x)、len(s)、加号+拼接序列,乘号*重复序列、in/not in、min(s)、max(s)
序列的优点:存储数据性能好,存储整齐,便于批量取数。
序列的缺点:查询性能差,需要一个一个元素顺序查询。类似于看书没有目录,想要找到某一个章节,需要从第一页开始翻找。
0.2 映射(mapping)
映射:python中的一种数据结构。
映射的优点:查询性能好。类似于看书有了目录,可以直接找到所需的章节,而不需要从一页一页翻找。
0.3 常用数据结构总结
中文名 | 英文名 | 形式 | 是否有序 | 是否可索引 | 是否可修改元素(改值、排序、新增、删除等) |
---|---|---|---|---|---|
列表 | list | [元素1, 元素2] | 是 | 是 | 是(Mutable) |
元组 | tuple | (元素1, 元素2) | 是 | 是 | 否(Immutable) |
字典 | dictionary | {key1:value, key2:value} | 否 | 是(用key检索) | keys: 否(Immutable);values:是(Mutable) |
集合 | set | (元素1, 元素2) | 否 | 否 | 否(Immutable) |
1. 列表 list
列表:有序的序列,没有固定大小,能够保存任意数量、任意类型的对象。
- 列表的表示形式 list = [a,b,c,d]。其中,中括号[] 代表列表的范围,[]以内的都是这个列表的元素;逗号,将列表中每个元素分开。
- 也可以把列表看作用于存储对象的对象。
列表中的内容可更改 (mutable),可以增加 (append, extend)、插入 (insert)、删除 (remove, pop, del) 列表中的元素。
1.1 创建列表
- 用 [] 创建空列表
x = [] #创建空列表
- 枚举创建列表
x = [2, 3, 4, 5, 6, 7]
x = ['a', 1, [1,4], 3.14, print,True] #创建混合列表
print (x)
# 运行结果
# ['a', 1, [1, 4], 3.14, <built-in function print>, True]
- 用range创建列表
x = list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
x = list(range(1, 11, 2)) # [ 1, 3, 5, 7, 9]
x = list(range(10, 1, -2)) # [ 10, 8, 6, 4, 2]
- 用循环函数创建列表
x = [0 for i in range(5)] # [0, 0, 0, 0, 0]
x = [i for i in range(5)] # [0, 1, 2, 3, 4]
x = [i for i in range(1, 10, 2)] # [1, 3, 5, 7, 9]
x = [i for i in range(10, 1, -2)] # [10, 8, 6, 4, 2]
x = [i ** 2 for i in range(1, 10)] # [1, 4, 9, 16, 25, 36, 49, 64, 81]
x = [i for i in range(40) if (i % 2) != 0 and (i % 3) == 0] # [3, 9, 15, 21, 27, 33, 39]
- 创建只包含0元素的列表
x = [0] * 4 # [0, 0, 0, 0, 0]
x = [[0]*3]*4 # [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
注意:由于列表的元素可以是任何对象,因此列表中保存的是对象的指针。例如,当创建一个列表[1,2,3]时,系统里实际上创建了3个指针和3个整数对象。
- x = [a] * 4操作中,创建了指向同一对象[a]的4个指针,所以一旦改变a,列表x中4个元素a都会改变。
x = [[0]*3]*4 # [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
x [0][0] = 1 #修改列表第一个元素里的第一个数值
print(x) # [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]] #列表所有元素的第一个数值都会被修改
1.1.1 列表方法method
列表方法:与具体的列表密切相关的函数。当调用列表方法时,需要先声明具体列表,调用语法为:列表名my_list.方法名method(x)
列表方法使用时,一般都会对列表中指定的元素obj或者位置index进行操作。因此,列表方法的调用与列表本身息息相关。
常用的列表方法:s.append(x), s.extend(x), s.insert(x), s.remove(x), s.pop(x), s.index(x), s.count(x)
- 对my_list.count(x)的中文理解:在变量名为my_list的列表中,计算值为x的元素的个数
- 对my_list.append(x)的中文理解:在变量名为my_list的列表末尾,增加一个值为x的元素
1.1.2 Nesting
列表中可以嵌套其他数据结构,比如列表中的元素可以是另一个列表、元组、字典等。嵌套的列表可以索引找到元素,比如:
- NL = [1,2,[2.1, 1, 2], ‘Dict’, [‘lily’,‘bob’], (‘name’, ‘sex’, (‘class’, ‘id’))]
- NL[4] 是 [‘lily’,‘bob’]
- NL[4][1] 是 ‘bob’
- NL[5][2][1] 是 ‘id’
1.2 新增列表元素
通过列表方法append()和extend()新增列表元素。注意,上述两个方法仅在列表的末尾增加元素。
-
append():(在列表末尾增加一个元素):
-
my_list.append(obj),在列表末尾添加新的对象,只接受一个参数obj。
-
该参数可以是任何数据类型,被追加的元素在 list 中保持着原结构类型。
-
extend():(扩展列表)
-
my_list.extend(seq) ,在列表末尾一次性追加另一个序列seq中的所有值。
-
用新列表扩展原列表。
#【示例】
x = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
x.append(['Thursday', 'Sunday'])
#结果:['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', ['Thursday', 'Sunday']]
x.extend(['Thursday', 'Sunday'])
#结果: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Thursday', 'Sunday']
1.3 在列表中插入元素
insert():(在列表中间某个位置插入新元素)
my_list.insert(index, obj) :在编号 index 位置插入 对象obj。
x = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
x.insert(2, 'Sunday')
#结果:['Monday', 'Tuesday', 'Sunday', 'Wednesday', 'Thursday', 'Friday']
1.4 删除列表元素
remove(obj), pop(index), del var1…,s[i:j] = []
- my_list.remove(obj) : 指定要删除的元素值obj,移除列表中该元素值的第一个匹配项。
#【示例 - remove()】
x = ['Monday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
x.remove('Monday')
print (x) # ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
- my_list.pop(index): 指定要删除的位置index,移除列表中该指定位置index的元素(如不写index,则默认删除最后一个元素),删除后返回被删除元素的值。
#【示例 - pop()】
x = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
y = x.pop() # Friday
y = x.pop(0) # Monday
y = x.pop(-2) # Thursday 即删除倒数第2个
print(x) # ['Tuesday', 'Thursday']
- del var1[, var2 ……] :指定要删除的单个或多个对象。如果要同时删除多个元素且指定需删除元素在列表中的位置,可使用del语句。
#【示例 - del】
x = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
del x[0:2] #含头不含尾
print(x)
# 运行结果
# ['Wednesday', 'Thursday', 'Friday']
x = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
del x[::2] #切片删除,从第0个元素开始,每隔一个元素删除一个。
print (x)
# 运行结果
# ['Tuesday', 'Thursday']
- my_list[i:j]= []: 将列表s的某个位置的序列替换成空序列
#【用空序列替换原序列,删除原列表中的值】
x = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
x[0:3] = [] #删除第0、1、2个元素
print (x)
# 运行结果
# ['Thursday', 'Friday']
备注:如果需要从列表中删除某元素,且不再以任何方式使用它,使用del;如果需要在删除元素后还能继续使用被删除的元素,使用pop()。
- 为什么remove()不返回被删除的值,而pop()返回被删除的值呢?remove()是删除指定的元素值,所以在使用remove的时候,程序员已经知道要被删除的值,再返回这个值没有意义。pop()是根据元素的位置进行删除,程序员可能不知道被删除位置的元素值,所以返回这个值有意义。
1.5 获取列表元素
1.5.1 索引index(获取单个元素)
索引 index:使用元素的index索引值,从列表获取单个元素。语法: my_list[index]
- 注意: 列表索引值是从0开始的。将索引指定为-1,可让Python返回最后一个列表元素,索引 -2 返回倒数第二个列表元素,以此类推。
#【示例-索引】
x = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
x[0] #Monday
x[3] #Thursday
x[-1] #Friday
x[-2] #Thursday
1.5.2 切片 [起始:结束:步长] (获取多个元素)
切片:从现有列表中,获取一个子列表。切片后生成新的列表。切片不影响原列表。
- 语法: 列表名[起始位置:结束位置: 步长] 。切片获得的新列表包括起始位置的值,不包括结束位置的值。步长默认为1,可以设定。
#【列表切片】
names = ['Eva', 'Bob', 'Anna', 'Tom', 'John']
names [1:4] #['Bob', 'Anna', 'Tom']
- 切掉第一个和最后一个元素
names = ['Eva', 'Bob', 'Anna', 'Tom', 'John']
names [1:-1] #['Bob', 'Anna', 'Tom']
- 步长默认为1,可以设定。步长可以正数(代表从前向后)或者为负数(代表从后向前),但步长不可以为0。将步长设为-1,可得到倒叙的列表。步长为负数时,起始位置应大于结束位置,否则返回空列表
#【切片步长】
names [1:4:2] #['Bob', 'Tom']
names [1:5:3] #['Bob', 'John']
names [1:4:0] #ValueError: slice step cannot be zero 步长不可以为0
names [::-1] #['John', 'Tom', 'Anna', 'Bob', 'Eva'] 列表倒排
name [1:4:-1] #[] 步长为负数时,起始位置应大于结束位置,否则返回空列表
name [4:1:-1] #['John', 'Tom', 'Anna']
- 起始位置和结束位置均可以省略。如果省略起始位置,代表从第一个元素开始截取;如果省略结束位置,代表截取到最后一个元素;如果都省略,代表创建列表的一个副本。
#【省略起始位置】
new_1 = names[:3]
print (new_1) #['Eva', 'Bob', 'Anna']
#【省略结束位置】
new_2 = names[3:]
print (new_2) #['Tom', 'John']
#【省略起始位置和结束位置】
new_3 = names[:]
print (new_3) #['Eva', 'Bob', 'Anna', 'Tom', 'John']
1.6 其他通用操作
1.6.1 拼接和重复列表
- 加号+:将加号左右两侧列表拼接在一起
- 乘号*:将列表内的元素重复指定次数
#【列表拼接】
my_list = [1,2,3]+[4,5,6]
print (my_list)
# 运行结果
# [1,2,3,4,5,6]
#【列表重复】
my_list = [1,2,3] *3
print (my_list)
# 运行结果
# [1,2,3,1,2,3,1,2,3]
1.6.2 查找元素是否在列表内 in/not in
- in: 检查元素是否在列表内,在列表内返回True, 反之返回False
- not in: 检查元素是否不在列表内,不在列表内返回True, 反之返回False
# 【使用in和not in判读某元素是否在或不在列表内】
my_list = ['Eva',19,'Bob', 'Bonnie', 13]
i = 'Eva' in my_list
j = 'Eva' not in my_list
print (i, j)
# 运行结果
# True False
i = 21 in my_list
j = 21 not in my_list
# 运行结果
# False True
1.6.3 获取列表的长度 len()
- len(): 获取列表的长度,获取的是列表索引最大值+1
#【获取列表的长度】
list_1 = [1,'4',3,4,True]
len(list_1)
#输出
#[Out] 5
1.6.4 获取列表的最小值min 和最大值max
- min(): 获取最小值
- max(): 获取最大值
#【获取列表最大值和最小值】
my_list = [1,2,3,4,5,6]
max(my_list)
# 输出
# Out: 6
min(my_list)
# 输出
# Out: 1
1.6.5 获取列表中指定元素的个数 count()
- count(x): 用于获取列表中指定元素x的个数。注意,需要指定元素x,不指定元素会报错
- count()是一个方法(method), 需要通过一个具体的列表调用,可以理解为与对象联系紧密的函数,调用方法为list_name.count(x)
#【获取列表中元素个数】
my_list = [1,2,3,4,'Eva'*2, 'Anna', 'Hu', -0.13, 3, [3]*2, 3, 4]
my_list.count()
# 运行报错(因为没有指定元素)
# TypeError: count() takes exactly one argument (0 given)
print(my_list.count(2))
print(my_list.count(3))
print(my_list.count('Anna'))
# 运算结果
# 1
# 3
# 1
print(my_list.count([3]))
print(my_list.count([3]*2))
print(my_list.count([3,3]))
# 运算结果
# 0
# 1
# 1 因为[3]*2等于[3,3]
1.6.6 获取列表指定元素的位置 index()
- index(x): 获取列表中元素x第一次出现的位置index。如果列表中没有元素x,则抛出异常(ValueError)
- index()是一种方法,与count()一样,需要具体的列表才能调用,调用方法为list_name.index(x)。
- my_list.index(3): 即获取列表名称为’my_list’中值为3的元素第一次出现时的位置。
- 为什么index(x), count(x)调用时其前面都需要关联具体的列表,可以这么理解:上述两个函数都是针对列表内特定元素的操作,因此首先必须先找到这个特定的元素,而这个特定的元素一定是在某特定的列表里,所以上面两个函数依赖于特定的列表。在不同的列表查找同一个值,可能返回的结果不同。
#【获取指定元素的位置】
my_list = ['Bob','Anna', 3,21,4,3,'Bob', 3]
my_list.index(3) # 2
my_list.index('Bob') # 0
my_list.index('John') # ValueError: 'John' is not in list
- 进阶版 index(x, i, j): 返回从第i个位置开始到第j个位置(不包括第j个位置)结束之间,x第一次出现的位置。
- 可以有起始位置 i 但没有结束位置 j ,此时系统默认从起始位置 i 到列表最后一位;但是没有起始位置 i 但有结束位置 j ,此时,系统会报错。
#【获取指定元素的位置-进阶版】
my_list = ['Bob','Anna', 3,21,4,3,'Bob', 3]
my_list.index(3, 3)
#5 从列表index为3的元素开始向后查找值为3的元素,返回第一次出现位置的index
my_list.index(3, 6)
#7
my_list.index(3, 4, 7)
#5 在列表index为4的元素和index为7(不包括)的元素之间查找值为3的元素,返回第一次出现位置的index
my_list.index(3, 6, 7)
#ValueError: 3 is not in list 因为最后一个元素3的位置index为7,正好在查找的范围之外,所以不存在值为3的元素,系统报错
1.6.7 官方手册中的常用操作
可以从python官方手册中找到,步骤如下:
- 找到所使用的python版本的手册:Python 3.8.X(此处为版本号) Documents
- 在手册中,找到并点击 “The Python Standard Library” (或者官网上的链接"Library Reference")
- 找到第四部分 ”4 Built-in Types“
- 找到讲解序列的部分 “4.6 Sequence Types list, tuple, range”
- 点开序列部分,第一块内容就是常用操作 “4.6.1 Common Sequence Operations”
也可以点击此链接(3.8.8版本),一步到位
1.7 修改列表中的元素
1.7.1 直接通过索引修改
#【通过索引修改列表中的元素】
my_list = ['Bob','Anna', 3,21,4,3,'Bob', 3]
my_list[3] = 'John'
print (my_list)
# 运行结果
# ['Bob','Anna', 'John',21,4,3,'Bob',3]
1.7.2 通过切片修改
在使用切片修改列表时,必须传递一个序列。用切片等号右边的序列,替换切片等会左边列表里对应位置的序列
在不设置切片步长的情况下,替换的序列里的元素个数无需一一匹配。
#【通过切片修改列表】
my_list = ['Bob','Anna', 3,21,4,3,'Bob',3]
my_list[1:3] = ['John', 'Alan'] #用['John', 'Alan'] 替换原列表中位置为[1:3]的['Anna', 3]
print (my_list)
# 运行结果
# ['Bob', 'John', 'Alan', 21, 4, 3, 'Bob', 3]
my_list[1:3] = ['John', 'Alan', 'Max', 'Kate']
# 替换的序列中元素个数可以不等于原列表中的元素个数。
print (my_list)
# 运行结果
# ['Bob', 'John', 'Alan', 'Max', 'Kate', 21, 4, 3, 'Bob', 3]
my_list[1:3] = 123
# 运行报错,因为123不是序列。必须用序列替换序列
# TypeError: can only assign an iterable
- 当切片的起始位置和终止位置一致时,相当于在该位置插入等号右边的序列。由于等号左边为空序列,可以理解为,用等号右边的序列替换一个空序列。
my_list[1:1] = ['123']
print (my_list)
# 运行结果 在第0个元素和第1个元素位置中间插入’123‘,插入后,’123‘变成第1个元素。
# ['Bob', '123', 'John', 'Alan', 'Max', 'Kate', 21, 4, 3, 'Bob', 3]
my_list[5:5] = ['Helen', 'Julie']
# 运行结果
# ['Bob', '123', 'John', 'Alan', 'Max', 'Helen', 'Julie', 'Kate', 21, 4, 3, 'Bob', 3]
- 插入时,字符串中的每一个字母会被当作一个元素
#【在列表中切片插入字符串】
our_list = [1,2,3,4,5]
our_list[0:0] = '123'
print (our_list)
# 运行结果 字符串123中的每一个数字都会作为一个元素插入列表中
# ['1', '2', '3', 1, 2, 3, 4, 5]
在设置切片步长后,等式右边替换序列中元素的个数必须与等式左边切片中元素的个数一致
#【设置步长的切片修改】
our_list = [1,2,3,4,5,6]
our_list[::2] = [0]
# 运行报错 切片中元素个数为3,但是替换序列中元素个数为1,元素个数不足
# ValueError: attempt to assign sequence of size 1 to extended slice of size 3
our_list[::2] = [0]*3
print (our_list)
# 运行结果
# [0, 2, 0, 4, 0, 6]
1.8 其他常见列表方法
1.8.1 清空列表 s.clear()
#【清空整个列表】
our_list = [1,2,3,4,5,6]
our_list.clear()
print(our_list)
# 运行结果 列表内所有的元素被删除,返回一个空列表
# []
1.8.2 反转列表 s.reverse()
reverse(): 直接将原列表s进行反转,无返回值
#【反转列表】
our_list = [1,2,3,4,5,6]
our_list.reverse()
print (our_list)
new = our_list.reverse()
print (new)
# 运行结果 直接对our_list进行反转,不生成新的list,无返回值
# [6, 5, 4, 3, 2, 1] our_list本身被反转了
# None
1.8.3 列表中元素排序 s.sort()
sort(): 直接对列表s中的元素进行排序(原列表s元素排序发生改变),不生成新的list,返回排序后的列表。
- 默认升序(从小到大)排列。如果需要降序(从大到小)排列,需传递一个reverse=True的参数
#【对数字列表进行排序】
our_list = [4,2,1,7,0,6]
our_list.sort()
print (our_list)
# 运行结果 our_list内的元素从小到大的升序排列
# [0, 1, 2, 4, 6, 7]
our_list.sort(reverse = True) #降序排列
print (our_list)
# 运行结果
# [7, 6, 4, 2, 1, 0]
#【对字母也可以排列】
my_list = ['Bob', '123', 'John', 'Alan', 'Max', 'Kate', 'bob']
my_list.sort()
print (my_list)
# 运行结果 从每个元素的首字母开始比较,数字字符>大写字母>小写字母
# ['123', 'Alan', 'Amn', 'Bob', 'John', 'Kate', 'Max', 'bob']
#【但是多类型元素的列表不能排序】
my_list = ['Bob', '123', 'John', 'Alan', 'Max', 'Kate', 21, 4, 3, 'Bob', 3]
my_list.sort()
print (my_list)
# 运行报错 混合列表不能排序,因为不同的数据类型不能比较,例如字符串和整数之间不能比较
# TypeError: '<' not supported between instances of 'int' and 'str'
sort()的高阶用法(可结合Day3的函数的参数、高阶函数等内容学习)
- 实际情景下,可能想根据一个字符串列表中每个字符串的长度从短到长进行排序,该如何实现呢?
- sort()方法可以接收一个关键字参数key,key需要用函数作为参数。
- 如果使用了函数作为参数,则每次会将列表中的一个元素作为这个函数的参数,调用这个函数,然后用函数的返回值来比较大小
- 如果想实现按字符串的长短排序,可以用len函数作为关键字参数
#【sort()+key关键字参数-示例】
# 将以下列表中的字符串按照字符长度从短到长排序
strs = ['aaa', 'b','ccccccc','dddd']
strs.sort(key=len)
print (strs)
# 运行结果
# ['b', 'aaa', 'dddd', 'ccccccc']
- 如果想对实现多元素的列表排序,也可以使用key关键字,比如使用key = str, 即将列表内的元素都转换成字符串进行比较
- 注意,仅在元素比较的时候使用了str函数对元素进行了类型转换,列表中的元素类型并没有真的转换。
#【实现多类型元素比较】
# 使用key关键字参数,将所有元素转换成字符串进行比较
my_list = ['Bob', '123', 'John', 'Alan', 'Max', 'Kate', 21, 4, 3, 'Bob', 3]
my_list.sort(key = str)
print (my_list)
# 运行结果
# ['123', 21, 3, 3, 4, 'Alan', 'Bob', 'Bob', 'John', 'Kate', 'Max']
# 可以看到,列表里存储的元素的类型实际没有发生转换,例如元素21还是int类型。
1.9 遍历列表
遍历列表:将列表中的所有元素取出。
可以用循环语句遍历列表。考虑到列表的长度会变化,不能用固定的数值作为遍历次数,因此可以采用len()函数获取列表长度,动态需遍历列表的长度。
- 通过while循环遍历(不常用)
#【while循环遍历列表】
my_list = [1,2,3,4,5]
i = 0
while i < len(my_list): #从第1个元素一直遍历到列表最后一个元素
print (my_list[i])
i += 1
- 通过for循环遍历(常用)
#【for循环遍历列表】
# 语法:for 变量 in 列表:
# 循环体
# for循环每执行一次,会按顺序将序列中的一个元素赋值给变量
my_list = [1,2,3,4,5]
for num in my_list:
print (num)
2. 元组tuple
元组:不可变的对象,可看作不可修改的列表。一般用于当不希望数据发生改变的时候。可对元组进行切片查询(与列表相同),但不能进行任何会修改元组内元素(包括数值和位置)的操作。
如果想修改元组中的数据,只能建立新的元组。
2.1 创建元组
- 用()创建元组,用, 分隔开元组内的元素
#【创建空元组】
tuple_1 = ()
#【创建有多个元素的元组】
tuple_2 = (1,2,3,4)
- 当元组不为空时,可以省略()
#【不用()也可以创建元组】
tuple_3 = 1,2,3,4,5
print (tuple_3)
print (type(tuple_3))
#【运行结果】
#(1,2,3,4,5)
#<class 'tuple'>
- 元组中只包含一个元素时,需要在元素后面添加逗号,否则括号会被当作运算符使用,即元组内至少包含一个逗号, 。
#【单一元素元组需在元素后面添加逗号】
a = (10)
print (type(a)) #<class 'int'>
a = (10,)
print (type(a)) #<class 'tuple'>
2.2 元组的操作
- 可以对元组进行相加(Concatenate)
#【元组的相加】
tuple_1 = (1,2,3)
tuple_2 = ('a','b')
tuple_1+tuple_2
# [out]: (1,2,3,'a','b')
- 可以对元组进行切片查询(与列表切片相同)
#【元组的切片查询】
tuple_test = (1,2,3,4,5)
tuple_test[3]
# 【输出】
# [Out] 4
tuple_test[:3]
# [Out] (1,2,3)
tuple_test[2:3]
# [Out] (3,)
- 可以在元组末尾增加新的值
#【可以在元组末尾增加新的值】
tuple_test = tuple_test + (7,8)
print (tuple_test)
#【运行结果】
#(1,2,3,4,5,7,9)
#【但不能用append. extend】
tuple_test.append('2')
#【运行报错】
# AttributeError: 'tuple' object has no attribute 'append'
tuple_test.extend(('3','2'))
#【运行报错】
# AttributeError: 'tuple' object has no attribute 'extend'
- 获取元组的长度len(), 与获取列表长度的方法一致
#【获取元组长度】
tuple_test = (1,2,3,4,5)
print (len(tuple_test)
# 运行结果
# 5
- 不能对元组进行修改、赋值、增减、排序等会修改元组内元素数值或位置的操作
#【不能修改元组内元素的值】
tuple_test[3] = 10
#【运行报错】
# TypeError: 'tuple' object does not support item assignment
#【不能删除元组内的元素】
tuple_test.remove('2')
#【运行报错】
# AttributeError: 'tuple' object has no attribute 'remove'
#【不能在元组中插入元素】
tuple_test.insert(2,'3')
#【运行报错】
#AttributeError: 'tuple' object has no attribute 'insert'
- 元组排序
利用sorted()函数可以对元组进行排序。因为元组本身是不可修改的(包括元素的顺序也不可修改),所以排序后的元组是一个新的元组。
#【元组排序】
tuple_1 = (1,4,3,7,8,2,9,0)
sorted_tuple = sort(tuple_1)
sorted_tuple
#[out] (0,1,2,3,4,7,8,9)
2.3 元组的解构
元组的解构:将元组中的每个元素分别赋给一个单独的变量。单独变量的个数必须与元组中的元素个数一致。
#【元组的解构】
tuple_1 = (1,2,3,4)
a,b,c,d = tuple_1
print (d,c,b,a)
# 运行结果
# 4,3,2,1
- 如果不想把每个元素分别赋值给一个单独变量(例如当元组的元素很多时),可以在某一个变量之前加*,表示该变量用于储存剩余的元素,该变量的类型为列表。不能同时出现两个或以上的带星号*的变量
#【用带*的变量解构元组】
tuple_2 = (1,2,3,4,5,6,7,8,9,10)
a, b, *c = tuple_2
print (a,b,c)
print (type(c))
# 运行结果
#1 2 [3, 4, 5, 6, 7, 8, 9, 10]
#<class 'list'>
*d, e, f = tuple_2
print (d,e,f)
# 运行结果
# [1, 2, 3, 4, 5, 6, 7, 8] 9 10]
g, *h, i = tuple_2
print (g,h,i)
# 运行结果
# 1 [2, 3, 4, 5, 6, 7, 8, 9] 10
- 元组解构的应用:可用于更便捷的交换变量的值
#【用元组交换两个变量的值】
a = 1
b = 2
tuple_temp = a,b #a,b组成一个元组
b,a = tuple_temp #将元组解构,并分别赋值给b,a
print (a,b)
# 运行结果
# 2, 1
#【简化写法】
a = 3
b = 4
b, a = a, b
# 运行结果
# 4, 3
2.4 Nesting
元组里可以嵌套元组,比如:
- NT = (1,2,(‘rock’, ‘pop’), (3,4),(‘disco’,(3,4)))
嵌套的元组也可以切片索引,比如:
- NT[2] 是(‘rock’, ‘pop’)
- 所以,NT[2][1] 是’pop’
可以把元组的嵌套想象成树结构,最外层的元组像是主干,嵌套的元组为树枝,多层嵌套相当于不断分化的树枝
3. 字符串 string
3.1 创建字符串
字符串必须用引号引起来,不引起来不是字符串,会被错认为变量。
可以用单引号‘’,或者双引号“”,但不能混用。
s1 = 'abc'
print (s1) # abc
s2= “abc” # abc
print (s2)
s3 = abc
print (s3) # NameError: name 'abc' is not defined,认为abc是没被定义的变量
s4 = 'abd"
print(s4) # SyntaxError: EOL while scanning string literal, 因为引号混用)
相同的引号之间不能嵌套(中文字符可以嵌套!)
test = "Hello"W"orld" # SyntaxError: invalid syntax
test2 = "Hello'W'orld"
print (test2) # Hello'W'orld
test3 = 'Hello"W"orld'
print (test3) # Hello"W"orld
mm = "有句古话:“少壮不努力!”"
nn = "有句古话:‘少壮不努力!’"
print (mm) # 有句古话:“少壮不努力!”
print (nn) # 有句古话:‘少壮不努力!’
如果一定要相同的引号嵌套,则需要加转义字符 \
test = "Hello\"W\"orld"
print (test) # Hello"W"orld
单引号和双引号不能跨行使用。如果写长字符串需要换行,可以在每行末尾加 \
words = "学习后将掌握:
Python语法及应用,
会使用Python编写小程序。" # SyntaxError: EOL while scanning string literal
words = '学习后将掌握:\
Python语法及应用,\
会使用Python编写小程序。'
print (words) # 学习后将掌握:Python语法及应用,会使用Python编写小程序。
写长字符串还可以用三重引号。三重引号‘’‘(即三个单引号)可以跨行使用,还能保持字符串格式。
words = '''学习后将掌握:
Python语法及应用,
会使用Python编写小程序。'''
print (words)
# 学习后将掌握:
# Python语法及应用,
# 会使用Python编写小程序。
3.2 转义字符
转义字符 \ 可以用来在字符串中表示一些特殊的内容。常用情况:
- \ ’ 表示单引号’ (注意两者之间不能有空格);
- \ “ 表示双引号;
- \t 表示制表符(类似tab键)
- \n 表示换行符
- \ \ 表示反斜杠(即用于展示, 注意两者之间不能有空格)
- \uxxxx 表示unicode的编码。 因为python用unicode编译,所以可以主要用于输出一些键盘打不出来的奇奇怪怪的符号
words = "学习:\"语法,使用Python。"
print (words) #学习:"语法,使用Python。
words = "学习:\t语法,使用Python。"
print (words) #学习: 语法,使用Python。
words = "学习:\n语法,使用Python。"
print (words)
#学习:
#语法,使用Python。
words = "\\\\语法,\\n使用Python\\。"
print (words) # \\语法,\n使用Python\。
special = "\u12A2"
print (special) #ኢ (跪了。。)
3.3 占位符和格式化字符串
在打印字符串的时候,可以通过“+”或者传多个参数的方式拼接并输出字符串
#拼接字符串
a = "hello"
print ("a = "+a) #a = hello
#导入多个参数打印字符串
a = "hello"
print ("a =", a) # a = hello
print ("a =", a, a) # a = hello hello
在创建字符串的时候,可以在指定位置设置占位符%s, %f, %d等.
- %s : 在字符串中代表任意字符,可以填字符、整数、小数等。(s = string)
#示例
#一个占位符
t_1 = "my name is %s"%"Eva"
t_2 = "my age is %s"%20
t_3 = "luck num is %s"%18.8
print (t_1) #my name is Eva
print (t_2) #my age is 20
print (t_3) #luck num is 18.8
#多个占位符,每个占位符都需要传参数
a = "I'm from %s, and I'm %s."%("China", "17")
print (a) #I'm from China, and I'm 17.
- 可以在%s的s前面加数字,用于限制填充字符串的长度。
#占位符可以设置长度
#最小长度5个字符,不足部分用空格补全
c = "say!%5s!" %"bye"
print (c) #say! bye!
#最多3个字符,超出部分删除
c = "say!%.3s!" %"nothing"
print (c) #say!not!
#字符长度3-6个字符,不足部分用空格补全,超出部分删掉
d = "say!%3.6s!" % "no"
d_1 = "say!%3.6s!" % "noo"
d_2 = "say!%3.6s!" % "no_more"
print (d) #say! no!
print (d_1) #say!noo!
print (d_2) #say!no_mor!
- %f: 浮点数的占位符,用于代表浮点数(f = float),f前面加.数字代表小数点后的位数,位数不足用0填充,可以四舍五入。
# 浮点数占位符%f的用法
t_1 = "pi is %f"%3.141 #注意:%后面直接数值,不加引号。
print (t_1) #pi is 3.141000
t_2 = "pi is %.2f"%3.141
print (t_2) #pi is 3.14
t_3 = "pi is %.4f"%3.141
print (t_3) #pi is 3.1410
t_4 = "pi is not %.2f"%3.146
print (t_4) #pi is 3.15
- %d: 整数的占位符,抹去小数位,不四舍五入,d前面加数字代表整数长度,不足的地方补空格或者补0
# 整数占位符%d的用法
d_1 = "age is %d" %19
d_2 = "age is %d" %19.3
d_3 = "age is %d" %19.7
d_4 = "age is %3d" %19.7 #长度不足,用空格填充
d_5 = "age is %.3d" %19.7 #长度不足,用0填充
print (d_1) #age is 19
print (d_2) #age is 19
print (d_3) #age is 19
print (d_4) #age is 19
print (d_5) #age is 019
在python 3版本里,可以用 f 格式化字符串,直接在字符传中嵌入变量。f 需写在字符串的引号之外,嵌入的变量要用大括号{}包括。
#使用f格式化字符串,f要在引号外。
name = "Eva"
country = "China"
s = f'{name} is from {country}.'
print (s) #Eva is from China.
print (f"s = {s}") #s = Eva is from China.
#格式化字符串之前,要先定义变量,否则会报错
s = f'{name} is from {country}.'
name = "Eva"
country = "China"
print (s) #NameError: name 'name' is not defined
拼接字符串的方法总结
#拼接字符串的4种方法
#例子:打印 “Welcome XXX”
name = "Eva"
#传入多个参数
print ("1-Welcome", name) #1-Welcome Eva
#直接拼接
print ("2-Welcome "+name) #2-Welcome Eva
#占位符
print ("3-Welcome %s"%name) #3-Welcome Eva
#格式化字符串
print (f"4-Welcome {name}") #4-Welcome Eva
3.4 复制字符串
利用字符串与数字相乘,复制字符串
a = "haha_"
print (a*5) #haha_haha_haha_haha_haha_
3.5 字符串切片
字符串是有排序的,所以字符串切片与列表切片类似。
例如:字符串M = 'Michael John’的下标可以是正序(下标从前向后,从0开始):
字符串M: | M | i | c | h | a | e | J | o | h | n | |
---|---|---|---|---|---|---|---|---|---|---|---|
下标: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
也可以是倒序(下标从后向前,从-1开始):
字符串M: | M | i | c | h | a | e | J | o | h | n | |
---|---|---|---|---|---|---|---|---|---|---|---|
下标: | -11 | -10 | -9 | -8 | -7 | -6 | -5 | -4 | -3 | -2 | -1 |
所以,
- M[0]=M[-11]=‘M’,
- M[4] = M[-7]=‘a’,
- M[1:3] = M[-11:-9] = ‘ic’
4. 字典 Dictionary
字典:python中储存对象的容器,数据结构为映射mapping(python中映射类型的数据结构只有字典)。字典的存储性能不如列表,但在查询时非常高效。
字典中可以保存多个对象,每一个对象都有一个唯一的名字(key),可以通过这个名字快速定位对象,并获取这个对象的值(value)。key也称为键,即键是对象的名字。key-value称为键值对结构,每一个键值对称为一项(item)。
python 3.8 官方文档里对字典的说明点击这里。
4.1 创建字典
4.1.1 用大括号{}直接创建字典
创建字典:用大括号{}创建新字典,字典结构为{key1:value, key2:value2,…, keyn:valuen}。
- 字典的值value可以是任意类型对象(列表、元组、字符串、数字等)
- 字典的键key可以是任意的不可变对象(字符串、数字、元组、布尔值),一般使用字符串。
#【创建空字典】
dic_1 = {}
print (dic_1, type(dic_1))
# 运行结果
# {} <class 'dict'>
#【创建一个有数据的字典】
dic_2 = {'name':'Eva', 'gender':'Female', 'age':18}
#【可以换行写,看起来更清晰】
dic_2 = {
'name':'Eva',
'gender':'Female',
'age':18
}
- 同一字典内,键不能重复,如果出现重复的键,则后面键的值会替换前面键的值。
#【创建一个有重复key的字典】
dic_3 = {'name':'Eva', 'gender':'Female', 'age':18, 'name':'Susan'}
print (dic_3, type(dic_3))
# 运行结果 ‘name’的值被替换为'Susan'
# {'name': 'Susan', 'gender': 'Female', 'age': 18} <class 'dict'>
- 通过对象的键key获取存储在字典中对象的值value
#【获取字典内对象的值】
print(dic_3['name'], dic_3['age'])
# 运行结果
# Susan 18
#【使用不在字典里的key获取值,系统报错】
print(dic_3['address'])
# 运行错误 不存在名字为address的键
# KeyError: 'address'
4.1.2 用dict()函数创建字典
语法:my_dict = dict(key1 = value1, key2 = value2,…, keyn = valuen) 每一个参数都是一个键值对,每一个参数名都是键。
- 以dict()方式创建字典时,键都是字符串
- 特别注意:键不用加引号,值如果是字符串需要加引号。
#【用dict()函数创建字典】
my_dict = dict(name = 'Eva', age = 18, gender = 'Female')
print (my_dict, type(my_dict))
# 运行结果
# {'name': 'Eva', 'age': 18, 'gender': 'Female'} <class 'dict'>
my_dict = dict('name' = 'Eva', 'age' = 18, 'gender' = 'Female')
print (my_dict, type(my_dict))
# 运行报错 参数名(键)不能加引号
# SyntaxError: keyword can't be an expression
dict()的另一种用法:将双值子序列转换为字典。
- 双值序列:只有两个值的序列。例如: [1,2], [‘ao’, 3], (‘class’, ‘in’), ‘ab’
- 子序列:如果序列中的元素也是序列,则这个元素叫做子序列。例如:[‘a’, 78, [‘12’, 3, ‘Pop’]]中的[‘12’,3,'Pop’]是一个子序列,(‘Eva’, (‘name’, ‘age’))中的(‘name’, ‘age’)也是一个子序列
- 双值子序列:如果序列中的元素都是序列,而且这些子序列都是双值。例如:((‘国家’, ‘China’), (‘城市’, ‘Beijing’),(‘地区’, ‘Chaoyang’)), 或者[(‘pants’, ‘pink’), (‘dress’, ‘red’)]
#【用dict()函数将双值子序列转换为字典】
#【转换前】
address = (('国家', 'China'), ('城市', 'Beijing'),('地区', 'Chaoyang'))
print (type(address))
# 运行结果
# <class 'tuple'>
#【双值元组转换为字典】
address = dict((('国家', 'China'), ('城市', 'Beijing'),('地区', 'Chaoyang')))
print (address, type(address))
# 运行结果
# {'国家': 'China', '城市': 'Beijing', '地区': 'Chaoyang'} <class 'dict'>
#【双值列表元组转换为字典】
cloth_color = dict([('pants', 'pink'), ('dress', 'red'), ('hat', 'blue')])
print (cloth_color, type(cloth_color))
# 运行结果
# {'pants': 'pink', 'dress': 'red', 'hat': 'blue'} <class 'dict'>
#【双值列表转换为字典】
cloth_color = dict([['pants', 'pink'], ['dress', 'red']])
print (cloth_color, type(cloth_color))
# 运行结果
# {'pants': 'pink', 'dress': 'red'} <class 'dict'>
4.2 获取字典的值
4.2.1 直接用[键]获取值
语法:dict_name[key]。
- 文字理解:address[country] 代表 获取名字为address的字典中,对象名(键)为country对应的值。
#【获取字典中的值】
cloth_color = {'pants': 'pink', 'dress': 'red', 'hat': 'blue'}
cloth_color['pants'] #注意要带引号!'pants'是键,即对象的名字。pants会被当做一个没有定义的变量
# 运行结果
# Out: pink
- 缺点:用dict_name[key]的方式获取值时,如果key不在字典里,系统会抛出异常。
4.2.2 用get()方法获取字典值
语法:d.get(key[, default])
- *[]中的内容代表非必填项
- 用get()方法,如果字典中不存在指定的键,则默认返回None;
- 或者通过指定一个默认值,作为第二个参数,当键不存在时返回设定的默认值。
- 注意!get()是字典的一种方法,与字典密切相关,因此在调用时前面要带字典名。d_name.get(’name’) 代表获取名字为d_name的字典中名字为’name’的对象的值。
#【用get()方法获取字典值】
cloth_color = {'pants': 'pink', 'dress': 'red', 'hat': 'blue'}
print(cloth_color.get('pants'))
print(cloth_color.get('gloves'))
print(cloth_color.get('gloves','Not Exist')) # 第二个参数为指定默认值
# 运行结果
# pink
# None
# Not Exist
4.3 增加、修改和删除字典的value和item
- d[key] = value
- 如果字典d中有key,则将key的值修改;如果字典d中没有key,则增加这个item。
#【直接修改字典中的值】
cloth_color = {'pants': 'pink', 'dress': 'red', 'hat': 'blue'}
cloth_color['pant']='black'
print(cloth_color)
# 运行结果
# {'pants': 'black', 'dress': 'red', 'hat': 'blue'}
#【所查找的key不在字典中时】
cloth_color['gloves']='white'
print(cloth_color)
# 运行结果 因为gloves不是cloth_color字典中的key, 所以将gloves:white这个键值对增加到字典中
# {'pants': 'black', 'dress': 'red', 'hat': 'blue', 'gloves': 'white'}
- d.setdefault(key[,default])
- 用于向字典中添加item,
- 如果key在字典d中已经存在,则返回key对应的值,不对字典做任何修改操作;
- 如果key在字典d中不存在,则向字典中添加这个key,并将设定的default参数作为key的值;
- default参数非必填项。
#【用d.setdefault()增加item】
cloth_color = {'pants': 'pink', 'dress': 'red', 'hat': 'blue'}
result = cloth_color.setdefault('pants')
print (result)
print (cloth_color)
# 运行结果 因为pants是cloth_color字典中已经存在的key,所以返回这个key对应的value,字典本身不发生变化
# pink
# {'pants': 'pink', 'dress': 'red', 'hat': 'blue'}
result = cloth_color.setdefault('pants','white')
print (result)
print (cloth_color)
# 运行结果 因为pants是cloth_color字典中已经存在的key,所以返回这个key对应的value,字典本身不发生变化
# pink
# {'pants': 'pink', 'dress': 'red', 'hat': 'blue'}
result = cloth_color.setdefault('gloves')
print (result)
print (cloth_color)
# 运行结果 因为gloves在cloth_color字典中不存在,所以增加了gloves键,但因为没有设置default参数,没有给gloves赋值,所以gloves对应的值为None.
# None
# {'pants': 'pink', 'dress': 'red', 'hat': 'blue', 'gloves': None}
result = cloth_color.setdefault('shirts', 'white')
print (result)
print (cloth_color)
# 运行结果 因为shirts在cloth_color字典中不存在,所以增加了shirts键,因为设置了default参数为'white',所以shirts对应的值为white.
# white
# {'pants': 'pink', 'dress': 'red', 'hat': 'blue', 'gloves': None, 'shirts': 'white'}
- d1.update(d2)
- 将其他字典d2中的items合并添加到当前字典d1的末尾
#【update()示例】
d1 = {'pants': 'pink', 'dress': 'red', 'hat': 'blue'}
d2 = {'国家': 'China', '城市': 'Beijing', '地区': 'Chaoyang'}
d1.update(d2)
print('d1 =', d1)
print('d2 =',d2)
# 运行结果 d2中的key-value都添加到了d1的末尾
# d1 = {'pants': 'pink', 'dress': 'red', 'hat': 'blue', '国家': 'China', '城市': 'Beijing', '地区': 'Chaoyang'}
# d2 = {'国家': 'China', '城市': 'Beijing', '地区': 'Chaoyang'}
- 如果有重复的key,则后面的(即添加字典)会覆盖前面的(即当前字典)key的值
#【update()-重复key示例】
d1 = {'pants': 'pink', 'dress': 'red', 'hat': 'blue'}
d2 = {'国家': 'China', '城市': 'Beijing', 'hat': 'green'}
d1.update(d2)
print('d1 =', d1)
# 运行结果 d2中与d1不重复的key-value添加到了d1的末尾, 同时hat键的值被更换为'green'
# d1 = {'pants': 'pink', 'dress': 'red', 'hat': 'green', '国家': 'China', '城市': 'Beijing'}
- del(Dict[‘key’])
4.4 字典常用操作
- len(): 获取字典长度,即获取字典中键值对的个数。
#【获取字典中键值对的个数】
cloth_color = {'pants': 'pink', 'dress': 'red', 'hat': 'blue'}
len(cloth_color)
# 运行结果
# Out: 3
- in/not in: 检查字典中是否包含/不包含指定的键,并返回一个布尔值(True or False)。注意!不能用于查值。
#【查看某个键是不是在字典内】
cloth_color = {'pants': 'pink', 'dress': 'red', 'hat': 'blue'}
result = 'pants' in cloth_color
print (result)
# 运行结果
# True
result = 'pants' not in cloth_color
print (result)
# False
result = 'gloves' in cloth_color
print (result)
# False
result = 'gloves' not in cloth_color
print (result)
# True
- .keys(): 获取字典所有键的名称
cloth_color = {'pants': 'pink', 'dress': 'red', 'hat': 'blue'}
cloth_colot.keys()
# dict_keys(['pants', 'dress', 'hat'])
5. 集合 Set
5.1 基础概念
无序、只保存唯一值的数据结构,用{}
可以把list转换为set, 转换的时候list里面的重复值会被删除
5.2 集合运算
设A、B为集合:
5.2.1 添加元素:A.add(添加的元素)
由于set里的元素无序,所以新添加的元素并不是在队尾,不过在展示的时候,会按首字母排序。
#集合展示的时候,按元素首字母排序
A = {'Thriller', 'ABC', 'NYSC','abc', '123'}
A.add('Black')
A
#Out: {'123', 'ABC', 'Black', 'NYSC','Thriller', 'abc'}
5.2.2 删除元素:A.remove(需删除的元素)
是否包含某元素:XX in A -->返回True或False
找到两个集合的交集:A & B -->返回新的set 或者 A.intersection(B)
两个集合全部元素:A.union(B) 或者 B.union(A) -->返回新的set
找到只在A集合中出现的元素:A.difference(B) -->返回新的set
集合A是不是B的子集:A.issubset(B) -->返回True或False
集合A是不是B的母集:A.issuperset(B) -->返回True或False