Python编程基础

课程介绍

课程目标
通过本阶段的学习,使学员能够养成编程思维,掌握Python基础语法,能使用Python开发较为简单的需求。
课程内容
Python语言介绍及环境安装核心语法

第一部分 Python入门

第二部分 核心语法

第三部分 数据结构

第一节 字符串

在任何一门编程语言中,字符串都是最基础、最重要的数据结构。前面我们已经学习过字符串的基本使 用方法,现在继续深入的学习更多的知识。

字符串的格式化输出

格式化运算符

在之前while循环的一个例子中, 有这样一行代码:

print(“我跑完了第” + str(lap + 1) + “圈”)

这里我们使用了两个加号做了字符串拼接,并且将整形转换成了字符串,现在介绍一种更好的办法,使 用格式化输出来打印这句话。

print(“我跑完了第%d圈” % 1)

这里的百分号就是格式化符号,跟模运算符一样,但在不同的地方用法不一样。%d是一种占位,表示 要显示在这里是一个整数,常用的占位符有以下几种:

占位符 描述
%d 整数占位符
%f 浮点数占位符
%.f 指定精度的浮点数占位符
%s 字符串占位符
%% 输出百分号%

如果给%d 传入一个浮点数,那它会自动将它转换成整数

print(“%d” % 3.14) # 输出3 print(“%d” % 3.99) # 输出3

转换成整数的规则和类型转换的规则一 样,不会四舍五入。
%f的用法有两种,一种就是直接使用,比如

print(“%f” % 3.14)

它会输出“3.140000”,后面的0是自动补齐的,如果我们只想要输出小数点后两位,可以这样写:

print(“%.2f” % 3.14)
print(“%.2f” % 3.1415926)

上面的两行代码输出都是”3.14”,”%.2f” 这种写法指定了小数点后面的位数,即使浮点数后面的小数部分超出了2位,也只会输出两位。如果不足两位,或者是个整数,会自动补零到两位。

print(“%.2f” % 3) # 3.00
print(“%.2f” % 3.1) # 3.10

%s 是胜任最广泛的占位符,它可以对应任何类型的变量。

print(“%s” % 100) # 输 出 100 print(“%s” % 3.14) # 输 出 3.14 print(“%s” % “python”) # 输出python

在同一个字符串可以同时使用多个占位符:

report = “%d年%s公司营收增长了百分之%.2f” % (2019, “腾讯”, 20.28) print(report)

当我们需要在字符串输出一个百分比,就需要用到%%,比如说:

report = “%d年%s公司营收增长了%.2f%%” % (2019, “腾讯”, 20.28) print(report)

format函数

除了%运算符外,Python还为我们提供了字符串的format函数提供丰富的格式化。比如说,在输出一个较长的数字时,根据国际惯例,每三位用逗号分隔:

‘{:,}’.format(1234567890) # 1,234,567,890

format函数也可以像%那样来格式化多个参数:

report = “{0}年{1}公司营收增长了{2}%”.format(2019, “腾讯”, 20.28) print(report)

{0}表示第一个参数,{1}{2}表示第二、第三个参数,以此类推。这样做的好处是,如果有参数在字符串出现多次,可以不用重复的传入。

‘{0}的GDP为{1:,}…虽然它的GDP只有{1:,}美元,但它的人均GDP高达18万美元’.format(“摩纳哥”, 7100000000)

假设这个GDP数据在报告中多处被引用,万一需要修订的话,我们只需要修改一处就行了。

字符串的下标和切片

字符串其实也是一种序列,可以理解为一串整齐的按顺序排着队的字符,组成了字符串,那每个字符在 队伍中都有自己的位置,这个位置就是下标,又叫作索引。
第三部分 数据结构 - 图1
如上图,”CHINA”这个字符串,从左往右每一个字符对应了一个下标(索引),需要特别注意的是,在计算机编程中,所有的下标都是从0开始的,当我们要访问一个字符串的第1个字符时,使用的下标应该 是0。

