内容介绍:Python是一个功能很强大的工具,也是我现在读研阶必须要掌握的一门语言。所以先将Python的基础知识和使用方法过一遍,以便后面更好地使用Python进行其它方向的学习,例如数据学习、测试、机器学习等等。本文是自己学习Python基础知识时整理的笔记,和大家一起共勉。主要参考Python怎么学习?学习Python方法和教程汇总! - 知乎进行学习。现在其实还不是很全,有一些比较不常用或者还没有遇到的知识点会随着后面的学习逐渐添加进来。
Python强大的功能绍
Python环境安装
注释
变量
变量和类型
变量命名
变量的使用
查看变量类型
改变变量类型
变量总结
运算符
算术运算符
赋值运算符
比较(关系)运算符和逻辑运算符
运算符和表达式应用举例
例子1:华氏温度转摄氏温度(输出格式化处理)
例子2:计算圆的周长和面积
例子3:判断闰年
分支(选择)结构
使用if和else构造分支结构
使用match和case构造分支结构
分支结构应用举例
例子1:分段函数求值
例子2:百分制成绩转换为等级制成绩
例子3:计算三角形的周长和面积
循环结构
for-in循环
range函数介绍
while循环
break和continue
嵌套的循环结构
循环结构应用举例
例子1:判断素数
例子2:最大公约数
例子3:猜数字小游戏
循环总结
列表
创建列表
列表的运算
元素的遍历
列表应用举例
掷色子统计每种点数出现次数
列表的方法
添加和删除元素
元素位置和频次
元素排序和反转
列表生成式
嵌套列表
列表应用举例
元组
元组的定义和运算
打包和解包操作
交换变量的值
元组和列表的比较
元组总结
字符串
字符串的定义
转义字符
原始字符串
字符的特殊表示
字符串的运算
拼接和重复
比较运算
成员运算
获取字符串长度
索引和切片
字符的遍历
字符串的方法
大小写相关操作
查找操作find/index
性质判断
格式化字符串
修剪操作strip
替换操作replace
拆分与合并split join
编码和解码
其他方法
集合
创建集合
集合的遍历
集合的运算
成员运算
二元运算
比较运算
集合的方法(添加、删除元素)
不可变集合
集合总结
字典
字典定义
创建字典
访问字典元素
修改字典元素
删除字典元素
字典键的特性
字典内置函数&方法
函数
函数的定义和作用
函数基本使用
函数的参数
函数的返回值
函数的嵌套调用
使用模块中的函数
模块导入
内容申明
自动化运维:越来越多的运维开始倾向于自动化,批量处理大量的运维任务。 python 在系统管理上的优势在于强大的开发能力和完整的工具链。
数据分析师:python 能快速开发的特性可以让你迅速验证你的想法,而不是把时 间浪费在程序本身上,并且有丰富的第三方库的支持,也能帮你节省时间。
游戏开发者: —般是作为游戏脚本内嵌在游戏中,这样做的好处是即可以利用游 戏引擎的高性能,又可以受益于脚本化开发的优点。只需要修改脚本内容就可以调整游戏内容,不需要重新编译游戏,特别方便。
自动化测试:对于测试来说,要掌握 script 的特性,会在设计脚本中,有更好的 效果。python 是目前比较流行的 script。
用爬虫爬取或处理大量信息:当你需要获取大批量数据或是批量处理的时候,python 爬虫可以快速做到这些, 从而节省你的重复劳动时间。比如:微博私信机器人、批量下载美剧、运行投资策 略、刷折扣机票、爬合适房源、系统管理员的脚本任务等等。
再包装其他语言的程序:python 又叫做胶水语言,因为它可以用混合编译的方式使用c/c++/java等等语言 的库。 另外,树每派作为微型电脑,也使用了 python 作为主要开发语言。
心动了吗!?心动不如行动,开始学习!!!
版本:建议安装python 3.x
检测是否安装成功 cmd 然后输入python
一般会使用pycharm完成Python代码的编写(个人感觉vscode这个软件也很方便,而且免费)
pycharm软件是需要付费的。
说明:python和pycharm的安装由于之前我已经安装好了,所以这里就不详细写了,感兴趣的同学可以看看其他博主发的安装教程。
Python 中的注释有单行注释和多行注释。
Python 中单行注释以 # 开头
# 这是一个注释
print("Hello, World!")
多行注释用三个单引号 ''' 或者三个双引号 """ 将注释括起来。
单引号(''')
#!/usr/bin/python3
'''
这是多行注释,用三个单引号
这是多行注释,用三个单引号
这是多行注释,用三个单引号
'''
print("Hello, World!")
双引号(""")
#!/usr/bin/python3
"""
这是多行注释,用三个双引号
这是多行注释,用三个双引号
这是多行注释,用三个双引号
"""
print("Hello, World!")
注意:多行注释可以嵌套使用,但是单行注释不能嵌套使用。
在编程语言中,变量是数据的载体,简单的说就是一块用来保存数据的内存空间,变量的值可以被读取和修改,这是所有计算和控制的基础。
Python语言中预设了多种数据类型,也允许自定义新的数据类型,几种Python中最为常用的数据类型。
(1)整型(int
)
Python中可以处理任意大小的整数,而且支持二进制(如0b100
,换算成十进制是 4)、八进制(如0o100
)、十进制(100
)和十六进制(0x100
)的表示法。
# 二进制整数
print(0b100) #4
# 八进制整数
print(0o100) #64
# 十进制整数
print(100) #100
# 十六进制整数
print(0x100) #256
(2)浮点型(float
)
浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,浮点数除了数学写法(如123.456
)之外还支持科学计数法(如1.23456e2
)
# 数学写法
print(123.456) #123.456
# 科学计数法
print(1.23456e2) #123.456
print(1.23456e-2) # 0.0123456
(3)字符串型(str
)
字符串是以单引号或双引号包裹起来的任意文本,比如'hello'
和"hello"
。
(4)布尔型(bool
)
布尔值只有True
、False
两种值,要么是True
,要么是False
。
(5)常见数据类型总结
对于每个变量,我们都需要给它取一个名字,就如同我们每个人都有自己的名字一样。在 Python 中,变量命名需要遵循以下的规则和惯例。
规则部分:
!
、@
、#
等)是不能出现在变量名中的。我们强烈建议大家把这里说的字母理解为尽可能只使用英文字母。A
和小写的a
是两个不同的变量,这一条其实并不算规则,而是需要注意的地方。is
、if
、else
、for
、while
、True
、False
等),保留字主要指 Python 语言内置函数、内置模块等的名字(如:int
、print
、input
、str
、math
、os
等)。惯例部分:
下面通过例子来说明变量的类型和变量的使用。
"""
使用变量保存数据并进行加减乘除运算
"""
a = 45 # 定义变量a,赋值45
b = 12 # 定义变量b,赋值12
print(a, b) # 45 12
print(a + b) # 57
print(a - b) # 33
print(a * b) # 540
print(a / b) # 3.75
在 Python 中可以使用type
函数对变量的类型进行检查。程序设计中函数它包括了函数名、自变量和因变量,详细内容后面学习。
"""
使用type函数检查变量的类型
"""
a = 100
b = 123.45
c = 'hello, world'
d = True
print(type(a)) #
print(type(b)) #
print(type(c)) #
print(type(d)) #
可以通过 Python 内置的函数来改变变量的类型,下面是一些常用的和变量类型相关的函数。
int()
:将一个数值或字符串转换成整数,可以指定进制。float()
:将一个字符串(在可能的情况下)转换成浮点数。str()
:将指定的对象转换成字符串形式,可以指定编码方式。chr()
:将整数(字符编码)转换成对应的(一个字符的)字符串。ord()
:将(一个字符的)字符串转换成对应的整数(字符编码)。"""
变量的类型转换操作
"""
a = 100
b = 123.45
c = '123'
d = '100'
e = '123.45'
f = 'hello, world'
g = True
print(float(a)) # int类型的100转成float,输出100.0
print(int(b)) # float类型的123.45转成int,输出123
print(int(c)) # strl类型的'123'转成int,输出123
print(int(c, base=16)) # str类型的'123'按十六进制转成int,输出291
print(int(d, base=2)) # str类型的'100'按二进制转成int,输出4
print(float(e)) # str类型的'123.45'转成float,输出123.45
print(bool(f)) # str类型的'hello, world'转成bool,输出True
print(int(g)) # bool类型的True转成int,输出1
print(chr(a)) # int类型的100转成str,输出'd'
print(ord('d')) # str类型的'd'转成int,输出100
说明:str
类型转int
类型时可以通过base
参数来指定进制,可以将字符串视为对应进制的整数进行转换。str
类型转成bool
类型时,只要字符串有内容,不是''
或""
,对应的布尔值都是True
。bool
类型转int
类型时,True
会变成1
,False
会变成0
。在 ASCII 字符集和 Unicode 字符集中, 字符'd'
对应的编码都是100
。
在 Python 程序中,我们可以使用变量来保存数据,变量有不同的类型,常用的类型有int
、float
、str
和bool
。在有需要的情况下,可以通过 Python 内置的函数对变量进行类型转换。
Python 语言支持很多种运算符,下面的表格按照运算符的优先级从高到低,对 Python 中的运算符进行了罗列。有了变量和运算符,我们就可以构造各种各样的表达式来解决实际问题。
在计算机科学中,表达式是计算机程序中的句法实体,它由一个或多个常量、变量、函数和运算符组合而成,编程语言可以对其进行解释和计算以得到另一个值。不管使用什么样的编程语言,构造表达式都是非常重要的。
运算符 | 描述 |
---|---|
[]、[:] | 索引、切片 |
** | 幂 |
~、+、- | 按位取反、正号、负号 |
*、/、%、// | 乘、除、模、整除 |
+、- | 加、减 |
>>、<< | 右移、左移 |
& | 按位与 |
^、` | ` |
<=、<、>、>= | 小于等于、小于、大于、大于等于 |
==、!= | 等于、不等于 |
is、is not | 身份运算符 |
in、not in | 成员运算符 |
not、or、and | 逻辑运算符 |
=、+=、-=、*=、/=、%=、//=、**=、&=、` | =、^=、>>=、<<=` |
说明: 所谓优先级就是在一个运算的表达式中,如果出现了多个运算符,应该先执行什么再执行什么的顺序。编写代码的时候,如果搞不清楚一个表达式中运算符的优先级,可以使用圆括号来确保运算的执行顺序。
Python 中的算术运算符非常丰富,除了最为熟悉的加、减、乘、除之外,还有整除运算符、求模(求余数)运算符和求幂运算符。
"""
算术运算符的使用
"""
print(321 + 12) # 加法运算,输出333
print(321 - 12) # 减法运算,输出309
print(321 * 12) # 乘法运算,输出3852
print(321 / 12) # 除法运算,输出26.75
print(321 // 12) # 整除运算,输出26
print(321 % 12) # 求模(余数)运算,输出9
print(321 ** 12) # 求幂运算,输出1196906950228928915420617322241
赋值运算符作用是将右边的值赋给左边的变量。赋值运算符还可以跟上面的算术运算符放在一起,组合成复合赋值运算符,例如:a += b
相当于a = a + b
,a *= a + 2
相当于a = a * (a + 2)
。
"""
赋值运算符和复合赋值运算符
"""
a = 10
b = 3
a += b # 相当于:a = a + b 此时a=13
a *= a + 2 # 相当于:a = a * (a + 2) 13*15
print(a) # 195 13*15
注意:赋值运算构成的表达式本身不产生任何值,为了解决这个问题,Python 3.8中引入了一个新的赋值运算符:=
,通常称之为海象运算符,与传统赋值运算符“=”不同,海象运算符可以赋值并同时返回变量的值。可以简化代码,并使代码更高效。但是,也可能会降低代码的可读性。
"""
海象运算符和普通赋值对比
"""
#使用“=”,变量赋值后,调用变量,返回变量的值
>>> a=123
>>> a
123
#使用“:=”,变量赋值并直接返回变量的值
>>> (a:=123)
123
#普通赋值
pwd=input("请输入:")
if pwd=="123":
print("输入正确!")
#海象运算符
if (pwd:=input("请输入:"))=="123":
print("输入正确!")
比较运算符也称为关系运算符,包括==
、!=
、<
、>
、<=
、>=
,需要提醒的是比较相等用的是==
,比较不相等用的是!=
。比较运算符会产生布尔值,要么是True
要么是False
。
逻辑运算符有三个,分别是and
、or
和not
。
and
运算符会连接两个布尔值或者产生布尔值的表达式,如果两边的布尔值都是True
,那么运算的结果就是True
;左右两边的布尔值有一个是False
,最终的运算结果就是False
。如果and
运算符左边的布尔值是False
,不管右边的布尔值是什么,最终的结果都是False
,这时运算符右边的布尔值会被跳过(专业的说法叫短路处理,如果and
右边是一个表达式,那么这个表达式不会执行)。or
运算符也会连接两个布尔值或产生布尔值的表达式,如果两边的布尔值有任意一个是True
,那么最终的结果就是True
。or
运算符也是有短路功能的,当它左边的布尔值为True
的情况下,右边的布尔值会被短路(如果or
右边是一个表达式,那么这个表达式不会执行)。not
运算符的后面可以跟一个布尔值,如果not
后面的布尔值或表达式是True
,运算的结果就是False
;如果not
后面的布尔值或表达式是False
,运算的结果就是True
。"""
比较运算符和逻辑运算符的使用
"""
flag0 = 1 == 1
flag1 = 3 > 2
flag2 = 2 < 1
flag3 = flag1 and flag2
flag4 = flag1 or flag2
flag5 = not flag0
print('flag0 =', flag0) # flag0 = True
print('flag1 =', flag1) # flag1 = True
print('flag2 =', flag2) # flag2 = False
print('flag3 =', flag3) # flag3 = False
print('flag4 =', flag4) # flag4 = True
print('flag5 =', flag5) # flag5 = False
print(flag1 and not flag2) # True
print(1 > 2 or 2 == 3) # False
说明:比较运算符的优先级高于赋值运算符,所以上面的flag0 = 1 == 1
先做1 == 1
产生布尔值True
,再将这个值赋值给变量flag0
。,
进行分隔,输出的内容之间默认以空格分开。
要求:输入华氏温度将其转换为摄氏温度,华氏温度到摄氏温度的转换公式为:{C = (F - 32) / 1.8}。
"""
将华氏温度转换为摄氏温度
"""
f = float(input('请输入华氏温度')) # 输入40
c = (f - 32) / 1.8
print('%.1f华氏度 = %.1f摄氏度' % (f, c)) # 40.0华氏度 = 4.4摄氏度
说明:上面代码中的input
函数用于从键盘接收用户输入,由于输入的都是字符串,如果想处理成浮点小数来做后续的运算,用float
函数将str
类型处理成float
类型。
上面的代码对print
函数输出的内容进行了格式化处理,print
输出的字符串中有两个%.1f
占位符,这两个占位符会被%
之后的(f, c)
中的两个float
类型的变量值给替换掉,浮点数小数点后保留1位有效数字。如果字符串中有%d
占位符,那么我们会用int
类型的值替换掉它,如果字符串中有%s
占位符,那么它会被str
类型的值替换掉。
除了上面格式化输出的方式外,Python 中还可以用下面的办法来格式化输出,我们给出一个带占位符的字符串,字符串前面的f
表示这个字符串是需要格式化处理的,其中的{f:.1f}
和{c:.1f}
可以先看成是{f}
和{c}
,表示输出时会用变量f
和变量c
的值替换掉这两个占位符,后面的:.1f
表示这是一个浮点数,小数点后保留1位有效数字。
"""
将华氏温度转换为摄氏温度
"""
f = float(input('请输入华氏温度: ')) # 输入40
c = (f - 32) / 1.8
print(f'{f:.1f}华氏度 = {c:.1f}摄氏度') # 40.0华氏度 = 4.4摄氏度
要求:输入一个圆的半径,计算出它的周长()和面积()。
Python 中有一个名为math
的内置模块,该模块中定义了名为pi
的变量,它的值就是圆周率。如果要使用 Python 内置的这个pi
,需要提前使用import进行导入。
"""
输入半径计算圆的周长和面积
"""
import math # 导入math模块获取π的值
r = float(input('请输入圆的半径:')) # 输入3
c = 2 * math.pi * r;
s = math.pi * r ** 2;
print('周长: %.1f; 面积: %.1f' % (c,s)) # 周长: 18.8; 面积: 28.3
print(f'周长:{c:.1f}; 面积:{s:.1f}') # 周长: 18.8; 面积: 28.3
这里其实还有一种格式化输出的方式,是 Python 3.8 中增加的新特性,
"""
输入半径计算圆的周长和面积
"""
import math # 导入math模块获取π的值
r = float(input('请输入圆的半径:')) # 输入3
c = 2 * math.pi * r;
s = math.pi * r ** 2;
print(f'{c=:.1f}') # c=18.8
print(f'{s=:.1f}') # s=28.3
说明:这种格式化输出的方式会同时输出变量名和变量值。
要求:输入一个1582年以后的年份,判断该年份是不是闰年。闰年输出True,平年输出False。
"""
输入年份,闰年输出True,平年输出False
"""
year = int(input('请输入年份:')) # 输入2000
is_leap = year % 4 == 0 and year % 100 != 0 or year % 400 == 0
print(f'{is_leap=}') # is_leap=True
说明:判断闰年的规则:
1. 公元年份非4的倍数是平年;
2. 公元年份为4的倍数但非100的倍数是闰年;
3. 公元年份为400的倍数是闰年。
上面的代码通过%
来判断year
是不是4
的倍数、100
的倍数、400
的倍数,然后用and
和or
运算符将三个条件组装在一起,前两个条件要同时满足,第三个条件跟前两个条件的组合只需满足其中之一。
迄今为止,我们写的 Python 代码都是一条一条语句按顺序向下执行的,这种代码结构叫做顺序结构。然而仅有顺序结构并不能解决所有的问题,比如我们设计一个游戏,游戏第一关的过关条件是玩家获得1000分,那么在第一关完成后,我们要根据玩家得到分数来决定是进入第二关,还是告诉玩家“Game Over”。在这样的场景下,我们的代码就会产生两个分支,而且这两个分支只有一个会被执行。
我们将这种结构称之为“分支结构”或“选择结构”。
在 Python 中,要构造分支结构可以使用if
、elif
和else
三个关键字。并不是每次构造分支结构都会把三个关键字全部用上。
所谓关键字就是编程语言中有特殊含义的单词,像
if
和else
就是专门用于构造分支结构的关键字,很显然你不能够使用它作为变量名。
举例说明:
写一个身体质量指数(BMI)的计算器。身体质量质数也叫体质指数,是国际上常用的衡量人体胖瘦程度以及是否健康的一个标准,计算公式如下所示。通常认为18.5≤BMI<24是正常范围,BMI<18.5说明体重过轻,BMI≥24说明体重过重,BMI≥27就属于肥胖的范畴了。
BMI=体重(kg)÷身高^2(m)
说明: 上面公式中的体重以千克(kg)为单位,身高以米(m)为单位。
"""
BMI计算器
"""
weight = float(input('请输入体重(kg):'))
height = float(input('请输入身高(cm)'))
bmi = weight / (height / 100) ** 2
print("您的bmi值为%.1f" % bmi)
if bmi < 18.5:
print('太轻了,多吃点哟!')
elif bmi <= 24:
print('刚刚好哟,很不错!')
elif bmi < 27:
print('有一点点重了哟!')
else:
print('属于肥胖了,要开始减肥了!')
运行结果:
请输入体重(kg):>? 48
请输入身高(cm)>? 160
您的bmi值为18.7
刚刚好哟,很不错!
提示:if
、elif、else语句的最后面有一个:
,它是用英文输入法输入的冒号;程序中输入的'
、"
、=
、(
、)
等特殊字符,都是在英文输入法状态下输入的, 强烈建议写代码的时候 切换到英文输入法。
Python 中没有用花括号来构造代码块而是使用缩进的方式来表示代码的层次结构,如果if
条件成立的情况下需要执行多条语句,只要保持多条语句具有相同的缩进就可以了。
换句话说,若干行连续的语句如果保持了相同的缩进,那么它们就属于同一个代码块,相当于是一个执行的整体。
缩进可以使用任意数量的空格,但通常使用4个空格,强烈建议大家不要使用制表键(Tab键)来缩进代码,如果你已经习惯了这么做,可以设置你的代码编辑器自动将1个制表键变成4个空格,很多代码编辑器都支持这项功能,PyCharm 中默认也是这样设定的。
还有一点,在 C、C++、Java 等编程语言中,18.5 <= bmi < 24
(Python中可以直接这样写)要写成两个条件bmi >= 18.5
和bmi < 24
,然后把两个条件用逻辑与运算符连接起来,Python 中也可以这么做,例如刚才的if
语句也可以写成if bmi >= 18.5 and bmi < 24:
,但是没有必要,难道if 18.5 <= bmi < 24:
这个写法它不香吗?
Python 3.10 中增加了一种新的构造分支结构的方式,通过使用match
和case
关键字,我们可以轻松的构造出多分支结构。Python 的官方文档在介绍这个新语法时,举了一个 HTTP 响应状态码识别的例子。
对官方文档上的示例稍作修改,为大家讲解这个语法,先看看下面用if-else
结构实现的代码。
status_code = int(input('响应状态码: '))
if status_code == 400:
description = 'Bad Request'
elif status_code == 401:
description = 'Unauthorized'
elif status_code == 403:
description = 'Forbidden'
elif status_code == 404:
description = 'Not Found'
elif status_code == 405:
description = 'Method Not Allowed'
else:
description = 'Unknown status Code'
print('状态码描述:', description)
运行结果:
响应状态码: 403
状态码描述: Forbidden
下面是使用match-case
语法实现的代码,虽然作用完全相同,但是代码显得更加简单优雅。
status_code = int(input('响应状态码: '))
match status_code:
case 400: description = 'Bad Request'
case 401: description = 'Unauthorized'
case 403: description = 'Forbidden'
case 404: description = 'Not Found'
case 405: description = 'Method Not Allowed'
case _: description = 'Unknown Status Code'
print('状态码描述:', description)
说明: 带有_
的case
语句在代码中起到通配符的作用,如果前面的分支都没有匹配上,代码就会来到case _
。case _
的使用是可选的, 并非每种分支结构都要给出通配符选项。如果分支中出现了case _
,它只能放在分支结构的最后面,如果它的后面还有其他的分支,那么这些分支将是不可达的。感觉和C++的switch-case的用法差不多,但写法上简洁一点。
当然,match-case
语法还有很多高级玩法,有一个合并模式可以在这里分享给大家。例如,我们要将响应状态码401
、403
和404
归入一个分支,400
和405
归入到一个分支,其他保持不变,代码还可以这么写。
status_code = int(input('响应状态码: '))
match status_code:
case 400 | 405: description = 'Invalid Request'
case 401 | 403 | 404: description = 'Not Allowed'
case _: description = 'Unknown Status Code'
print('状态码描述:', description)
运行结果:
响应状态码: 403
状态码描述: Not Allowed
有如下所示的分段函数,要求输入x
,计算出y
。
"""
分段函数求值
"""
x = float(input('x = '))
if x > 1:
y = 3 * x - 5
elif x >= -1:
y = x + 2
else:
y = 5 * x + 3
print(f'{y = }')
分支结构是可以嵌套的,也就是说在分支结构的if
、elif
或else
代码块中还可以再次引入分支结构。例如if
条件成立表示玩家过关,但过关以后还要根据你获得宝物或者道具的数量对你的表现给出评价(比如点亮一颗、两颗或三颗星星),那么我们就需要在if
的内部再构造一个新的分支结构。
同理,我们在elif
和else
中也可以构造新的分支,我们称之为嵌套的分支结构。按照这样的思路,上面的分段函数求值也可以用下面的代码来实现。
"""
分段函数求值
"""
x = float(input('x = '))
if x > 1:
y = 3 * x - 5
else:
if x >= -1:
y = x + 2
else:
y = 5 * x + 3
print(f'{y = }')
说明:大家可以自己感受和评判一下上面两种写法哪一种更好。在 Python之禅中有这么一句话:“ Flat is better than nested”。之所以认为 “扁平化”的代码更好,是因为代码嵌套的层次如果很多,会严重的影响代码的可读性。所以,上面的代码第一种写法是更好的选择。
要求:如果输入的成绩在90分以上(含90分),则输出A
;输入的成绩在80分到90分之间(不含90分),则输出B
;输入的成绩在70分到80分之间(不含80分),则输出C
;输入的成绩在60分到70分之间(不含70分),则输出D
;输入的成绩在60分以下,则输出E
。
"""
百分制成绩转换为等级制成绩
"""
score = float(input('请输入成绩: '))
if score >= 90:
grade = 'A'
elif score >= 80:
grade = 'B'
elif score >= 70:
grade = 'C'
elif score >= 60:
grade = 'D'
else:
grade = 'E'
print(f'{grade = }')
要求:输入三条边的长度,如果能构成三角形就计算周长和面积;否则给出“不能构成三角形”的提示。
"""
计算三角形的周长和面积
"""
a = float(input('a = '))
b = float(input('b = '))
c = float(input('c = '))
if a + b > c and a + c > b and b + c > a:
perimeter = a + b + c
print(f'周长: {perimeter}')
s = perimeter / 2
area = (s * (s - a) * (s - b) * (s - c)) ** 0.5
print(f'面积: {area}')
else:
print('不能构成三角形')
说明: 上面的if
条件表示任意两边之和大于第三边,这是构成三角形的必要条件。当这个条件成立时,我们要计算并输出周长和面积,所以if
下方有五条语句都保持了相同的缩进,它们是一个整体,只要if
条件成立,它们都会被执行,这就是我们之前提到的代码块的概念。另外,上面计算三角形面积的公式叫做 海伦公式,若已知三角形的三条边长分别为a、b、c,S= (p为三角形周长的一半,即p=(a+b+c) / 2。
有的场景需要重复执行某条指令或某些指令,例如我们需要每隔1秒钟在屏幕上输出一次“hello, world”并持续输出一个小时。
import time
print('hello, world')
time.sleep(1)
说明:Python 内置time
模块的sleep
函数可以实现程序的休眠,参数1
表示休眠的秒数,可以使用int
或float
类型,例如0.05
表示50
毫秒。
为了应对上述场景,可以在 Python 程序中使用循环结构。所谓循环结构,就是程序中控制某条或某些指令重复执行的结构。有了这样的结构,刚才的代码就不需要写3600遍,而是写一遍然后放到循环结构中重复3600次。在 Python 语言中构造循环结构有两种做法,一种是for-in
循环,另一种是while
循环。
如果明确知道循环执行的次数,推荐使用for-in
循环。例如上面说的那个重复3600次的场景,我们可以用下面的代码来实现。 注意,被for-in
循环控制的代码块也是通过缩进的方式来构造,这一点跟分支结构中构造代码块的做法是一样的。我们被for-in
循环控制的代码块称为循环体,通常循环体中的语句会根据循环的设定被重复执行。
"""
每隔1秒输出一次“hello,world",持续1小时
"""
import time
for i in range(3600):
print('hello,world')
time.sleep(1)
上面代码中的range(3600)
可以构造出一个从0
到3599
的范围,当我们把这样一个范围放到for-in
循环中,就可以通过前面的循环变量i
依次取出从0
到3599
的整数,这就让for-in
代码块中的语句可以重复3600次。当然,range
的用法非常灵活。【从0开始】
range(101)
:可以用来产生0
到100
范围的整数,需要注意的是取不到101
。range(1, 101)
:可以用来产生1
到100
范围的整数,相当于是左闭右开的设定,即[1, 101)
。range(1, 101, 2)
:可以用来产生1
到100
的奇数,其中2
是步长(跨度),即每次递增的值,101
取不到。range(100, 0, -2)
:可以用来产生100
到1
的偶数,其中-2
是步长(跨度),即每次递减的值,0
取不到。可以注意的是,上面的输出和休眠操作都没有用到循环变量i
,对于不需要用到循环变量的for-in
循环结构,按照 Python 的编程惯例,我们通常把循环变量命名为_
,修改后的代码如下所示。虽然结果没什么变化,但是这样写显得你更专业。
"""
每隔1秒输出一次“hello, world”,持续1小时
"""
import time
for _ in range(3600):
print('hello, world')
time.sleep(1)
上面的代码要执行一个小时,如果想提前结束程序,在 PyCharm 中可以点击运行窗口上的停止按钮,如下图所示。如果在命令提示符或终端中运行代码,可以使用组合键ctrl+c
来终止程序。
用for-in
循环实现从1到100的整数求和,即。
"""
从1到100的整数求和
"""
total = 0
for i in range(1, 101):
total += i
print(total) # 5050
上面的代码中,变量total
的作用是保存累加的结果。在循环的过程中,循环变量i
的值会从1
一直取到100
。对于变量i
的每个取值,我们都执行了total += i
,它相当于total = total + i
,这条语句实现了累加操作。所以,当循环结束,我们输出变量total
的值,它的值就是从1
累加到100
的结果5050
。注意,print(total)
这条语句前是没有缩进的,它不受for-in
循环的控制,不会重复执行。
再来写一个从1到100偶数求和的代码,如下所示。
"""
从1到100的偶数求和
"""
total = 0
for i in range(1, 101):
if i % 2 == 0:
total += i
print(total)
说明:上面的for-in
循环中我们使用了分支结构来判断循环变量i
是不是偶数。
我们也可以修改range
函数的参数,将起始值和跨度修改为2
,用更为简单的代码实现从1到100的偶数求和。
"""
从1到100的偶数求和
"""
total = 0
for i in range(2, 101, 2):
total += i
print(total)
更为简单的办法是使用 Python 内置的sum
函数求和,这样我们连循环结构都省掉了。
"""
从1到100的偶数求和
"""
print(sum(range(2, 101, 2)))
如果要构造循环结构但是又不能确定循环重复的次数,我们推荐使用while
循环。while
循环通过布尔值或能产生布尔值的表达式来控制循环,当布尔值或表达式的值为True
时,循环体(while
语句下方保持相同缩进的代码块)中的语句就会被重复执行,当表达式的值为False
时,结束循环。
下面我们用while
循环来实现从1到100的整数求和,代码如下所示。
"""
从1到100的整数求和
"""
total = 0
i = 1
while i <= 100:
total += i
i += 1
print(total)
相较于for-in
循环,上面的代码我们在循环开始前增加了一个变量i
,我们使用这个变量来控制循环,所以while
后面给出了i <= 100
的条件。在while
的循环体中,我们除了做累加,还需要让变量i
的值递增,所以我们添加了i += 1
这条语句,这样i
的值就会依次取到1
、2
、3
、……,直到101
。当i
变成101
时,while
循环的条件不再成立,代码会离开while
循环,此时我们输出变量total
的值,它就是从1
到100
求和的结果5050
。
如果要实现从1到100的偶数求和,我们可以对上面的代码稍作修改。
"""
从1到100的偶数求和
"""
total = 0
i = 2
while i <= 100:
total += i
i += 2
print(total)
把while
循环的条件直接设置为布尔值True
,还是从1到100的偶数求和。
"""
从1到100的偶数求和
"""
total = 0
i = 2
while True:
total += i
i += 2
if i > 100:
break
print(total)
上面的代码中使用while True
构造了一个条件恒成立的循环,这也就是常说的“死循环”。为了在i
的值超过100
后让循环停下来,可以使用break
关键字,它的作用是终止循环结构的执行。需要注意的是,break
只能终止它所在的那个循环,这一点在使用嵌套循环结构时需要引起注意。除了break
之外,还有另一个在循环结构中可以使用的关键字continue
,它可以用来放弃本次循环后续的代码直接让循环进入下一轮,代码如下所示。
"""
从1到100的偶数求和
"""
total = 0
for i in range(1, 101):
if i % 2 != 0:
continue
total += i
print(total)
说明:上面的代码使用continue
关键字跳过了i
是奇数的情况,只有在i
是偶数的前提下,才会执行到total += i
。
总结:break可以终止它所在的那个循环;而continue是放弃本次的循环,直接进行下次的循环。
循环结构是可以嵌套的,也就是说在循环结构中还可以构造循环结构。下面的例子演示了如何通过嵌套的循环来输出一个乘法口诀表(九九表)。
"""
打印乘法口诀表
"""
for i in range(1, 10):
for j in range(1, i + 1):
print(f'{j}×{i}={i * j}', end='\t')
print() # 换行
上面的代码中,for-in
循环的循环体中又用到了for-in
循环,外面的循环用来控制产生i
行的输出,而里面的循环则用来控制在一行中输出j
列。显然,里面的for-in
循环的输出就是乘法口诀表中的一整行。所以在里面的循环完成时,使用一个print()
来实现换行的效果,最后的输出如下所示。
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
1×4=4 2×4=8 3×4=12 4×4=16
1×5=5 2×5=10 3×5=15 4×5=20 5×5=25
1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36
1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49
1×8=8 2×8=16 3×8=24 4×8=32 5×8=40 6×8=48 7×8=56 8×8=64
1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81
要求:输入一个大于1的正整数,判断它是不是素数。
提示:素数指的是只能被1和自身整除的大于1的整数。例如对于正整数n
,我们可以通过在2
到n-1
之间寻找有没有n
的因子,来判断它到底是不是一个素数。当然,循环不用从2
开始到n-1
结束,因为对于大于1的正整数,因子应该都是成对出现的,所以循环到 就可以结束了。
"""
输入一个大于1的正整数判断它是不是素数
"""
import math
number = int(input('请输入需要判断的数字:'))
end = int(math.sqrt(number))
is_prime = 1
for i in range(2, end + 1): # 注意,这里需要从2开始循环
if number % i == 0:
is_prime = 0 # 说明此数字不是素数,结束整个循环
break
if is_prime:
print('%d是素数' % number)
else:
print('%d不是素数' % number)
输出结果
请输入需要判断的数字:>? 23
23是素数
请输入需要判断的数字:>? 100
100不是素数
说明:使用is_prime
来标记,值为1则说明是素数,反之则不是。先假设number
是一个素数,接下来,我们在2
到 的范围寻找number
的因子,如果找到了number
的因子,那么它一定不是素数,此时我们将is_prime
赋值为0
,同时使用break
关键字终止循环结构;最后,我们根据is_prime
的值是1
还是0
来给出不同的输出。
要求:输入两个大于0
的正整数,求两个数的最大公约数。
提示:两个数的最大公约数是两个数的公共因子中最大的那个数。
"""
输入两个正整数计算它们的最大公约数和最小公倍数
"""
x = int(input('输入x值:'))
y = int(input('输入y值:'))
for i in range(x, 0, -1):
if x % i == 0 and y % i == 0:
print(f'最大公约数是:{i}')
break
说明:上面代码中for-in
循环的循环变量值是从大到小的,这样我们找到的能够同时整除x
和y
的因子i
,就是x
和y
的最大公约数,此时我们用break
终止循环。如果x
和y
互质,那么循环会执行到i
变成1
,因为1
是所有正整数的因子,此时x
和y
的最大公约数就是1
。
用上面代码的找最大公约数在执行效率是有问题的。假如x
的值是999999999998
,y
的值是999999999999
,很显然两个数是互质的,最大公约数为1
。但是我们使用上面的代码,循环会重复999999999998
次,这通常是难以接受的。我们可以使用欧几里得算法(辗转相除法)来找最大公约数,它能帮我们更快的得到想要的结果,代码如下所示。
"""
输入两个正整数计算它们的最大公约数
"""
x = int(input('x = '))
y = int(input('y = '))
while y % x != 0:
x, y = y % x, x
print(f'最大公约数: {x}')
欧几里得算法
在求解最大公因数的方法中,辗转相除法是比较常规的一种算法。举个例子,我们想要求出 30 和 45 的最大公约数,按照辗转相除法,我们进行以下步骤:
用较大数 45 除以较小数 30,得商 1 余 15;
用上一步的余数 15 除以刚才的除数 30,得商 0 余 15;
用上一步的余数 15 除以刚才的除数 15,得商 1 余 0。
此时余数为零,所以最大公约数为 15。
要求:计算机出一个1
到100
之间的随机数,玩家输入自己猜的数字,计算机给出对应的提示信息“大一点”、“小一点”或“猜对了”,如果玩家猜中了数字,计算机提示用户一共猜了多少次,游戏结束,否则游戏继续。
"""
猜数字小游戏
Version: 1.0
"""
import random
answer = random.randrange(1, 101)
counter = 0
while True:
counter += 1
num = int(input('请输入: '))
if num < answer:
print('大一点.')
elif num > answer:
print('小一点.')
else:
print('猜对了.')
break
print(f'你一共猜了{counter}次.')
说明:上面的代码使用import random
导入了 Python 标准库的random
模块,该模块的randrange
函数帮助我们生成了1
到100
范围的随机数。变量counter
用来记录循环执行的次数,也就是用户一共做出了几次猜测,每循环一次counter
的值都会加1
。
学会了 Python 中的分支结构和循环结构,就可以解决很多实际的问题了。如果事先知道循环结构重复的次数,通常使用for
循环;如果循环结构的重复次数不能确定,可以用while
循环。此外,可以在循环结构中使用break
终止循环,也可以在循环结构中使用continue
关键字让循环结构直接进入下一轮次。
考虑将一颗色子掷6000
次,统计每种点数出现的次数。通过之前的学习,我们可以用1
到6
均匀分布的随机数来模拟掷色子,然后用6
个变量分别记录每个点数出现的次数。使用if-else分支结构,代码如下所示。
"""
将一颗色子掷6000次,统计每种点数出现的次数
"""
import random
f1 = 0
f2 = 0
f3 = 0
f4 = 0
f5 = 0
f6 = 0
for _ in range(6000): # 使用_比较专业
face = random.randrange(1, 7)
if face == 1:
f1 += 1
elif face == 2:
f2 += 1
elif face == 3:
f3 += 1
elif face == 4:
f4 += 1
elif face == 5:
f5 += 1
else:
f6 += 1
print(f'1点出现了{f1}次')
print(f'2点出现了{f2}次')
print(f'3点出现了{f3}次')
print(f'4点出现了{f4}次')
print(f'5点出现了{f5}次')
print(f'6点出现了{f6}次')
使用match-case分支结构,代码如下所示:
"""
将一颗色子掷6000次,统计每种点数出现的次数
"""
import random
f1 = 0
f2 = 0
f3 = 0
f4 = 0
f5 = 0
f6 = 0
for _ in range(6000): # 使用_比较专业
face = random.randrange(1, 7)
match face:
case 1: f1 += 1
case 2: f2 += 1
case 3: f3 += 1
case 4: f4 += 1
case 5: f5 += 1
case 6: f6 += 1
print(f'1点出现了{f1}次')
print(f'2点出现了{f2}次')
print(f'3点出现了{f3}次')
print(f'4点出现了{f4}次')
print(f'5点出现了{f5}次')
print(f'6点出现了{f6}次')
对于这种情况,在 Python 中可以通过容器类型的变量来保存和操作多个数据,首先介绍列表(list
)这种新的数据类型。
在 Python 中,列表是由一系元素按特定顺序构成的数据序列,这就意味着如果我们定义一个列表类型的变量,可以用它来保存多个数据。在 python 中,可以使用[]
字面量语法来定义列表,列表中的多个元素用逗号进行分隔,代码如下所示。
items1 = [35, 12, 99, 68, 55, 35, 87]
items2 = ['Python', 'Java', 'Go', 'Kotlin']
items3 = [100, 12.3, 'Python', True]
print(items1) # [35, 12, 99, 68, 55, 35, 87]
print(items2) # ['Python', 'Java', 'Go', 'Kotlin']
print(items3) # [100, 12.3, 'Python', True]
print(type(items1)) #
说明:列表中可以有重复元素,例如items1
中的35
;列表中可以有不同类型的元素,例如items3
中有int
类型、float
类型、str
类型和bool
类型的元素,但是我们通常并不建议将不同类型的元素放在同一个列表中,主要是操作起来极为不方便。
因为列表可以保存多个元素,它是一种容器型的数据类型,所以在给列表类型的变量起名字时,变量名通常用复数形式的单词。
除此以外,还可以通过 Python 内置的list
函数将其他序列变成列表。准确的说,list
并不是一个普通的函数,它是创建列表对象的构造器。
items4 = list(range(1, 10))
items5 = list('hello')
print(items4) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(items5) # ['h', 'e', 'l', 'l', 'o']
说明:range(1, 10)
会产生1
到9
的整数序列,给到list
构造器中,会创建出由1
到9
的整数构成的列表。字符串是字符构成的序列,上面的list('hello')
用字符串hello
的字符作为列表元素,创建了列表对象。
我们可以使用+
运算符实现两个列表的拼接,拼接运算会将两个列表中的元素连接起来放到一个列表中,代码如下所示。
items5 = [35, 12, 99, 45, 66]
items6 = [45, 58, 29]
items7 = ['Python', 'Java', 'JavaScript']
print(items5 + items6) # [35, 12, 99, 45, 66, 45, 58, 29]
print(items6 + items7) # [45, 58, 29, 'Python', 'Java', 'JavaScript']
items5 += items6
print(items5) # [35, 12, 99, 45, 66, 45, 58, 29]
我们可以使用*
运算符实现列表的重复运算,*
运算符会将列表元素重复指定的次数,我们在上面的代码中增加两行,如下所示。
print(items6 * 3) # [45, 58, 29, 45, 58, 29, 45, 58, 29]
print(items7 * 2) # ['Python', 'Java', 'JavaScript', 'Python', 'Java', 'JavaScript']
我们可以使用in
或not in
运算符判断一个元素在不在列表中,我们在上面的代码代码中再增加两行,如下所示。
print(29 in items6) # True
print(99 in items6) # False
print('C++' not in items7) # True
print('Python' not in items7) # False
由于列表中有多个元素,而且元素是按照特定顺序放在列表中的,所以当我们想操作列表中的某个元素时,可以使用[]
运算符,通过在[]
中指定元素的位置来访问该元素,这种运算称为索引运算。需要说明的是,[]
的元素位置可以是0
到N - 1
的整数,也可以是-1
到-N
的整数,分别称为正向索引和反向索引,其中N
代表列表元素的个数。对于正向索引,[0]
可以访问列表中的第一个元素,[N - 1]
可以访问最后一个元素;对于反向索引,[-1]
可以访问列表中的最后一个元素,[-N]
可以访问第一个元素,代码如下所示。
items8 = ['apple', 'waxberry', 'pitaya', 'peach', 'watermelon']
print(items8[0]) # apple
print(items8[2]) # pitaya
print(items8[4]) # watermelon
items8[2] = 'durian'
print(items8) # ['apple', 'waxberry', 'durian', 'peach', 'watermelon']
print(items8[-5]) # 'apple'
print(items8[-4]) # 'waxberry'
print(items8[-1]) # watermelon
items8[-4] = 'strawberry'
print(items8) # ['apple', 'strawberry', 'durian', 'peach', 'watermelon']
在使用索引运算的时候要避免出现索引越界的情况,对于上面的items8
,如果我们访问items8[5]
或items8[-6]
,就会引发IndexError
错误,导致程序崩溃,对应的错误信息是:list index out of range,翻译成中文就是“数组索引超出范围”。因为对于只有五个元素的列表items8
,有效的正向索引是0
到4
,有效的反向索引是-1
到-5
。
如果希望一次性访问列表中的多个元素,我们可以使用切片运算。切片运算是形如[start:end:stride]
的运算符,其中start
代表访问列表元素的起始位置,end
代表访问列表元素的终止位置(终止位置的元素无法访问),而stride
则代表了跨度,简单的说就是位置的增量,比如我们访问的第一个元素在start
位置,那么第二个元素就在start + stride
位置,当然start + stride
要小于end
。我们给上面的代码增加下面的语句,来使用切片运算符访问列表元素。
# items8 ['apple', 'strawberry', 'durian', 'peach', 'watermelon']
print(items8[1:3:1]) # ['strawberry', 'durian']
print(items8[0:3:1]) # ['apple', 'strawberry', 'durian']
print(items8[0:5:2]) # ['apple', 'durian', 'watermelon']
print(items8[-4:-2:1]) # ['strawberry', 'durian']
print(items8[-2:-6:-1]) # ['peach', 'durian', 'strawberry', 'apple']
提醒:上面代码中的最后一行,当 跨度为负数时,切片运算是倒着访问元素的。 以下情况参数可以省略不写:start = 0; end = N; stride = 1;
下面的代码跟上面的代码作用完全相同。
# items8 ['apple', 'strawberry', 'durian', 'peach', 'watermelon']
print(items8[1:3]) # ['strawberry', 'durian']
print(items8[:3:1]) # ['apple', 'strawberry', 'durian']
print(items8[::2]) # ['apple', 'durian', 'watermelon']
print(items8[-4:-2]) # ['strawberry', 'durian']
print(items8[-2::-1]) # ['peach', 'durian', 'strawberry', 'apple']
事实上,我们还可以通过切片操作修改列表中的元素,例如我们给上面的代码再加上一行,大家可以看看这里的输出。
items8[1:3] = ['x', 'o']
print(items8) # ['apple', 'x', 'o', 'peach', 'watermelon']
两个列表还可以做关系运算,我们可以比较两个列表是否相等,也可以给两个列表比大小,代码如下所示。
nums1 = [1, 2, 3, 4]
nums2 = list(range(1, 5))
nums3 = [3, 2, 1]
print(nums1 == nums2) # True
print(nums1 != nums2) # False
print(nums1 <= nums3) # True
print(nums2 >= nums3) # False
说明:上面的nums1
和nums2
对应元素完全相同,所以==
运算的结果是True
。nums2
和nums3
的比较,由于nums2
的第一个元素1
小于nums3
的第一个元素3
,所以nums2 >= nums3
比较的结果是False
。如果第一个元素相等,则比较第二个元素,以此递推。
如果想逐个取出列表中的元素,可以使用for-in
循环的,有以下两种做法。
方法一:在循环结构中通过索引运算,遍历列表元素。
languages = ['c', 'c++', 'java', 'python', 'html+css+jquery']
for index in range(len(languages)):
print(languages[index])
输出:
c
c++
java
python
html+css+jquery
说明:上面的len
函数可以获取列表元素的个数N
,而range(N)
则构成了从0
到N-1
的范围,刚好可以作为列表元素的索引。
方法二:直接对列表做循环,循环变量就是列表元素的代表。
languages = ['c', 'c++', 'java', 'python', 'html+css+jquery']
for index in languages:
print(index)
输出:
c
c++
java
python
html+css+jquery
可以用列表的知识来重构上面“掷色子统计每种点数出现次数”的代码。
题目:将一颗色子掷6000次,统计每种点数出现的次数
"""
将一颗色子掷6000次,统计每种点数出现的次数
"""
import random
count = [0] * 6
# 模拟掷色子记录每种点数出现的次数
for _ in range(6000):
num = random.randrange(1, 7)
count[num - 1] += 1
# 输出每种点数出现的次数
for index in range(1, 7):
print(f'{index}出现的次数是{count[index - 1]}')
使用了列表类型加上循环结构可以对数据批量化处理,代码更优雅。
列表类型的变量拥有很多方法可以帮助我们操作一个列表,假设我们有名为foos
的列表,列表有名为bar
的方法,那么使用列表方法的语法是:foos.bar()
,这是一种通过对象引用调用对象方法的语法,这种语法也称为给对象发消息。
列表是一种可变容器,可变容器指的是我们可以向容器中添加元素、可以从容器移除元素,也可以修改现有容器中的元素。
languages = ['Python', 'Java', 'C++']
languages.append('JavaScript')
print(languages) # ['Python', 'Java', 'C++', 'JavaScript']
languages.insert(1, 'SQL')
print(languages) # ['Python', 'SQL', 'Java', 'C++', 'JavaScript']
remove
: 从列表中删除指定元素,如果要删除的元素并不在列表中,会引发ValueError
错误导致程序崩溃,所以建议大家在删除元素时,先用之前讲过的成员运算做一个判断。pop
: 从列表中删除元素,默认删除列表中的最后一个元素,当然也可以给一个位置,删除指定位置的元素。如果索引的值超出了范围,会引发IndexError
异常,导致程序崩溃。在删除元素时会返回被删除的元素。clear
: 清空列表中的元素。del
:用法和pop一样,不同的是pop在删除元素时会返回被删除的元素,而del不会,但del的性能相对会好一点。languages = ['Python', 'SQL', 'Java', 'C++', 'JavaScript']
if 'Java' in languages:
languages.remove('Java')
if 'Swift' in languages:
languages.remove('Swift')
print(languages) # ['Python', 'SQL', C++', 'JavaScript']
languages.pop()
temp = languages.pop(1)
print(temp) # SQL
languages.append(temp)
print(languages) # ['Python', C++', 'SQL']
languages.clear()
print(languages) # []
items = ['Python', 'Java', 'C++']
del items[1]
print(items) # ['Python', 'C++']
说明:pop
方法删除元素时会得到被删除的元素,上面的代码中,我们将pop
方法删除的元素赋值给了名为temp
的变量。当然如果你愿意,还可以把这个元素再次加入到列表中,正如上面的代码languages.append(temp)
所做的那样。
这里还有一个小问题,例如languages
列表中有多个'Python'
,那么我们用languages.remove('Python')
是删除所有的'Python'
,还是删除第一个'Python'
?【答案:删除第一个】
languages = ['Python', 'SQL', 'Java', 'C++', 'JavaScript', 'Java']
if 'Java' in languages:
languages.remove('Java') # ['Python', 'SQL', 'C++', 'JavaScript', 'Java']
index
方法会引发ValueError
错误。items = ['Python', 'Java', 'Java', 'C++', 'Kotlin', 'Python']
print(items.index('Python')) # 0
# 从索引位置1开始查找'Python'
print(items.index('Python', 1)) # 5
print(items.count('Python')) # 2
print(items.count('Kotlin')) # 1
print(items.count('Swfit')) # 0
# 从索引位置3开始查找'Java'
print(items.index('Java', 3)) # ValueError: 'Java' is not in list
sort
:实现列表元素的排序。
reverse
:实现元素的反转。items = ['Python', 'Java', 'C++', 'Kotlin', 'Swift']
items.sort()
print(items) # ['C++', 'Java', 'Kotlin', 'Python', 'Swift']
items.reverse()
print(items) # ['Swift', 'Python', 'Kotlin', 'Java', 'C++']
在 Python 中,列表还可以通过一种特殊的字面量语法来创建,这种语法叫做生成式。【优雅且性能比通过循环创建的方式好】
场景一:创建一个取值范围在1
到99
且能被3
或者5
整除的数字构成的列表。
items = []
for i in range(1, 100):
if i % 3 == 0 or i % 5 == 0:
items.append(i)
print(items)
使用列表生成式做同样的事情,代码如下所示。
items = [i for i in range(1, 100) if i % 3 == 0 or i % 5 == 0]
print(items)
场景二:有整数列表nums1
,创建一个新的列表nums2
,nums2
中的元素是nums1
中对应元素的平方。
nums1 = [35, 12, 97, 64, 55]
nums2 = []
for num in nums1:
nums2.append(num ** 2)
print(nums2)
使用列表生成式做同样的事情,代码如下所示。
nums1 = [35, 12, 97, 64, 55]
nums2 = [num ** 2 for num in nums1]
print(nums2)
场景三: 有整数列表nums1
,创建一个新的列表nums2
,将nums1
中大于50
的元素放到nums2
中。
nums1 = [35, 12, 97, 64, 55]
nums2 = []
for num in nums1:
if num > 50:
nums2.append(num)
print(nums2)
使用列表生成式做同样的事情,代码如下所示。
nums1 = [35, 12, 97, 64, 55]
nums2 = [num for num in nums1 if num > 50]
print(nums2)
使用列表生成式创建列表不仅代码简单优雅,而且性能上也优于使用
for-in
循环和append
方法向空列表中追加元素的方式。为什么说生成式有更好的性能呢,那是因为 Python 解释器的字节码指令中有专门针对生成式的指令(LIST_APPEND
指令);而for
循环是通过方法调用(LOAD_METHOD
和CALL_METHOD
指令)的方式为列表添加元素,方法调用本身就是一个相对比较耗时的操作。对这一点不理解也没有关系,记住“强烈建议用生成式语法来创建列表”这个结论就可以了。
Python 语言没有限定列表中的元素必须是相同的数据类型,也就是说一个列表中的元素可以任意的数据类型,当然也包括列表本身。如果列表中的元素也是列表,那么我们可以称之为嵌套的列表。嵌套的列表可以用来表示表格或数学上的矩阵。
例如:我们想保存5个学生3门课程的成绩,可以用如下所示的列表。
scores = [[95, 83, 92], [80, 75, 82], [92, 97, 90], [80, 78, 69], [65, 66, 89]]
print(scores[0]) # [95, 83, 92]
print(scores[0][1]) # 83
对于上面的嵌套列表,每个元素相当于就是一个学生3门课程的成绩,例如[95, 83, 92]
,而这个列表中的83
代表了这个学生某一门课的成绩,如果想访问这个值,可以使用两次索引运算scores[0][1]
,其中scores[0]
可以得到[95, 83, 92]
这个列表,再次使用索引运算[1]
就可以获得该列表中的第二个元素。
如果想通过键盘输入的方式来录入5个学生3门课程的成绩并保存在列表中,可以使用如下所示的代码。
scores = []
for _ in range(5):
temp = []
for _ in range(3):
score = int(input('请输入: '))
temp.append(score)
scores.append(temp)
print(scores)
如果想通过产生随机数的方式来生成5个学生3门课程的成绩并保存在列表中,我们可以使用列表生成式,代码如下所示。
import random
scores = [[random.randrange(60, 101) for _ in range(3)] for _ in range(5)]
print(scores)
说明:上面的代码 [random.randrange(60, 101) for _ in range(3)]
可以产生由3个随机整数构成的列表,我们把这段代码又放在了另一个列表生成式中作为列表的元素,这样的元素一共生成5个,最终得到了一个嵌套列表。
双色球是由中国福利彩票发行管理中心发售的乐透型彩票,每注投注号码由6
个红色球和1
个蓝色球组成。红色球号码从1
到33
中选择,蓝色球号码从1
到16
中选择。每注需要选择6
个红色球号码和1
个蓝色球号码,如下所示。
提示:知乎上有一段对国内各种形式的彩票本质的论述相当精彩,这里分享给大家:“ 虚构一个不劳而获的人,去忽悠一群想不劳而获的人,最终养活一批真正不劳而获的人”。珍爱生命,远离(任何形式的)赌博!
下面,我们通过 Python 程序来生成一组随机号码。
"""
双色球随机选号程序
"""
import random
red_balls = list(range(1, 34))
selected_balls = []
# 添加6个红色球到选中列表
for _ in range(6):
# 生成随机整数代表选中的红色球的索引位置
index = random.randrange(len(red_balls))
# 将选中的球从红色球列表中移除并添加到选中列表
selected_balls.append(red_balls.pop(index))
# 对选中的红色球排序
selected_balls.sort()
# 输出选中的红色球
for ball in selected_balls:
print(f'\033[031m{ball:0>2d}\033[0m', end=' ')
# 随机选择1个蓝色球
blue_ball = random.randrange(1, 17)
# 输出选中的蓝色球
print(f'\033[034m{blue_ball:0>2d}\033[0m')
说明:上面代码中print(f'\033[0m...\033[0m')
是为了控制输出内容的颜色,红色球输出成红色,蓝色球输出成蓝色。其中省略号代表我们要输出的内容,\033[0m
是一个控制码,表示关闭所有属性,也就是说之前的控制码将会失效,你也可以将其简单的理解为一个定界符,m
前面的0
表示控制台的显示方式为默认值,0
可以省略,1
表示高亮,5
表示闪烁,7
表示反显等。在0
和m
的中间,我们可以写上代表颜色的数字,比如30
代表黑色,31
代表红色,32
代表绿色,33
代表黄色,34
代表蓝色等。
我们还可以利用random
模块提供的sample
和choice
函数来简化上面的代码,前者可以实现无放回随机抽样,后者可以实现随机抽取一个元素,修改后的代码如下所示。
"""
双色球随机选号程序
"""
import random
red_balls = [i for i in range(1, 34)]
blue_balls = [i for i in range(1, 17)]
# 从红色球列表中随机抽出6个红色球(无放回抽样)
selected_balls = random.sample(red_balls, 6)
# 对选中的红色球排序
selected_balls.sort()
# 输出选中的红色球
for ball in selected_balls:
print(f'\033[031m{ball:0>2d}\033[0m', end=' ')
# 从蓝色球列表中随机抽出1个蓝色球
blue_ball = random.choice(blue_balls)
# 输出选中的蓝色球
print(f'\033[034m{blue_ball:0>2d}\033[0m')
如果要实现随机生成N
注号码,我们只需要将上面的代码放到一个N
次的循环中,如下所示。
"""
双色球随机选号程序
"""
import random
n = int(input('生成几注号码: '))
red_balls = [i for i in range(1, 34)]
blue_balls = [i for i in range(1, 17)]
for _ in range(n):
# 从红色球列表中随机抽出6个红色球(无放回抽样)
selected_balls = random.sample(red_balls, 6)
# 对选中的红色球排序
selected_balls.sort()
# 输出选中的红色球
for ball in selected_balls:
print(f'\033[031m{ball:0>2d}\033[0m', end=' ')
# 从蓝色球列表中随机抽出1个蓝色球
blue_ball = random.choice(blue_balls)
# 输出选中的蓝色球
print(f'\033[034m{blue_ball:0>2d}\033[0m')
我们在 PyCharm 中运行上面的代码,输入4,运行效果如下图所示。
Python 中的列表底层是一个可以动态扩容的数组,列表元素在计算机内存中是连续存储的,所以可以实现随机访问(通过一个有效的索引获取对应的元素且操作时间与列表元素个数无关)。
在 Python 中,元组也是多个元素按照一定顺序构成的序列。元组和列表的不同之处在于,元组是不可变类型,这就意味着元组类型的变量一旦定义,其中的元素不能再添加或删除,而且元素的值也不能修改。如果试图修改元组中的元素,将引发TypeError
错误,导致程序崩溃。定义元组通常使用形如(x, y, z)
的字面量语法,元组类型支持的运算符跟列表是一样的。【元组里面的元素一旦定义不可更改】
# 定义一个三元组
t1 = (35, 12, 98)
# 定义一个四元组
t2 = ('大力', 23, True, '湖南长沙')
# 查看变量的类型
print(type(t1)) #
print(type(t2)) #
# 查看元组中元素的数量
print(len(t1)) # 3
print(len(t2)) # 4
# 索引运算
print(t1[0]) # 35
print(t1[2]) # 98
print(t2[-1]) # 湖南长沙
# 切片运算
print(t2[:2]) # ('大力', 23)
print(t2[::3]) # ('大力', '湖南长沙')
# 循环遍历元组中的元素
for elem in t1:
print(elem)
# 成员运算
print(12 in t1) # True
print(99 in t1) # False
print('Hao' not in t2) # True
# 拼接运算
t3 = t1 + t2
print(t3) # (35, 12, 98, '大力', 23, True, '湖南长沙')
# 比较运算
print(t1 == t3) # False
print(t1 >= t3) # False
print(t1 <= (35, 11, 99)) # False
一个元组中如果有两个元素,我们就称之为二元组;一个元组中如果五个元素,我们就称之为五元组。需要提醒大家注意的是,()
表示空元组,但是如果元组中只有一个元素,需要加上一个逗号,否则()
就不是代表元组的字面量语法,而是改变运算优先级的圆括号,所以('hello', )
和(100, )
才是一元组,而('hello')
和(100)
只是字符串和整数。
a = ()
print(type(a)) #
b = ('hello')
print(type(b)) #
c = (100)
print(type(c)) #
d = ('hello', )
print(type(d)) #
e = (100, )
print(type(e)) #
当我们把多个用逗号分隔的值赋给一个变量时,多个值会打包成一个元组类型;当我们把一个元组赋值给多个变量时,元组会解包成多个值然后分别赋给对应的变量。
# 打包操作
a = 1, 10, 100
print(type(a)) #
print(a) # (1, 10, 100)
# 解包操作
i, j, k = a
print(i, j, k) # 1 10 100
在解包时,如果解包出来的元素个数和变量个数不对应,会引发ValueError
异常,错误信息为:too many values to unpack
(解包的值太多)或not enough values to unpack
(解包的值不足)。
a = 1, 10, 100, 1000
# i, j, k = a # ValueError: too many values to unpack (expected 3)
# i, j, k, l, m, n = a # ValueError: not enough values to unpack (expected 6, got 4)
有一种解决变量个数少于元素的个数方法,就是使用星号表达式。通过星号表达式,我们可以让一个变量接收多个值,代码如下所示。需要注意两点:
a = 1, 10, 100, 1000
i, j, *k = a
print(i, j, k) # 1 10 [100, 1000]
i, *j, k = a
print(i, j, k) # 1 [10, 100] 1000
*i, j, k = a
print(i, j, k) # [1, 10] 100 1000
*i, j = a
print(i, j) # [1, 10, 100] 1000
i, *j = a
print(i, j) # 1 [10, 100, 1000]
i, j, k, *l = a
print(i, j, k, l) # 1 10 100 [1000]
i, j, k, l, *m = a
print(i, j, k, l, m) # 1 10 100 1000 []
需要说明一点,解包语法对所有的序列都成立,这就意味着我们之前讲的列表、range
函数构造的范围序列甚至字符串都可以使用解包语法。
a, b, *c = range(1, 10)
print(a, b, c) # 1 2 [3, 4, 5, 6, 7, 8, 9]
a, b, c = [1, 10, 100]
print(a, b, c) # 1 10 100
a, *b, c = 'hello'
print(a, b, c) # h ['e', 'l', 'l'] o
交换变量的值是写代码时经常用到的一个操作,但是在很多编程语言中,交换两个变量的值都需要借助一个中间变量才能做到,如果不用中间变量就需要使用比较晦涩的位运算来实现。在 Python 中,交换两个变量a
和b
的值只需要使用如下所示的代码。【超简洁!】
a, b = b, a
同理,如果要将三个变量a
、b
、c
的值互换,即b
的值赋给a
,c
的值赋给b
,a
的值赋给c
,也可以如法炮制。
a, b, c = b, c, a
需要说明的是,上面的操作并没有用到打包和解包语法,Python 的字节码指令中有ROT_TWO
和ROT_THREE
这样的指令可以直接实现这个操作,效率是非常高的。但是如果有多于三个变量的值要依次互换,这个时候是没有直接可用的字节码指令的,需要通过打包解包的方式来完成变量之间值的交换。
timeit
模块的timeit
函数来看看创建保存相同元素的元组和列表各自花费的时间,timeit
函数的number
参数表示代码执行的次数。下面的代码中,我们分别创建了保存1
到9
的整数的列表和元组,每个操作执行10000000
次,统计运行时间。 import timeit
print('%.3f' % timeit.timeit('[1, 2, 3, 4, 5, 6, 7, 8, 9]', number=10000000)) # 0.527
print('%.3f' % timeit.timeit('(1, 2, 3, 4, 5, 6, 7, 8, 9)', number=10000000)) # 0.099
说明:上面代码的执行结果因软硬件系统而异,在我目前使用的电脑上,执行10000000
次创建列表的操作时间是0.527
秒,而执行10000000
次创建元组的操作时间是0.099
秒,显然创建元组更快且二者时间上有数量级的差别。当然,Python 中的元组和列表类型是可以相互转换的。
infos = ('大力', 23, True, '湖南长沙')
# 将元组转换成列表
print(list(infos)) # ['大力', 23, True, '湖南长沙']
fruits = ['apple', 'banana', 'orange']
# 将列表转换成元组
print(tuple(fruits)) # ('apple', 'banana', 'orange')
列表和元组都是容器型的数据类型,即一个变量可以保存多个数据,而且它们都是按一定顺序组织元素的有序容器。列表是可变数据类型,元组是不可变数据类型,所以列表可以添加元素、删除元素、清空元素、排序反转,但这些操作对元组来说是不成立的。列表和元组都可以支持拼接运算、成员运算、索引运算、切片运算等操作,后面我们要学到的字符串类型也支持这些运算,因为字符串就是字符按一定顺序构成的序列,在这一点上三者并没有什么区别。推荐使用列表的生成式语法来创建列表,它不仅好用而且效率很高,是 Python 语言中非常有特色的语法。
所谓字符串,就是由零个或多个字符组成的有限序列,一般记为:
s = a1a2⋯an(0≤n≤∞)
在 Python 程序中,我们把单个或多个字符用单引号或者双引号包围起来,就可以表示一个字符串。字符串中的字符可以是特殊符号、英文字母、中文字符、日文的平假名或片假名、希腊字母、Emoji 字符(如: 、 、 ️)等。
s1 = 'hello, world!'
s2 = "你好,世界!❤️"
s3 = '''hello,
wonderful
world!'''
print(s1)
print(s2)
print(s3)
结果
hello, world!
你好,世界!❤️
hello,
wonderful
world!
我们可以在字符串中使用\
(反斜杠)来表示转义,也就是说\
后面的字符不再是它原来的意义,例如:\n
不是代表字符\
和字符n
,而是表示换行;\t
也不是代表字符\
和字符t
,而是表示制表符。所以如果字符串本身又包含了'
、"
、\
这些特殊的字符,必须要通过\
进行转义处理。例如要输出一个带单引号或反斜杠的字符串,需要用如下所示的方法。
s1 = '\'hello, world!\''
s2 = '\\hello, world!\\'
print(s1) # 'hello, world!'
print(s2) # \hello, world!\
常见转义字符
# 续行符
str1 = "abcdefghijk\
lmnopqrstuvwxyz"
print(str1)
# 单引号
print('Hello\'World')
# 双引号
print("Hello\"World")
# 反斜杠
print("Hello\\World")
# 退格键
print("Hello \bWorld")
# 空字符
print("Hello \0World")
# 换行符
print("Hello \nWorld")
# 制表符
print("Hello\tWorld")
# 回车符
print("Hello\rWorld")
# 八进制
print("\110")
# 十六进制
print("\x48")
结果
# 续行符
str1 = "abcdefghijk\
lmnopqrstuvwxyz" # abcdefghijklmnopqrstuvwxyz
print(str1)
# 单引号
print('Hello\'World') # Hello'World
# 双引号
print("Hello\"World") # Hello"World
# 反斜杠
print("Hello\\World") # Hello\World
# 退格键
print("Hello \bWorld") # HelloWorld
# 空字符
print("Hello \0World") # Hello World
# 换行符
print("Hello \nWorld") # Hello
# World
# 制表符
print("Hello\tWorld") # Hello World
# 回车符
print("Hello\rWorld") # World
# 八进制
print("\110") # H
# 十六进制
print("\x48") # H
Python 中有一种以r
或R
开头的字符串,这种字符串被称为原始字符串,意思是字符串中的每个字符都是它本来的含义,没有所谓的转义字符。例如,在字符串'hello\n'
中,\n
表示换行;而在r'hello\n'
中,\n
不再表示换行,就是字符\
和字符n
。
s1 = '\it \is \time \to \read \now'
s2 = r'\it \is \time \to \read \now'
print(s1)
print(s2)
结果
ead
ow
\it \is \time \to \read \now
说明:上面的变量s1
中,\t
、\r
和\n
都是转义字符。\t
是制表符(table),\n
是换行符(new line),\r
是回车符(carriage return)相当于让输出回到了行首。
Python 中还允许在\
后面还可以跟一个八进制或者十六进制数来表示字符,例如\141
和\x61
都代表小写字母a
,前者是八进制的表示法,后者是十六进制的表示法。另外一种表示字符的方式是在\u
后面跟 Unicode 字符编码,例如\u9a86\u660a
代表的是中文“大力”。
s1 = '\141\142\143\x61\x62\x63'
s2 = '\u5927\u529b'
print(s1) # abcabc
print(s2) # 大力
可以通过下面的代码查询字符对应的Unicode字符编码
print(hex(ord('大')), hex(ord('力'))) # 0x5927 0x529b
ord()函数获取对应的字符编码,hex()函数将结果转换成十六进制。
Python 语言为字符串类型提供了非常丰富的运算符,有很多运算符跟列表类型的运算符作用类似。例如,我们可以使用+
运算符来实现字符串的拼接,可以使用*
运算符来重复一个字符串的内容,可以使用in
和not in
来判断一个字符串是否包含另外一个字符串,我们也可以用[]
和[:]
运算符从字符串取出某个字符或某些字符。
python常见运算操作符如下所示。
下面的例子演示了使用+
和*
运算符来实现字符串的拼接和重复操作。
s1 = 'hello' + ', ' + 'world'
print(s1) # hello, world
s2 = '!' * 3
print(s2) # !!!
s1 += s2
print(s1) # hello, world!!!
s1 *= 2
print(s1) # hello, world!!!hello, world!!!
用*
实现字符串的重复是非常有意思的一个运算符,在很多编程语言中,要表示一个有10个a
的字符串,你只能写成'aaaaaaaaaa'
,但是在 Python 中,你可以写成'a' * 10
。
对于两个字符串类型的变量,可以直接使用比较运算符来判断两个字符串的相等性或比较大小。需要说明的是,因为字符串在计算机内存中也是以二进制形式存在的,那么字符串的大小比较比的是每个字符对应的编码的大小。例如A
的编码是65
, 而a
的编码是97
,所以'A' < 'a'
的结果相当于就是65 < 97
的结果,这里很显然是True
;而'boy' < 'bad'
,因为第一个字符都是'b'
比不出大小,所以实际比较的是第二个字符的大小,显然'o' < 'a'
的结果是False
,所以'boy' < 'bad'
的结果是False
。如果不清楚两个字符对应的编码到底是多少,可以使用ord
函数来获得,之前我们有提到过这个函数。例如ord('A')
的值是65
,而ord('大')
的值是22823。
s1 = 'a whole new world'
s2 = 'hello world'
print(s1 == s2) # False
print(s1 < s2) # True
print(s1 == 'hello world') # False
print(s2 == 'hello world') # True
print(s2 != 'Hello world') # True
s3 = '大力'
print(ord('大')) # 22823
print(ord('力')) # 21147
print(s3 >= s2) # True
print(s3 != s2) # True
Python 中可以用in
和not in
判断一个字符串中是否包含另外一个字符或字符串,跟列表类型一样,in
和not in
称为成员运算符,会产生布尔值True
或False
。
s1 = 'hello, world'
s2 = 'goodbye, world'
print('wo' in s1) # True
print('wo' not in s2) # False
print(s2 in s1) # False
获取字符串长度跟获取列表元素个数一样,使用内置函数len
,代码如下所示。
s = 'hello, world'
print(len(s)) # 12
print(len('goodbye, world')) # 14
注意:逗号,后面的空格符也算作一个字符哦!
字符串的索引和切片操作跟列表几乎一样,因为字符串也是一种有序序列,可以通过正向或反向的整数索引访问其中的元素。但是有一点需要注意,因为字符串是不可变类型,所以不能通过索引运算修改字符串中的字符。
s = 'abc123456'
n = len(s)
print(s[0], s[-n]) # a a
print(s[n-1], s[-1]) # 6 6
print(s[2], s[-7]) # c c
print(s[5], s[-4]) # 3 3
print(s[2:5]) # c12
print(s[-7:-4]) # c12
print(s[2:]) # c123456
print(s[:2]) # ab
print(s[::2]) # ac246
print(s[::-1]) # 654321cba
注意:在进行索引运算时,如果索引越界,会引发IndexError
异常,错误提示信息为:string index out of range
(字符串索引超出范围)。
如果希望遍历字符串中的每个字符,可以使用for-in
循环,有如下所示的两种方式。
方式一:
s = 'hello'
for i in range(len(s)):
print(s[i])
方式二:
s = 'hello'
for elem in s:
print(elem)
在 Python 中,可以通过字符串类型自带的方法对字符串进行操作和处理,跟前面使用列表方法的语法是一样的。
下面的代码演示了和字符串大小写变换相关的方法。
s1 = 'hello, world!'
# 字符串首字母大写
print(s1.capitalize()) # Hello, world!
# 字符串每个单词首字母大写
print(s1.title()) # Hello, World!
# 字符串变大写
print(s1.upper()) # HELLO, WORLD!
s2 = 'GOODBYE'
# 字符串变小写
print(s2.lower()) # goodbye
# 检查s1和s2的值
print(s1) # hello, world
print(s2) # GOODBYE
说明:由于 字符串是不可变类型,使用字符串的方法对字符串进行操作会产生新的字符串,但是原来变量的值并没有发生变化。所以上面的代码中,当我们最后检查s1
和s2
两个变量的值时,s1
和s2
的值并没有发生变化。
如果想在一个字符串中从前向后查找有没有另外一个字符串,可以使用字符串的find
或index
方法。在使用find
和index
方法时还可以通过方法的参数来指定查找的范围,也就是查找不必从索引为0
的位置开始。
-1。
ValueError
错误。s = 'hello, world!'
print(s.find('or')) # 8
print(s.find('or', 9)) # -1
print(s.find('of')) # -1
print(s.index('or')) # 8
print(s.index('or', 9)) # ValueError: substring not found
find
和index
方法还有逆向查找(从后向前查找)的版本,分别是rfind
和rindex
。
s = 'hello world!'
print(s.find('o')) # 4
print(s.rfind('o')) # 7
print(s.rindex('o')) # 7
print(s.rindex('o', 8)) # ValueError: substring not found
可以通过字符串的startswith
、endswith
来判断字符串是否以某个字符串开头和结尾;还可以用is
开头的方法判断字符串的特征,这些方法都返回布尔值。
s1 = 'hello, world!'
print(s1.startswith('He')) # False
print(s1.startswith('hel')) # True
print(s1.endswith('!')) # True
s2 = 'abc123456'
print(s2.isdigit()) # False
print(s2.isalpha()) # False
print(s2.isalnum()) # True
在 Python 中,字符串类型可以通过center
、ljust
、rjust
方法做居中、左对齐和右对齐的处理。如果要在字符串的左侧补零,也可以使用zfill
方法。
s = 'hello, world'
print(s.center(20, '*')) # ****hello, world****
print(s.rjust(20)) # hello, world
print(s.ljust(20, '~')) # hello, world~~~~~~~~
print('33'.zfill(5)) # 00033
print('-33'.zfill(5)) # -0033
在用print
函数输出字符串时,可以用下面的方式对字符串进行格式化。
a = 321
b = 123
print('%d * %d = %d' % (a, b, a * b))
也可以用字符串的format
方法来完成字符串的格式。
a = 321
b = 123
print('{0} * {1} = {2}'.format(a, b, a * b))
从 Python 3.6 开始,格式化字符串还有更为简洁的书写方式,就是在字符串前加上f
来格式化字符串,在这种以f
打头的字符串中,{变量名}
是一个占位符,会被变量对应的值将其替换掉。
a = 321
b = 123
print(f'{a} * {b} = {a * b}')
如果需要进一步控制格式化语法中变量值的形式,可以参照下面的表格来进行字符串格式化操作。
变量值 | 占位符 | 格式化结果 | 说明 |
---|---|---|---|
3.1415926 | {:.2f} | '3.14' | 保留小数点后两位 |
3.1415926 | {:+.2f} | '+3.14' | 带符号保留小数点后两位 |
-1 | {:+.2f} | '-1.00' | 带符号保留小数点后两位 |
3.1415926 | {:.0f} | '3' | 不带小数 |
123 | {:0>10d} | '0000000123' | 左边补0,补够10位 |
123 | {:x<10d} | '123xxxxxxx' | 右边补x ,补够10位 |
123 | {:>10d} | ' 123' | 左边补空格,补够10位 |
123 | {:<10d} | '123 ' | 右边补空格,补够10位 |
123456789 | {:,} | '123,456,789' | 逗号分隔格式 |
0.123 | {:.2%} | '12.30%' | 百分比格式 |
123456789 | {:.2e} | '1.23e+08' | 科学计数法格式 |
字符串的strip
方法可以获得将原字符串修剪掉左右两端指定字符之后的字符串,默认是修剪空格字符。这个方法非常有实用价值,可以用来将用户输入时不小心键入的头尾空格等去掉,strip
方法还有lstrip
和rstrip
两个版本。
s1 = ' [email protected] '
print(s1.strip()) # [email protected]
s2 = '~你好,世界~'
print(s2.lstrip('~')) # 你好,世界~
print(s2.rstrip('~')) # ~你好,世界
如果希望用新的内容替换字符串中指定的内容,可以使用replace
方法。replace
方法的第一个参数是被替换的内容,第二个参数是替换后的内容,还可以通过第三个参数指定替换的次数。
s = 'hello, good world'
print(s.replace('o', '@')) # hell@, g@@d w@rld
print(s.replace('o', '@', 1)) # hell@, good world
可以使用字符串的split
方法将一个字符串拆分为多个字符串(放在一个列表中),也可以使用字符串的join
方法将列表中的多个字符串连接成一个字符串。
s = 'I love you'
words = s.split()
print(words) # ['I', 'love', 'you']
print('~'.join(words)) # I~love~you
注意:split
方法默认使用空格进行拆分,我们也可以指定其他的字符来拆分字符串,而且还可以指定最大拆分次数来控制拆分的效果。
s = 'I#love#you#so#much'
words = s.split('#')
print(words) # ['I', 'love', 'you', 'so', 'much']
words = s.split('#', 2)
print(words) # ['I', 'love', 'you#so#much']
Python 中除了字符串str
类型外,还有一种表示二进制数据的字节串类型(bytes
)。所谓字节串,就是由零个或多个字节组成的有限序列。通过字符串的encode
方法,我们可以按照某种编码方式将字符串编码为字节串,我们也可以使用字节串的decode
方法,将字节串解码为字符串。
a = '大力'
b = a.encode('utf-8')
c = a.encode('gbk')
print(b) # b'\xe5\xa4\xa7\xe5\x8a\x9b'
print(c) # b'\xb4\xf3\xc1\xa6'
print(b.decode('utf-8')) # 大力
print(c.decode('gbk')) # 大力
注意:如果编码和解码的方式不一致,会导致乱码问题(无法再现原始的内容)或引发
UnicodeDecodeError
错误,导致程序崩溃。
对于字符串类型来说,还有一个常用的操作是对字符串进行匹配检查,即检查字符串是否满足某种特定的模式。例如,一个网站对用户注册信息中用户名和邮箱的检查,就属于模式匹配检查。实现模式匹配检查的工具叫做正则表达式,Python 语言通过标准库中的re
模块提供了对正则表达式的支持。其它方法后面随着学习再进行补充。
如果我们把一定范围的、确定的、可以区别的事物当作一个整体来看待,那么这个整体就是集合,集合中的各个事物称为集合的元素。通常,集合需要满足以下特性:
注意:
in
和not in
成员运算的,这样就可以确定一个元素是否属于集合。在 Python 中,创建集合可以使用{}
字面量语法,{}
中需要至少有一个元素,因为没有元素的{}
并不是空集合而是一个空字典,字典是一中数据类型。也可以使用 Python 内置函数set
来创建一个集合,准确的说set
并不是一个函数,而是创建集合对象的构造器。
可以使用set
函数创建一个空集合,也可以用它将其他序列转换成集合,例如:set('hello')
会得到一个包含了4
个字符的集合(重复的字符l
只会在集合中出现一次)。除了这两种方式,还可以使用生成式语法来创建集合,就像我们之前用生成式语法创建列表那样。
set1 = {1, 2, 3, 3, 3, 2}
print(set1) # {1, 2, 3}
set2 = {True, False, True, True, False}
print(set2) # {False, True}
set3 = set('hello')
print(set3) # {'l', 'o', 'e', 'h'}
set4 = set([1, 2, 2, 3, 3, 3, 2, 1])
print(set4) # {1, 2, 3}
set5 = {num for num in range(1, 20) if num % 3 == 0 or num % 7 == 0}
print(set5) # {3, 6, 7, 9, 12, 14, 15, 18}
set6 = {('大力', 23), ('小气', 18)}
print(set6) # {('大力', 23), ('小气', 18)}
集合中的元素必须是hashable
类型,使用哈希存储的容器都会对元素提出这一要求。所谓hashable
类型指的是能够计算出哈希码的数据类型,通常不可变类型都是hashable
类型,如整数(int
)、浮点小数(float
)、布尔值(bool
)、字符串(str
)、元组(tuple
)等。可变类型都不是hashable
类型,因为可变类型无法计算出确定的哈希码,所以它们不能放到集合中。例如:我们不能将列表、集合作为集合中的元素。我们可以创建出嵌套的列表,但是我们不能创建出嵌套的集合,这一点在使用集合的时候一定要引起注意。【集合里面的元素必须是不可变类型的!】
我们可以通过len
函数来获得集合中有多少个元素,不能通过索引运算来遍历集合中的元素,因为集合元素并没有特定的顺序。当然,要实现对集合元素的遍历,我们仍然可以使用for-in
循环。
set1 = {'Python', 'C++', 'Java', 'Kotlin', 'Swift'}
for elem in set1:
print(elem)
结果
C++
Kotlin
Java
Python
Swift
提示:体会一下集合的无序性。
Python 为集合类型提供了非常丰富的运算符,主要包括:成员运算、交集运算、并集运算、差集运算、比较运算(相等性、子集、超集)等。
可以通过成员运算in
和not in
检查元素是否在集合中。
set1 = {11, 12, 13, 14, 15}
print(10 in set1) # False
print(15 in set1) # True
set2 = {'Python', 'Java', 'C++', 'Swift'}
print('Ruby' in set2) # False
print('Java' in set2) # True
集合的二元运算主要指集合的交集、并集、差集、对称差等运算,这些运算可以通过运算符来实现,也可以通过集合类型的方法来实现。
set1 = {1, 2, 3, 4, 5, 6, 7}
set2 = {2, 4, 6, 8, 10}
# 交集
print(set1 & set2) # {2, 4, 6}
print(set1.intersection(set2)) # {2, 4, 6}
# 并集
print(set1 | set2) # {1, 2, 3, 4, 5, 6, 7, 8, 10}
print(set1.union(set2)) # {1, 2, 3, 4, 5, 6, 7, 8, 10}
# 差集
print(set1 - set2) # {1, 3, 5, 7}
print(set1.difference(set2)) # {1, 3, 5, 7}
# 对称差
print(set1 ^ set2) # {1, 3, 5, 7, 8, 10}
print(set1.symmetric_difference(set2)) # {1, 3, 5, 7, 8, 10}
对两个集合求交集,&
运算符和intersection
方法的作用是完全相同的,使用运算符的方式显然更直观且代码也更简短。需要说明的是,集合的二元运算还可以跟赋值运算一起构成复合赋值运算,例如:set1 |= set2
相当于set1 = set1 | set2
,跟|=
作用相同的方法是update
;set1 &= set2
相当于set1 = set1 & set2
,跟&=
作用相同的方法是intersection_update
。
set1 = {1, 3, 5, 7}
set2 = {2, 4, 6}
set1 |= set2
# set1.update(set2)
print(set1) # {1, 2, 3, 4, 5, 6, 7}
set3 = {3, 6, 9}
set1 &= set3
# set1.intersection_update(set3)
print(set1) # {3, 6}
set2 -= set1
# set2.difference_update(set1)
print(set2) # {2, 4}
两个集合可以用==
和!=
进行相等性判断,如果两个集合中的元素完全相同,那么==
比较的结果就是True
,否则就是False
。如果集合A
的任意一个元素都是集合B
的元素,那么集合A
称为集合B
的子集,即对于∀a∈A,均有a∈B,则A⊆B,A
是B
的子集,反过来也可以称B
是A
的超集。如果A
是B
的子集且A
不等于B
,那么A
就是B
的真子集。Python 为集合类型提供了判断子集和超集的运算符,其实就是我们非常熟悉的<
、<=
、>
、>=
这些运算符。当然,我们也可以通过集合类型的方法issubset
和issuperset
来判断集合之间的关系。
set1 < set2
判断set1
是不是set2
的真子集set1 <= set2
判断set1
是不是set2
的子集set2 > set1
判断set2
是不是set1
的超集set1.issubset(set2)
判断set1
是不是set2
的子集set2.issuperset(set1)
判断set2
是不是set1
的超集set1 = {1, 3, 5}
set2 = {1, 2, 3, 4, 5}
set3 = {5, 4, 3, 2, 1}
print(set1 < set2) # True
print(set1 <= set2) # True
print(set2 < set3) # False
print(set2 <= set3) # True
print(set2 > set1) # True
print(set2 == set3) # True
print(set1.issubset(set2)) # True
print(set2.issuperset(set1)) # True
Python 中的集合是可变类型,可以通过集合类型的方法向集合添加元素或从集合中删除元素。
KeyError
错误,所以先通过成员运算判断元素是否在集合中。set1 = {1, 10, 100}
# 添加元素
set1.add(1000)
set1.add(10000)
print(set1) # {1, 100, 1000, 10, 10000}
# 删除元素
set1.discard(10)
if 100 in set1:
set1.remove(100)
print(set1) # {1, 1000, 10000}
# 清空元素
set1.clear()
print(set1) # set()
集合类型还有一个名为isdisjoint
的方法可以判断两个集合有没有相同的元素,如果没有相同元素,该方法返回True
,否则该方法返回False
。
set1 = {'Java', 'Python', 'C++', 'Kotlin'}
set2 = {'Kotlin', 'Swift', 'Java', 'Dart'}
set3 = {'HTML', 'CSS', 'JavaScript'}
print(set1.isdisjoint(set2)) # False
print(set1.isdisjoint(set3)) # True
Python 中还有一种不可变类型的集合,名字叫frozenset
。set
跟frozenset
的区别就如同list
跟tuple
的区别,frozenset
由于是不可变类型,能够计算出哈希码,因此它可以作为set
中的元素。除了不能添加和删除元素,frozenset
在其他方面跟set
是一样的。
fset1 = frozenset({1, 3, 5, 7})
fset2 = frozenset(range(1, 6))
print(fset1) # frozenset({1, 3, 5, 7})
print(fset2) # frozenset({1, 2, 3, 4, 5})
print(fset1 & fset2) # frozenset({1, 3, 5})
print(fset1 | fset2) # frozenset({1, 2, 3, 4, 5, 7})
print(fset1 - fset2) # frozenset({7})
print(fset1 < fset2) # False
Python 中的集合类型是一种无序容器,不允许有重复运算,由于底层使用了哈希存储,集合中的元素必须是hashable
类型。集合与列表最大的区别在于集合中的元素没有顺序、所以不能够通过索引运算访问元素、但是集合可以执行交集、并集、差集等二元运算,也可以通过关系运算符检查两个集合是否存在超集、子集等关系。
字典是另一种可变容器模型,且可存储任意类型对象。
字典的每个键值 key=>value 对用冒号 : 分割,每个对之间用逗号(,)分割,整个字典包括在花括号 {} 中 ,格式如下所示:
d = {key1 : value1, key2 : value2, key3 : value3 }
注意:dict 作为 Python 的关键字和内置函数,变量名不建议命名为 dict。
键必须是唯一的,但值则不必。值可以取任何数据类型,但键必须是不可变的,如字符串,数字。
一个简单的字典实例:
tinydict = {'name': 'runoob', 'likes': 123, 'url': 'www.runoob.com'}
也可如此创建字典:
tinydict1 = { 'abc': 456 }
tinydict2 = { 'abc': 123, 98.6: 37 }
创建空字典,有两种方式,使用大括号{}或者内建函数dict()
使用大括号 { } 创建空字典:
# 使用大括号 {} 来创建空字典
emptyDict = {}
# 打印字典
print(emptyDict) # {}
# 查看字典的数量
print("Length:", len(emptyDict)) # Length: 0
# 查看类型
print(type(emptyDict)) #
使用内建函数 dict() 创建字典
emptyDict = dict()
# 打印字典
print(emptyDict) # {}
# 查看字典的数量
print("Length:", len(emptyDict)) # Length: 0
# 查看类型
print(type(emptyDict)) #
把相应的键放入到方括号中,如下实例:
tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
print ("tinydict['Name']: ", tinydict['Name']) # tinydict['Name']: Runoob
print ("tinydict['Age']: ", tinydict['Age']) # tinydict['Age']: 7
如果用字典里没有的键访问数据,会输出错误KeyError: 'Alice'。
向字典添加新内容的方法是增加新的键/值对,修改或删除已有键/值对如下实例:
tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
tinydict['Age'] = 8 # 更新 Age
tinydict['School'] = "菜鸟教程" # 添加信息
print ("tinydict['Age']: ", tinydict['Age']) # tinydict['Age']: 8
print ("tinydict['School']: ", tinydict['School']) # tinydict['School']: 菜鸟教程
能删单一的元素也能清空字典,清空只需一项操作。显式删除一个字典用del命令,如下实例:
tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
del tinydict['Name'] # 删除键 'Name'
print(tinydict) # {'Age': 7, 'Class': 'First'}
tinydict.clear() # 清空字典
print(tinydict) # {}
del tinydict # 删除字典
print("tinydict['Age']: ", tinydict['Age']) # NameError: name 'tinydict' is not defined
最后一行代码引发一个异常,因为用执行 del 操作后字典不再存在。
字典值可以是任何的 python 对象,既可以是标准的对象,也可以是用户定义的,但键不行。
两个重要的点需要记住:
1)不允许同一个键出现两次。创建时如果同一个键被赋值两次,后一个值会被记住,如下实例:
tinydict = {'Name': 'Runoob', 'Age': 7, 'Name': '小菜鸟'}
print("tinydict['Name']: ", tinydict['Name']) # tinydict['Name']: 小菜鸟
2)键必须不可变,所以可以用数字,字符串或元组充当,而用列表就不行,如下实例:
tinydict = {['Name']: 'Runoob', 'Age': 7}
print("tinydict['Name']: ", tinydict['Name']) # TypeError: unhashable type: 'list'
内置函数
内置方法
序号 | 函数及描述 |
---|---|
1 | dict.clear() 删除字典内所有元素 |
2 | dict.copy() 返回一个字典的浅复制 |
3 | dict.fromkeys() 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值 |
4 | dict.get(key, default=None) 返回指定键的值,如果键不在字典中返回 default 设置的默认值 |
5 | key in dict 如果键在字典dict里返回true,否则返回false |
6 | dict.items() 以列表返回一个视图对象 |
7 | dict.keys() 返回一个视图对象 |
8 | dict.setdefault(key, default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default |
9 | dict.update(dict2) 把字典dict2的键/值对更新到dict里 |
10 | dict.values() 返回一个视图对象 |
11 | pop(key[,default]) 删除字典 key(键)所对应的值,返回被删除的值。 |
12 | popitem() 返回并删除字典中的最后一对键和值。 |
这部分的内容是跟着b站的黑马程序员进行学习的,在博主分享的笔记基础上进行学习和记录。主要学习函数以下知识点。
所谓函数,就是把具有独立功能的代码块组织为一个小模块,在需要的时候调用。
函数的使用包含两个步骤:
函数的作用,在开发程序时,使用函数可以提高编写的效率以及代码的重用。
以下是简单的规则:
函数的定义格式如下:
def 函数名():
函数封装的代码
……
def
是英文 define
的缩写。
函数名称应该能够表达函数封装代码 的功能,方便后续的调用。
函数名称的命名应该符合标识符的命名规则。
函数调用
定义一个函数:给了函数一个名称,指定了函数里包含的参数,和代码块结构。这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从 Python 命令提示符执行。调用函数很简单的,通过 函数名()
即可完成对函数的调用。
第一个函数演练
编写一个打招呼 say_hello
的函数,封装三行打招呼的代码。在函数下方调用打招呼的代码。
name = "小明"
# 解释器知道这里定义了一个函数
def say_hello():
print("hello 1")
print("hello 2")
print("hello 3")
print(name)
# 只有在调用函数时,之前定义的函数才会被执行
# 函数执行完成之后,会重新回到之前的程序中,继续执行后续的代码
say_hello()
print(name)
注意:定义好函数之后,只表示这个函数封装了一段代码而已。如果不主动调用函数,函数是不会主动执行的。
那么能否将函数调用放在函数定义的上方?
答案是不能!因为在使用函数名调用函数之前,必须要保证 Python
已经知道函数的存在。否则控制台会提示 NameError: name 'say_hello' is not defined
(名称错误:say_hello 这个名字没有被定义)。
PyCharm 的调试工具
F8 Step Over可以单步执行代码,会把函数调用看作是一行代码直接执行。
F7 Step Into可以单步执行代码,如果是函数,会进入函数内部。
函数的文档注释
在开发中,如果希望给函数添加注释,应该在定义函数的下方,使用连续的三对引号。
在连续的三对引号之间编写对函数的说明文字。
在函数调用位置,使用快捷键 CTRL + Q
可以查看函数的说明信息。
注意:因为 函数体相对比较独立,函数定义的上方,应该和其他代码(包括注释)保留 两个空行
考虑一种情况,需要开发一个 sum_2_num
的函数,该函数能够实现两个数字的求和功能。
def sum_2_num():
num1 = 10
num2 = 20
result = num1 + num2
print("%d + %d = %d" % (num1, num2, result))
sum_2_num()
上面的代码是将两个固定值相加,那么如果让相加的两个数可由自己来控制呢?
在调用函数时,传递到函数内部就好了!
函数参数的使用
在函数名的后面的小括号内部填写参数。
多个参数之间使用 ,
分隔。
def sum_2_num(num1, num2):
result = num1 + num2
print("%d + %d = %d" % (num1, num2, result))
sum_2_num(50, 20)
参数的作用
函数,把具有独立功能的代码块组织为一个小模块,在需要的时候调用。
函数的参数,增加函数的通用性,针对相同的数据处理逻辑,能够适应更多的数据。在函数内部,把参数当做变量使用,进行需要的数据处理。函数调用时,按照函数定义的参数顺序,把希望在函数内部处理的数据,通过参数传递。
形参和实参
形参:定义函数时,小括号中的参数,是用来接收参数用的,在函数内部作为变量使用。
实参:调用函数时,小括号中的参数,是用来把数据传递到函数内部用的。
在程序开发中,有时候,会希望一个函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理。返回值 是函数 完成工作后,最后给调用者的一个结果。在函数中使用 return
关键字可以返回结果。调用函数一方,可以使用变量来接收函数的返回结果。
注意:
return
表示返回,后续的代码都不会被执
def sum_2_num(num1, num2):
"""对两个数字的求和"""
return num1 + num2
# 调用函数,并使用 result 变量接收计算结果
result = sum_2_num(10, 20)
print("计算结果是 %d" % result)
一个函数里面 又调用了另外一个函数,这就是函数嵌套调用。
如果函数 test2
中,调用了另外一个函数 test1。
那么执行到调用 test1
函数时,会先把函数 test1
中的任务都执行完。才会回到 test2
中调用函数 test1
的位置,继续执行后续的代码。
def test1():
print("*" * 50)
print("test 1")
print("*" * 50)
def test2():
print("-" * 50)
print("test 2")
test1()
print("-" * 50)
test2()
函数嵌套的应用 —— 打印分隔线
需求 1:定义一个 print_line
函数能够打印 *
组成的 一条分隔线
def print_line(char):
print("*" * 50)
需求 2:定义一个函数能够打印由任意字符组成的分隔线
def print_line(char):
print(char * 50)
需求 3:定义一个函数能够打印 任意重复次数 的分隔线
def print_line(char, times):
print(char * times)
需求 4:定义一个函数能够打印 5 行 的分隔线,分隔线要求符合需求 3
提示:工作中针对需求的变化,应该冷静思考,不要轻易修改之前已经完成的,能够正常执行的函数!
def print_line(char, times):
print(char * times)
def print_lines(char, times):
for _ in range(5):
print_line(char, times)
print_lines('_', 50)
模块就好比是工具包,要想使用这个工具包中的工具,就需要导入import 这个模块。每一个以扩展名 py
结尾的 Python
源代码文件都是一个模块。在模块中定义的全局变量 、函数都是模块能够提供给外界直接使用的工具。
新建h_分隔线模块.py
并将上面一次输出多行的代码复制过来同时在最后一行添加name = "大力"。
def print_line(char, times):
print(char * times)
def print_lines(char, times):
for _ in range(5):
print_line(char, times)
name = "大力"
新建h_体验模块.py
文件,并且编写以下代码:
import h_分隔线模块
h_分隔线模块.print_line("*", 50)
print(h_分隔线模块.name)
结果
********************
********************
********************
********************
********************
大力
可以 在一个Python文件中定义变量或函数,然后在另外一个文件中使用 import
导入这个模块。
导入之后,就可以使用 模块名.变量
/ 模块名.函数
的方式,使用这个模块中定义的变量或者函数
模块可以让 曾经编写过的代码 方便的被 复用!
模块名也是一个标识符
标示符可以由 字母、下划线 和 数字 组成
不能以数字开头
不能与关键字重名
注意:如果在给 Python 文件起名时,以数字开头 是无法在
PyCharm
中通过导入这个模块的
可以直接像上面例子一样直接使用import导入模块,当然也可以使用from … import 语句实现模块的部分导入。Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中,语法如下:
from modname import name1[, name2[, ... nameN]]
例如,要导入模块 fibo 的 fib 函数,使用如下语句:
>>> from fibo import fib, fib2
开始学习Python了,但是没有找到合适的整理好的笔记进行学习,看视频又比较低效。所以主要参考知乎一个博主的分享内容进行学习Python怎么学习?学习Python方法和教程汇总! - 知乎,大家也可以直接去看该博主分享的内容进行学习。本文对该博主的分享内容和自己查的一些资料进行了整理学习。写这个主要是坚持“学有留痕”的思想,同时也方便自己以后回顾复习,如果刚好被打算学习Python的小伙伴看到了觉得有参考学习的价值,那就让这个行为变得更有意义叭。预祝大家都学有所成!