“CHINA”[0]

使用中括号加数字的方式,表示要访问的是具体哪个位置上的字符。

“CHINA”[1] # 第2个字符”H”
“CHINA”[4] # 第5个字符”A”

第5个字符”A”是这个字符串的最后一个,我们也可以这样来访问:

“CHINA”[-1]
“CHINA”[-2]
# 最后一个字符”A”
# 倒数第二个字符”N”

第三部分 数据结构 - 图2使用负数下标可以从右往左访问,这种写法是Python特有的,非常的快捷,对于任意长度的字符串,我们都可以使用-1来获取它的最后一个字符,注意使用负数下标是是从-1开始的,因为-0也是0,产生重复了。
切片操作也是Python的一大特色,极大简化了序列访问和操作,
第三部分 数据结构 - 图3

“CHINA”[0:3]
上面的切片将会得到”CHI”,切片操作是以冒号隔开两个下标,冒号左边的代表开始下标,右边的代表 结束下标,特别需要注意的是,结尾下标表示截取到该下标前一个位置的下标。那[0:3],一共截取了3- 0=3个字符,从0开始数,0、1、2,恰好是三个。

第三部分 数据结构 - 图4

所以如果我们用[0:0]这种写法,将会得到一个空的字符串,

“CHINA”[0:0] # 空字符串
“CHINA”[0:-1] # CHIN

那如果想得到切片出整个字符串,可以这样写

“CHINA”[0:6] # CHINA

但一般我们都会这样写,冒号右边的省略,表示一直截取到最后一个字符。

“CHINA”[0:] # CHINA

事实上,前面的0也可以不写,冒号左边为空表示从第一个字符开始截取。

从0到末尾
“CHINA”[:] # CHINA
# 从0到第3个
“CHINA”[:3] # CHI
# 从第3个到末尾
“CHINA”[2:] # INA

如果想要隔一个字符取一个,可以这样写

每隔两个字符截取一个
“CHINA”[::2] # CIA

第二个冒号表示截取步长,这里的2表示每两个字符取一个,如果不传,默认就是每一个都取。步长也 可以为负数,如果传递了一个负数,则表示是从右往左进行截取。

从右往左每隔两个两个字符截取一个
“CHINA”[::-2] # AIC

所以,如果想倒序输出一个字符串,可以这样写

“CHINA”[::-1] # ANIHC

字符串函数

字符串本身有很多函数,前面其实已经学习过一个format函数,我们再来介绍几个其他的常用函数:

去除空白字符函数

先来了解一下什么是空白字符,空白符包括空格、换行(\n)、制表符(\t)。

print(“A\tB\tC\nD\tE\tF”)

在控制台里会整齐的输出成这样:
A B C D E F
在C后面有一个\n换行符,所以D才会显示在了第二行。而ABC、DEF之间的空白则是\t制表符造成的。
按键盘上的空格键会产生一个空格,按回车键则会产生一个换行符,按Tab键则会产生一个制表符,用 户在输入数据的时候有时候经常会误输入这几个字符,所以在在处理用户输入的数据时,要先去除头尾 的空白字符。

password = “123” input_password = “ 123”
print(password == input_password)

print输出为False,由于在1前面有一个空格,导致了密码校验失败,所以必须对用户的输入先进行处理

password = “123” input_password = “ 123”
print(password == input_password.strip())

我们在input_password后面加了一个函数strip(),现在输出变成了True。strip函数的作用就是去除字符 串首尾的所有空白字符。

“ abc “.strip() “\t abc \n”.strip()

得到的将是字符串”abc”,但是strip函数并不会去除掉字符串之间的空白字符

“ a b c “.strip()

得到的结果是”a b c”,只去掉了首尾空白字符,保留了中间的。
另外还有 lstrip 和 rstrip 函数,分别去除字符串左边和右边的空白字符

  • abc “.lstrip() # 结果’abc ‘
  • abc “.rstrip() # 结果’ abc’

大小写操作

这个比较简单,我们直接看代码。

将所有字符变成大写”china”.upper() # CHINA # 将字符串的首字母变成大写
“china”.capitalize() # China # 将所有字符变成小写”CHINA”.lower() # china
# 将每个单词的首字母变成大写
“i have a dream”.title() # I Have A Dream

字符串判断

判断字符串是否以指定的字符串开头或者结尾

函数 说明
startswith 是否以指定的字符串开头
endswith 是否以指定的字符串结尾
isdigit 是否是一串数字
islower 是否全是小写字母
isupper 是否全是大写字母

查找与替换

在前面智能密码锁的案例中,我们用过in来判断一个字符串是否被包含在另一个字符中

password = ‘123’
input_pwd = ‘456123789’ password in input_pwd # True

这样可以判断出是input_pwd中是否有password,但如果想要知道password在input_pwd中的确切位置,就需要使用find函数

input_pwd.find(password) # 结果是3

结果是3。在input_pwd中寻找password,找到了,且它的出现的位置是3,也就是第4个字符。如果没 有找到则会返回-1

input_pwd.find(“notexists”) # 结果是-1

除了find函数,index函数也有相同的功能,唯一的区别是 ,index函数如果没有找到相应的字符串就会报错

input_pwd.index(password) # 结果是3 # 这行代码将会在运行时报错input_pwd.index(“notexists”)

count函数能够查找出指定的字符串一共出现了几次,如果没有出现,则返回0。

“abba”.count(‘a’) # 2
‘abba’.count(‘c’) # 0

replace函数提供了替换字符串中某些部分的功能

“abba”.replace(‘a’, ‘b’) # 结果是’bbbb’ ‘apple banana’.replace(‘apple’, ‘orange’) # 结果是’orange banana’

字符串长度

字符串本身没有测量长度的函数,需要借助一个Python内置函数len。

len(“China”) # 5
len(“”) # 0
len(“a”) # 1

len函数非常重要,它不光可以测量字符串的长度,也可以测量其他所有有长度的对象。

r = range(10) len(r) # 10

综合案例:异常号码数据分析

结合以上的字符操作知识,可以开发一个电话号码识别程序,用户输入一串数字,程序识别它是不是一 个有效的电话号码,如果是有效电话号码,我们再识别它是一个固定电话号码、手机号码、还是400号 码。用户输入”exit”后,程序退出。
这是一个稍微复杂的需求,在动手写代码之前,我们先分析一下需求。先列举一下常见的几种电话号码 形式,手机号码是11位的,以1开头,不同运营商的前三位不一样,由于三位太多了,我们就以前两位 来判断,包括

13,15,17,18,19

再看固定号码,区号+电话号码的方式,区号可能是三位(010),也可能是四位(0888),电话号码是8位,那加起来一共是11位或12位。
最是400电话,这个特征很明显,以400开头,共10位。 实现代码如下:
cellphone_number_start = “13,15,17,18,19”
telephone_number_start = “010,021,022,025,0888,0555” while True:
num = input(“请输入一个电话号码: \n”)
if num == ‘exit’: break
if not num:
print(“电话号码不能为空”) num = num.strip()
if not num.isdigit():
print(“您输入的是一个无效电话号码”) continue

if num.startswith(‘1’) and len(num) == 11 and num[0:2] in cellphone_number_start:
print(“这是一个手机号码”)
continue
elif num.startswith(‘400’) and len(num) == 10: print(“这是一个广告电话”)
continue
elif num.startswith(“0”):
# 当代码太长时,可以用反斜杠分割成多行。
if (len(num) == 12 and num[0:4] in telephone_number_start) or \ (len(num) == 11 and num[0:3] in telephone_number_start):
print(“这是一个固定电话”)
continue print(“无法识别该号码”)

第二节 元组 tuple

定义元组

现在我们知道了字符串是一种序列,它可以迭代循环,也可以按索引访问,也可以切片访问。但它的组 成只能是单个的字符,现在来介绍一种更多元化的序列:元组,英文叫tuple,可这样来定义一个元
组:

t = (‘My’, ‘age’, ‘is’, 18)

在这个元组中包含了3个字符串,一个整形数字,元组中的每一项称作元素,4个元素按照从左到右的顺 序排列。可以用下标索引访问:

t[0]
t[-1]
# ‘my’
# 18

也可以通过切片来访问,注意切片返回的是一个包含切片片段的新元组。

t[0:2] # (‘My’, ‘age’)

事实上元组定义的时候也可以不用括号

t = ‘My’, ‘age’, ‘is’, 18

但当,元组中只有一个元素的时候,必须要加一个逗号:

t = (‘solo’,) # 或者不带括号t = ‘solo’,

可以将一个序列强制转换为元组

tuple(‘abc’)
# (‘a’, ‘b’, ‘c’)
tuple(range(5)) # (0, 1, 2, 3, 4)

后面的逗号表明这是一个元组,否则就会被认为是一个字符串。

元组操作

现在我们介绍字符串的另一个函数join,有了它,可以把元组这样的序列拼接成一个整体的字符串。

注意最后一个元素
t = (‘My’, ‘age’, ‘is’, “18”)
print(“ “.join(t))
# 输出结果:’My age is 18’

注意最后一个元素,这次我们将它设置成了字符串,因为join函数要求参数序列中的每一个元素都必须 是字符串。
和字符串一样,元组也有count, index函数,使用的方法也是一样:

t = (‘a’, ‘b’, ‘b’, ‘a’)
t.count(‘a’)
t.index(‘b’)
t.index(‘c’) # 查看长度len(t)
# 2
# 1
# Error
# 4

元组也支持 操作,想要判断元组中是否包含某个元素:
第三部分 数据结构 - 图5
in

‘a’ in t
‘x’ in t
# True
# False

最后,需要记住的是元组和字符串都是只读的,也就是不可修改的。我们不能单独改变元组中的某个元 素,或者是字符串中的某个字符。

遍历元组

元组属于序列,所以可以像字符串那样去遍历它:

lst = (‘a’, ‘b’, ‘c’, ‘d’, ‘e’) for i in lst:
print(i)

使用for循环可以方便快捷的遍历元组,上面的例子将打印出元组中的每一个元素。也可以使用while来遍历元组,虽然并不经常这样使用。

lst = list(range(10)) i = 0
while i < 10: print(lst[i]) i += 1

综合案例:销售数据统计-销冠

在真实的项目中,数据结构通常是比较复杂,经常碰到嵌套的元组,甚至是多层嵌套,我们来看一个例 子:

当元组元素较多、较长时,可以这样书写
sales = (
(“Peter”, (78, 70, 65)),
(“John”, (88, 80, 85)),
(“Tony”, (90, 99, 95)),
(“Henry”, (80, 70, 55)),
(“Mike”, (95, 90, 95)),
)

这是包含某公司所有销售人员第一季度销售业绩的元组,单位是万元,其中的每一个元素对应一个销售 人员的信息,人员信息也是一个元组,包括姓名和业绩,业绩又是一个元组,按照顺序分别是1、2、3 月份的销售额。需求:找出总销售额最高的那个员工,并将TA的名字和总销售额输出。

champion = ‘’ max_amount = 0 for sale in sales:
name = sale[0] quarter_amount = sale[1] total_amount = 0
for month_amount in quarter_amount: total_amount += month_amount
if total_amount > max_amount: max_amount = total_amount champion = name
print(“第一季度的销冠是%s, TA的总销售额是%d万元” % (champion, max_amount))

上面的代码也可进一步优化一下,使得代码行数更少,结构更简单。

champion = ‘’ max_amount = 0
for name, quarter_amount in sales: total_amount = sum(quarter_amount) if total_amount > max_amount:
champion, max_amount = name, total_amount
print(“第一季度的销冠是%s, TA的总销售额是%d万元” % (champion, max_amount))

这里用到了一个sum函数,它是Python内置函数,可以计算出一个序列里所有数值的总和。

第三节 列表 list

定义列表

列表可以理解为可变的元组,它的使用方式跟元组差不多,区别就是列表可以动态的增加、修改、删除 元素。
列表的定义

定义一个空列表
lst = [] lst = list()
# 定义带有初始值的列表
lst = [1, 2, 3]
lst = [“a”, 1, 2, 3, “b”, “c”]
lst = list(range(5)) lst = list(“abc”) lst = list((1, 2, 3))

以上方式都可以定义一个列表。注意变量名使用了lst,有意的避开了list,虽然list不是关键字,但我们在命名变量的时候不要使用这些内置名称,否则可能会引起无法预知的错误。

增删改查

列表的访问和字符串、元组一样,索引或者下标都可以。

lst = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’] lst[0] # ‘a’
lst[1:3] # [‘b’, ‘c’]

列表是可以修改的, 还是以上面的lst为例:

lst.append(‘x’)

往lst里添加了一个元素,现在列表变成了

[‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘x’]

注意append函数总是在列表后面添加元素,列表的长度也增加了1.因此原来list[-1]的值从原来的’e’变成 了’x’,

len(lst)
lst[-1]
# 6
# ‘x’

修改列表中的元素

lst[-1] = ‘f’
# 修改后列表变为:
# [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]

删除列表中的元素

del lst[0]
# 删除后列表变为:
[‘b’, ‘c’, ‘d’, ‘e’, ‘f’]

注意,由于我们删除的是第一个元素,现在剩下的所有元素的索引都发生了变化,第一个lst[0]变成 了’b’,后面的也都往前挪了一位。但是lst[-1]没有变,还是’f’。涉及到删除操作的时候要小心,防止使用错误的索引。

列表函数

列表也是一种序列,它也具有index和count函数和支持len函数,这些函数的用法和元组一样,它的循环遍历也和元组一样,不再赘述。下面来介绍一下列表特有的一些函数。

insert

insert函数和刚刚介绍的append函数一样,用来向列表中添加一个新的元素,区别就是append是在最 后添加,insert则可以向任意位置添加。

lst = [‘a’, ‘c’, ‘e’]
# 在第二个元素’c’前面插入一个字符串’b’ lst.insert(1, ‘b’)
# lst现在的值是[‘a’, ‘b’, ‘c’, ‘e’] # 在最后一个元素’e’前面插入一个字符串’d’ lst.insert(-1, ‘d’)
# lst现在的值是[‘a’, ‘b’, ‘c’, ‘d’, ‘e’]

pop

每次调用pop函数会从列表中“弹”出一个元素,接着上面的lst操作

temp = lst.pop()
print(lst) print(temp)
# [‘a’, ‘b’, ‘c’, ‘d’]
# ‘e’

我们发现列表最后一个元素’e’不见了,并被在控制台打印出了。如果想“弹”出其他位置的元素,可以传一个位置参数给pop函数,像这样:

temp = lst.pop(2)
print(lst) # [‘a’, ‘b’, ‘d’]
print(temp) # ‘c’

remove

前面我们已经学习了使用del关键字去删除列表元素,del操作可删除指定下标索引的元素,如果我们要删除指定内容的元素,就需要用到remove函数。

lst = [1, 2, 1, ‘a’, ‘b’, ‘c’]
lst.remove(‘a’)
print(lst) # lst 的 值 为 [1, 2, 1, ‘b’, ‘c’] lst.remove(1) # 注意这里的1是元素值,不是索引print(lst) # lst的值为[2, 1, ‘b’, ‘c’]

remove函数会从左至右找到与指定的值相匹配的第一个元素,并将它删除。在使用的时候需要区分del, pop, remove的区别。

clear

clear函数会清空列表内的所有元素。

lst = [1,2,3,4]
lst.clear() print(lst) # 结果为[]

extend

extend函数有点像append函数,但append函数每次只能添加一个元素,而extend可以添加一组。

lst = [] lst.extend(range(5))

print(lst) # [0, 1, 2, 3, 4]
lst.extend([5, 6, 7])
print(lst) # [0, 1, 2, 3, 4, 5, 6, 7]

reverse

将整个列表反转,以上一步的lst为例

lst.reverse()
print(lst) # [7, 6, 5, 4, 3, 2, 1, 0]

sort

按照一定的规则将列表中的元素重新排序,对于数值,默认按从小到大的顺序排列。

lst = [3, 5, 2, 1, 4]
lst.sort()
print(lst) # [1, 2, 3, 4, 5]

如果想要让列表从大到小排列,可以加上reverse参数。

lst = [3, 5, 2, 1, 4]
lst.sort(reverse=True)
print(lst) # [5, 4, 3, 2, 1]

对于字符串,则会按照它们的ASCII值的顺序排列。ASCII是基于拉丁字母的一套电脑编码系统,所有的 编程语言都支持ASCII编码。ASCII值一共有128个字符,包含数字0~9,字母a-z, A-Z,还有一些常用的符号。每一个字符对应一个数字,比如字母’A’对应的就是65, 字母’B’对应66,等等。在Python中,可以使用内置函数将字符与它的ASSCII值互转。

ord(‘A’)
chr(66)
# 65
# ‘B’

sort函数会比对每个字符串的第一个字符,如果第一个字符相同,则比对第二个字符,以此类推。

fruits = [‘apple’, ‘banana’, ‘orange’, ‘blueberry’] fruits.sort()
print(fruits) # [‘apple’, ‘banana’, ‘blueberry’, ‘orange’]

注意观察”banana”和”blueberry”的顺序。
如果列表的元素不是简单的字符或者数字,那怎么进行排序呢,比如有下面一个列表,它存储了公司第 一季度每个月的收入。

revenue = [(‘1月’, 5610000), (‘2月’, 4850000), (‘3月’, 6220000)]

注意列表中的每一个元素是一个元组,元组的第一项是月份,第二项是销售额,现在想要按照它的销售 额来从高到低排序。如果直接调用sort函数,它会按照元组中第一项的字符串顺序进行排序。

revenue.sort(reverse=True)
# 排序后为 [(‘3月’, 6220000), (‘2月’, 4850000), (‘1月’, 5610000)]

这显然不对,2月的收入比1月低,应该排到最后。这时应该传递key参数

revenue.sort(reverse=True, key=lambda x:x[1])
# 排序后为 [(‘3月’, 6220000), (‘1月’, 5610000), (‘2月’, 4850000)]

key参数接收的是一个函数,我们在这里给它传递了一个匿名函数,关于函数的使用后面再学习,这里我们需要了解是通过key参数,我们指定了sort排序的依据,就是每个元组里面的第二项。

copy

lst1 = [1, 2, 3]
lst2 = lst1 lst1.append(4)

上面的代码执行完成以后,lst 和 lst2的值都变成了[1, 2, 3, 4] ,但我们在代码里面只修改了lst1, lst2的值也跟着改变了,这不符合我的预期,可能会导致bug。所以,如果我们想要创建一个跟lst1一模一样的新列表,且不再受它以后操作的影响,就可以使用copy函数:

lst1 = [1, 2, 3]
lst2 = lst1.copy() lst1.append(4)
print(lst1) # [1, 2, 3, 4]
print(lst2) # [1, 2, 3]

列表表达式

列表表达式是一种快捷的创建列表的表达式,可以将多行代码省略为一行。比如,列出20以内的所有偶 数

[i * 2 for i in range(10)]
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

当然,上面的代码我们也可以这样实现

[i for i in range(0, 20, 2)]

range函数可以接收三个参数:第一个是起始数值(包含),可以省略,默认从0开始;第二个是结束数值(不包含);第三个是步长,可以省略,默认为1。是不是有点像切片操作?
上面的代码就相当于:

even_nums = []
for i in range(0, 20, 2): even_nums.append(i)

对比来看,列表表达式确实更简洁更优雅,再看一个例子,打印出大写的26个字母。

65是大写字母‘A’的ASCII值
[chr(i) for i in range(65, 65 + 26)]

综合案例-销售数据统计-排行榜

再进一步,还记得前面写过的找出销售冠军的例子吗?

sales = (
(“Peter”, (78, 70, 65)),
(“John”, (88, 80, 85)),
(“Tony”, (90, 99, 95)),
(“Henry”, (80, 70, 55)),
(“Mike”, (95, 90, 95)),
)

现在我们将计算出每人的总销售额,并按销售额从多到少,存放到一个列表里。

top_sales = []
for name, quarter_amount in sales: total_amount = sum(quarter_amount) top_sales.append((name, total_amount))
top_sales.sort(key=lambda x:x[1], reverse=True) print(top_sales)

得到了一个下面的列表

[(‘Peter’, 213), (‘John’, 253), (‘Tony’, 284), (‘Henry’, 205), (‘Mike’, 280)]

提示:这个案例用列表表达式来开发,将会非常快速。

top_sales = [(sale, sum(amount))for sale, amount in sales] top_sales.sort(key=lambda x:x[1], reverse=True) print(top_sales)

列表表达式是一种非常强大和方便的写法,不要求大家掌握,如果不会写列表表达式,也可以用for循 环或while循环的方式来写,但至少要能看懂。

第四节 字典 dict

类似这种销售信息的数据结构,我们使用元组或者列表存储是可以的。

top_sales = [(‘Peter’, 213), (‘John’, 253), (‘Tony’, 284), (‘Henry’, 205),
(‘Mike’, 280)]

可以很方便的取出在这个榜单中第一名、第二名或者任意一名的销售数据。但它有一个缺点,如果我们 想取出特定的某个销售人员的数据时,它会很麻烦。比如如果想要找出Mike的数据,只能去循环遍历, 一个个的去比对。

for sale, amount in top_sales: if sale == ‘Mike’:
print(sale, amount)

这样不光写起来麻烦,执行效率也很低,假设这是一个庞大的销售数据库,那要花多少时间寻找呢?所 以必须使用字典。

字典的定义

使用花括号,可以直接定义字典

sales = { ‘Peter’: 213,
‘John’: 253,
‘Tony’: 284,
‘Henry’: 205,
‘Mike’: 280
}

每一行冒号左边的是键(key),右边的是值(value),称作键值对,以逗号分隔开。在这里我们故意写成每行一个键值对,实际并不要求每行一个,只要用逗号分隔开来就可以。键是不能重复的,值可以重 复。
对于top_sales 这种两个一组、一一对应的列表来说,可以直接转换为字典。

sales = dict(top_sales) # sales现在的值变成了
{
‘Peter’: 213,
‘John’: 253,
‘Tony’: 284,
‘Henry’: 205,
‘Mike’: 280
}

增删改查

有了字典,那现在就可以快速的取出任意一个人的数据了

sales[‘Mike’] sales[‘Henry’]

注意,键的名称是区分大小写的,’Mike’ 和 ‘mike’分别对应了不同的键。

sales[‘mike’]
# KeyError: ‘mike’

这行代码将会报错,因为不存在’mike’这个键。在访问之前,需要先往字典中添加数据相应的键:

值可以先设置为None或者0 sales[‘mike’] = 0

修改字典中的数据:

sales[‘mike’] = 300

删除字典中的数据

del sales[‘mike’]

遍历字典

字典的遍历和列表、元组、字符串有所区别,由于它的每一项都是一个键值对,所以在遍历时也要注 意。

for key_value in sales.items(): print(key_value)

注意sales.items() 这种写法,在遍历字典时,这是一种通用的写法。items函数将字典内的内容转换成了一种可迭代的序列,以供for循环遍历,遍历出来的每一项是一个元组,包含了键和值。所以通常 我们直接写成这样:

for key, value in sales.items(): print(key, value)

注意中间的逗号和最后的打印结果。
如果不使用items函数,那遍历的就是字典所有的key。

for key in sales: print(key)

字典函数

字典有一些函数和列表是一样的,比如clear, copy,这两个不再介绍,我们来看看其他的函数。

get

如果直接访问字典中一个不存在的key,就会产生报错,所以,通常我们如果不确定是否存在某个key 时,会先判断一下:

if ‘mike’ in sales: print(sales[‘mike’])
else:
print(‘mike’, 0)

in关键字又一次派上用场了, 在这里用in来检查字典中是否包含”mike”这个键,如果包含则返回True, 无论”mike”所对应的值是否为空。这样的写法,很麻烦,每次都要先判断,再查询,这时候get函数就派上用场了。

sales.get(‘mike’, 0)

这一行短短的代码就实现了上面4行代码的功能,它表示在字典中查询’mike’键所对应的值,如果不存在’mike’键,则返回0。这里的0可以替换成任何其他的默认值,这样就极大简化代码逻辑。

keys/values

如果只想单独列出所有的销售人员名单,可以这样写:

sales.keys()

可以对它进行遍历

for sale in sales.keys(): print(sale)

如果只想计算出所有销售人员的销售额总和,也就是公司总销售额,可以直接取出value部分并求和:

sum(sales.values())

第五节 集合 set

集合在Python中是一个无序的不重复的序列,一般用来删除重复数据,还可以计算交集、并集等。

集合的定义

这两方式都可以定义一个集合

nums = {1, 2, 3, 4, 5}
nums = set([1, 2, 3, 4, 5])

注意,集合是无序的,虽然我们在书写的时候是按照从小到大的顺序,有时候遍历出来也是有序的,但 不能把它视为有序,并作为某些逻辑的依据。
集合最常用的用法是用来消除列表或者元组中的重复元素

lst = [1, 2, 1, 3, 4, 5]
list(set(lst))

列表里里面有两个1,先将lst转成了集合,再将集合转成了列表,最终得到了一个没有重复元素的列表
,注意最后得到的列表的顺序有可能跟原来是不一样的。
[1, 2, 3, 4, 5]

遍历集合

集合的遍历和列表、元组很相像,再次重申,它不是有序的。

for n in nums: print(n)

也可以通过len函数来测量它的长度,准备地讲,在数学上叫集合的基数。

len(nums) # 5

第三部分 数据结构 - 图6可以通过in 来判断集合中是否有某个特定的元素

5 in nums # True

增删改查

往集合里添加一个元素

nums.add(5) # do nothing nums.add(6)

如果集合里已经有这个元素了,则什么也不做。像上面的第一行代码,什么也没有做。 已经加入集合的元素不能修改,只能删除,删除集合里的元素:

nums.remove(5) nums.remove(5) # Error

remove函数会从集合里删除指定元素,但如果元素不存在,则会报错,上面的第二行代码就会报错。如果不想报错,可以使用diiscard函数

nums.discard(5)

从集合内删除并返回一个元素:

num = nums.pop()

如果集合是空的,则会报错。有时候,我们也会使用pop函数来迭代一个集合。

while len(nums) > 0: print(nums.pop())

这样的好处是可以保证每个元素只被使用一次,不会重复使用。

  1. 1. **集合函数**

定义两个集合
s1 = {1, 2, 3}
s2 = {3, 4, 5}
# 求交集s1.intersection(s2) # 求并集
s3 = s1.union(s2)
# {3}
print(s3) # 是否是子集
s1.issubset(s3)
# 是否是父集
# {1, 2, 3, 4, 5}
# True
s3.issuperset(s2) # True