Python的优缺点
- Python的优点就是简单好用,语言更贴近人类的语言,同时免费开源,有强大的标准库和Pypi拓展模块社区
- Python的缺点就是执行速度慢,它和C这种一次性编译所有源代码的编译型语言不同,它是解释性语言,从上至下一边编译一边执行
- 概括来说,Python是一个非常适合自用的编程语言,用来写代码或者一些拓展类的程序很棒,但是并不适合用来构建偏底层或对执行速度有要求的大型系统
环境安装
- 在Python.org下载最新的Python版本,注意要将Python==添加到Path==这一选项勾上,同时在安装完选择取消长度限制
- 在Visual Studio Code - The open source AI code editor下载VScode,并安装中文和Python拓展
Python解释器
-
通过cmd命令行输入python,打开python解释器
-
>>>符号代表进入了交互模式 -
如果在安装时没有将python添加到系统路径,需要手动编辑系统环境变量进行添加,否则系统无法识别python相关命令
-
除了用cmd之外,也可以直接搜索python,打开python解释器
-
在解释器中输入如下语句
-
在
>>>下方的...代表着输入的时连续的语句 -
the_word_is_flat = True代表将布尔值True赋值给the_world_is_flat这个变量 -
if则是对后面的变量或语句返回的值进行判断,如果为True,则进行后续的连续语句 -
print("Be careful not to fall off!")是将"Be careful not to fall off!"这个字符串打印出来 -
对上述的布尔值、变量、判断、print等概念,在这里只做了解,后续我们会深入学习
-
输入完上述语句,我们按下回车,python解释器会再次进行一个连续行,等待我们输入后续内容,我们再次按下回车,解释器会对上述语句进行编译和执行。最后将结果显示在屏幕上
-
现在,我们对python的解释器和语句有一个简单的了解。python解释器可以将我们输入的语句逐行执行,并在屏幕上返回结果
-
这也是计算机的核心逻辑——==接受输入->进行计算->得到输出==
Python文件
-
在简单了解过Python解释器后,我们可以试着来创建一个python文件。计算机中的各种类型的文件都有着不同的编码格式,一般都通过文件的后缀名进行区分。python文件以.py结尾,我们可以新建一个文本文件,将名称改为
tutorial01.py,注意这一步要在文件管理器中,将显示文件后缀名的选项打开 -
当然,我们也可以在VScode中直接进行创建
-
第一行
# -*- coding: utf-8 -*-是声明文件的编码类型,python文件的默认编码类型是utf-8,如果要使用其他编码格式,需要在此处声明。注:==文件使用什么编码,文件中就只能用该编码支持的字符,否则会出现无法正常显示等问题== -
第二第三行是声明作者以及时间
-
在下面的行中,输入下述语句
-
import sys代表导入名为sys的模块,所谓模块就是python内置或别人编写好的python代码,我们可以直接拿过来用,不用重新编写,提高了代码复用性,避免了“重复造轮子”的行为。sys是python内置的标准库,所以我们无需进行下载 -
def main():代表定义了一个名为main的函数,括号中是函数接收的形式参数,括号内是空的,代表函数并不接收参数 -
print(f"Hello, {sys.argv[1]}!")中的f"Hello, {sys.argv[1]}!是格式化的字符串,{}内接收的是变量或语句,实际上显示的是变量的值或语句返回的值。具体代表什么意思我们稍后就能知道 -
最后
if __name__ == "__main__":判断我们是在当前文件中还是作为被导入的模块,如果是在当前文件中,则执行 -
main()代表调用main函数 -
我们打开命令行,进入文件目录,输入文件名+空格+自己的名字,然后回车
-
也可以在vscode中新建终端,输入同样的值
-
如果出现命令行闪退,要在vscode的设置中进行修改
注释
- python使用#来代表注释
- 注释不会被编译执行
- 在vscode中,使用
ctrl+/快速将语句进行注释
变量
- 在python中,我们通过等于号=来给变量赋值
- 赋值的底层逻辑,是在内存中的某个地址存入1这个值,然后用a对该值进行引用
- 简单来说,==变量就相当于是值的一个快捷方式,值就是变量引用的对象==
- 在python中,一个等于号=用来赋值,两个等于号用来比较,
is判断两个值是不是引用同一个对象,id()函数则是返回值的内存地址 - 当将表达式赋值给变量时,会先对表达式也就是等号右边进行计算,然后将返回的结果赋值给变量
- 对上述赋值语句进行拆解,
c = b + 9先计算等号右边b + 9,,由于变量b引用的是a + 4,等式右边变成了a + 4 + 9,依次类推等式右边最后变成了1 + 2 + 4 + 9也就是 16,最后将 16 赋值给变量c,注:c引用的是最后的结果 16,所以改变变量a和b的值,并不会对c产生影响 - 由于赋值的这种特性,变量也可以进行自增自减等运算,==注:自加自减等运算,对不可变类型的值来说,是创建了一个新的值让变量进行引用,原始的值并没有改动==
- 要注意,自加自减对不可变变量来说没什么区别,但对可变变量还是有很大区别的
- 变量赋值甚至还支持更高级的解包操作,同时对多个变量进行赋值,==注意,当用解包赋值时,等号左边的变量数和右边的值的个数必须相等 ==
- 变量的命名也有限制,尤其是不能用关键字,不能以数字开头,由英文字符和下划线组成,最好从命名上能看出变量代表的值的含义
数字
- 数字分为整数int、浮点数(小数)float和复数complex
- python解释器可以当成计算器使用,直接对数字进行运算
- 从上至下,依次是加、减、乘、除、整除、取余、乘方,==注,除法的结果总是一个浮点数,也就是小数==
- python中的运算同样遵循算术优先级,也可以用括号改变运算优先级
- 我们既可以直接将数字赋值给变量,也可以将表达式的结果赋值给变量,赋值后的变量也可以像数字一样进行运算
- 将整数和小数混合运算时,结果会变成小数
- 在交互模式中,表达式的值会赋值给
_ - 复数用j代表虚部,如
1+2j,可以和数字和浮点数一样进行计算
字符串
-
C语言中,字符用单引号包含,字符串用双引号包含
-
在python中,字符和字符串不做区分,用单引号和双引号包含的结果都一样
-
被引号包含的数字同样是字符串
-
type()函数用来返回一个值的类型,是常用的函数之一 -
在python中,有一些特殊的转义字符,它们以反斜杠
\为前缀 -
转义字符将反斜杠和后面的一个字符或符号视为一个整体,举例来说,
\n代表换行,\t代表制表符也就是一个tab -
当我们需要输出类型与对话的包含字符串的字符串,我们可以用不同的引号或者转义字符来实现
-
\"和\'代表了双引号和单引号 -
注意,python中,引号和括号等左右对称的符号都是==成对出现==,要注意对应关系,否则会导致语法错误
-
那如果我们要在字符串中原封不动地输出
\n或\t这样的字符,怎么办呢? -
答案就是反转义,在字符串前加r或者用双反斜杠可以反转义
-
要注意,在交互模式中,只有print会对特殊字符进行转义,如果我们直接用回显的方式显示字符串,转义字符不会起到特殊作用
-
多行的字符串可以用三对引号来包含,单引号和双引号是一样的
-
可以看到多行字符串默认给每一行末尾添加了换行符也就是
\n,我们可以在行尾添加反斜杠\取消这种行为 -
字符串可以像数字一样,用运算符来进行操作,比如用
+号进行拼接,用*号进行重复,但字符串仅支持个别运算符,类似于-号就并不支持 -
相邻的字符串会自动合并,但要注意,变量和字符串,变量和变量间不会自动合并,必须用
+号 -
除此之外,字符串还支持索引,索引这个功能重要且非常强大,许多编程语言中都有这个功能
-
python中的索引从0开始,第一个字符对应的索引是0,并且类似于
p[1:3]这样的索引切片还是以不计算索引3,也就是左闭右开的形式工作的 -
这样看起来,索引工作的方式有些奇怪。我们可以按照python官方文档给出的方式来理解
-
索引0是字符串最开始的左侧,这样既能解释为什么从零开始,也能解释切片为什么少算右边一位
-
注意,图中的“Python”字符长度为6,但最大索引只能是5。我们可以看到,字母P对应的是索引0,当我们索引为6的时候,6的右边没有值,所以无法找到,会报错提示超出索引
-
注意:当用索引切片时,不会有超出索引的担忧,这是因为python会对索引切片自动进行处理,当切片左右索引值大于长度时,就会用长度值进行代替。当左索引没有时,按0处理,右索引没有时,按长度值处理。当左索引值大于右索引值时,结果为空
-
为了更方便地进行切片,索引支持负值以及指定步长(每个值的间隔),步长可以是正的,也可以是负的,负数步长代表从后往前切片
-
我们可以用
len()函数查询字符串等序列的长度 -
有人会问,索引操作能不能用来修改字符串中的值呢?答案是否定的,因为在python中,数据类型分为两类,可变类型和不可变类型,字符串是不可变类型,要修改,我们只能新建一个字符串
-
但索引的功能只是在不可变类型中受到了限制,等我们学到可变类型后,就会发现索引功能的强大之处
列表
- 列表是 python 中的一种复合数据类型,用
[]包含,用逗号,分隔的一组值称为列表,这些值可以是不同类型的 - 列表和字符串一样,支持索引和切片
- 同样,列表也能像字符串一样用
+号进行拼接 - 和字符串不同的是,列表是可变类型,也就是说我们可以对列表中的值进行修改
- 由于列表是可变类型,所以列表这种可变类型的赋值和字符串这种不可变类型的赋值有本质上的区别
- 同样的列表,他们的值是一样的,但内存地址确不同。为什么
l1和l2不引用内存中的同一个列表呢?这样不是更节省内存空间吗? - 我们尝试将两个变量指向同一个列表,结果当我们修改其中一个列表时,另一个列表也发生了改变
- 这是因为
l1和l2引用了可变的列表后,当引用的可变列表发生改变,两个变量引用的值自然会发生改变 - 所以,除非我们强制两个变量引用同样的列表,我们新建列表时,哪怕列表的值是一样的,内存也会在不同的地址存入同样的值被不同变量引用。这样能够避免我们修改某一个变量时,其他引用同样值的变量也产生预期之外的改动
- 我们可以使用切片方法,快速地创建一个==浅拷贝==赋值给新的变量
- ==浅拷贝==相当于在内存中新建一个同样的列表,所以内存地址并不同,但是,在列表中嵌套的列表,并不会新建,也就是说
l1和l2中嵌套的列表[4, 5]仍然是同一个地址的值 - 关于赋值和深浅拷贝的解释,引用 Python 直接赋值、浅拷贝和深度拷贝解析 | 菜鸟教程中的图,解释的十分清楚明了
- 我们导入 copy 模块,尝试用深拷贝进行同样的操作,发现深拷贝将嵌套的列表也都新建了值进行引用
- 大家可以多多进行尝试和探索,了解了深浅拷贝之后,我们对可变类型、不可变类型以及变量的赋值就会有更透彻的理解
- 最后,
len()函数同样可以在列表上使用,查看列表的长度。除了可以修改值之外,列表的索引操作和字符串并无太大区别。可以理解为列表就是更高级的字符串,字符串就是只能存储字符的不可变列表
列表详解
- 列表是可变数据类型,有各种可用的方便的方法
- Append 方法——往列表中添加对象
- Extend 方法——往列表中添加一个列表中的每一项,不包括嵌套列表中的项
- Insert 方法——在指定位置插入对象,插入在索引值的左边,如果要插入在最后,索引可以超出列表索引值一位,也就是
insert(len(l), obj)等同于 append - Remove 方法——移除列表中第一个符合的对象,找不到会引发 valueerror
- Pop 方法——移除指定索引的项并返回,不指定索引则弹出最后一项,超出索引或列表为空时会报错
- Clear 方法——移除列表中的所有项,相当于
del l[:]清空列表 - Index 方法——返回对象在列表中首次出现的位置,可以指定开始和结束索引指定搜索范围
- Count 方法——返回对象在列表中的出现次数
- Sort 方法——给列表排序
- Reverse 方法——翻转列表,和 sort 功能相反
- Copy 方法——返回列表的浅拷贝,我们之前接触过
- Del 方法——按索引删除列表中的值,也可以删除整个列表
- 除了以上这些能让数据处理变的更简单的方法之外,列表还有很多有趣的特性
- 列表本身就是一个能实现让数据后入先出的==栈==,栈说白了也是存储数据的一种方式,如下图所示
- 我们用列表的 append 和 pop 方法就可以实现出栈和入栈,append 入栈,将对象添加列表中,pop 出栈,将最末尾的对象弹出
- 如果要用列表实现队列,需要用到 collections 模块
- 和列表一样,deque 用 append 入栈,但是出栈用 popleft 方法,弹出最前端的对象
- Popleft 方法相当与 del,只不过 popleft 会将删除对象返回
- 介绍完上面这些方法后,我们来学习一下列表的高级用法——==列表推导式==
- 下面这段代码,是将一个列表中的值全都开平方,然后用另一个列表保存
- 如果用列表推导式,这段代码就会变得非常简单
- 比较上面两段代码,大家可以发现,列表推导式其实就是将上面的代码浓缩到了一行里面
l2 = [i ** 2 for i in l1]其实就等价于for i in l1: l2.append(i ** 2)- 现在,我们来对列表推导式进行进阶,为它添加更多的条件。对
l1中,大于 5 的开平方,小于 5 的开立方 - 我们先用正常的语句写出来,再思考用推导式怎么去写
- 正常的语句如下
- 那么用列表推导式,就是多加一个
if-else判断语句 - 注意:在列表推导式中,如果 if 后面不需要 else 语句,if 语句要跟在 for 语句后面
- 嵌套的列表也可以使用推导式
- 如果我们要将嵌套列表的行和列翻转过来,我们需要用两个 for 语句
- 我们用推导式,则需要将两个 for 语句嵌套,要注意它们的顺序
- 在这里,更后面的 for 语句实际在更上面一层
元组
- Python中的元组是一组由逗号隔开的值
- 我们可以看到,元组在输出时会被圆括号
()包裹,在输入时则可以不用圆括号,但为了更好的区分,我们最好在定义元组时就加上圆括号。==注意,如果只有一个值,一定要加逗号== - 要注意,元组和列表不同,元组是==不可变类型==,我们可以让变量t引用新的元组,但不能对元组进行直接修改
- 那有些人就要问了,如果我在元组这个不可变类型里面嵌套一个可变的列表呢?我能修改这个列表吗?
- 答案是可以的
- 那我们再继续套娃,在这个元组里的列表中再嵌套一个元组,这个元组中的值可变吗?
- 答案是否定的
- 其实,我们可以换一种理解方式,元组本身是不能修改的,它里面的值能否修改取决于值的自身是否为可变类型
集合
- Python中的集合是一组不重复的值构成的序列
- 我们可以用
set ()方法或{}来创建集合,要注意,当创建空集合时不能用{},空{}代表的是字典 - 我们可以发现,集合有着自动去重的功能,这是集合的核心
- 我们还可以用集合来迅速比较出对象间的差值
集合a | 集合b代表选出集合a和集合b中所有的值集合a & 集合b代表选出同时存在于集合a和集合b中的值集合a ^ 集合b代表选出集合a和集合b中所有值除去集合a和集合b中共有的值- 集合和列表一样,支持推导式
- 上面推导式的作用是筛选出列表l中大于3的值,集合在赋值给变量的时候,已经自动进行了去重
集合详解
- 除了基本的赋值语句之外,集合也和列表一样有各种便于操作的方法
add()往集合中添加元素remove()从集合中移除元素,元素不存在返回KeyErrorpop()从集合中移除并返回任意一个元素。如果集合为空则会引发KeyErrorclear()移除集合中所有元素discard()判断元素是否在集合中,如果在则移除,和remove()相比就是不会报错update()合并目标集合中所有元素,相当于列表的extend(),等价于|=intersection_update()更新集合,只保留在原集合和目标集合都存在的元素,等价于&=difference_update()更新集合,移除其中也存在于 others 中的元素,相当于-=symmetric_difference_update()更新集合,只保留存在于集合的一方而非共同存在的元素
字典
- Python中的字典是以键值对组成的序列
- 键值对类似于目录+内容,我们可以用
{}或者dict()方法定义字典 - 大部分情况下,用
{}定义字典,要比dict()方法更方便 - 字典通过
字典[键] = 值的方式添加键值对,通过del 字典[键]的方式删除值 - 字典键值对的读取,有点类似于字符串和列表的索引,我们可以通过
字典[键]的方式读取键的值,也可以用字典的get()方法读取对应键的值,键不存在时会报错 - 注意:字典的键必须要是不可变类型,并且键不能重复
- 当键为可变类型时会报错,当键重复时,键的值会是最后的那个键的值
- 我们可以用
list()方法列出字典所有的键,也可以用items()方法读取所有的键和值,sort()函数则是对所有键进行排序 - 我们在遍历任何序列时,也可以用
enumerate()函数生成类似于键值对的索引和值 - 我们也可以将两个序列用
zip()函数变成一一对应的模式,序列中的值数量不对应时,只会按顺序一一对应输出,多余的值不会进行输出 - 这里我们只是简单了解,之后我们会更加深入地了解内置函数
- 字典与列表和集合一样,都能使用推导式
字典详解
- 除了上面说到的那些,字典类型也有一些方法可以方便我们使用
- 首先是
keys、values、items也就是键、值、键和值这三个字典最关键的属性 popitem()从字典中移除并返回一个键值对,按后进先出的顺序来update()更新键值对到字典,和集合的update()有异曲同工之妙- 也可以用运算符
|或|=来更新字典
While 语句
- While 语句概括来说,就是当给定条件为真时,则一直对后续的语句进行编译和执行,直到给定条件不为真
- 上述代码的作用是打印出斐波那契数列,既前两个数相加等于后一个数的数列
- 当判断语句
a < 10返回的结果为True的时候,会执行下述的语句。执行完print(a)后,对变量a和b重新进行赋值,将b和a + b的值重新赋值给a和b,这样就相当于让a始终等于前两个值的和 - 在这里,对 python 中的判断语句进行一下补充说明。在 python 中,任何非 0 的数字和非空的序列都为
True,其他都为False,我们可以用bool()函数求得对象的布尔值 - 我们可以用 while 语句来计算 1-100 的和
- 能计算一定范围内的总和,我们自然也能在这个基础上添加过滤条件,如计算奇数或偶数的和。这需要用到if语句
- 注意,while 语句当中的判断条件,一定要是能够变化的,如果判断条件一直为真,while 语句就会一直执行,进入死循环。如果在交互模式下进入了死循环,可以按住
ctrl + c来退出
If 语句
- If 语句同样是对给定的条件进行判断,如果条件为真,则执行后续语句。和 while 语句不同的是,if 不会一直循环执行
- 我们可以用 if 语句和 while 语句写一个猜大小的游戏,这个游戏比较长,在解释器中写并没有那么方便,我们打开 vscode,在 python 文件中进行编辑
- 这段代码的逻辑,是我们先通过
random模块中的randint()函数生成一个随机数,包含开始的 1 和结束的 100。再通过input()函数接收用户输入,由于input()函数返回的值默认是字符串类型,我们需要用int()函数将返回值转换成数字类型 - 注: 字符串和数字类型是无法进行比较的
- 有了输入的数字和随机数后,我们就需要添加判定条件。当 while 语句后的条件为 True 时,while 语句会一直执行后续的语句。在介绍 while 语句的部分,我们说过,如果判断条件不变,会进入死循环。所以,为了避免死循环,我们在最后猜对时,要用
break语句来跳出循环 - 最后我们需要不断接收用户输入,直到猜对为止,所以要再次加上将
input ()函数返回值赋值给input_num的语句 - 我们点击右上角的执行
- 在我们猜了很多次,一直到猜对时,程序才会停止运行
- 但是我们这个程序有很大的缺点,它没有猜测的限制,我们可以一直猜,直到猜对为止。所以我们要给一个限制条件,只能猜三次
- 这段代码看上去很正常,但它真的没有问题吗?
- 我们运行试试
- 可以发现,我们竟然能猜四次,这是为什么?
- 仔细看一下代码,我们能发现,变量
count从 3 到 0,while 语句的确是循环了三次没错。但是,我们在循环前,其实已经进行了一次输入,也就是说我们第一次猜的时候,并没有算在 count 里面 - 我们再次对代码进行一下修改
print("{}".format(变量))是对字符串进行格式化,能够让我们更方便地将变量的值填入到字符串中,之后我们会学习到有关于字符串格式化更为强大的功能- 再次运行,发现这个简单的猜数字游戏已经能正常运行了
For 语句
- For 语句的作用是对给出的序列进行迭代
- 我们可以用 for 语句迭代打印字符串中的字符和列表中的值
Range 函数
- Python 内置的 range 函数能快速地生成一个等差数列
range(5)等同于range(0, 5),range 函数和索引类似,从起始值到终止值是左闭右开的,并且可以给定步长。注:random模块中的randint ()函数是闭区间,不要混淆哦!- 我们可以将 for 语句和 range 函数结合起来,按照序列的索引进行迭代
- 我们可以将索引也打印出来,清楚地看清索引和值之间的对应关系
- 我们可以用这种索引遍历的方式,对序列一边遍历,一边修改,比如将一个数字列表中小于 10 的数字全都加 1
- 但是这种一边遍历,一边修改的方式,一定是在索引没有改变,也就是说序列的长度没有变化时才有用
- 当列表长度发生变化时,这种修改方式很容易出现问题
- 问题的根源在列表的长度发生了变化,但 for 语句一开始的遍历值,并没有随着列表的值被移除而减小,迭代已经混乱了
- 那如果我们不用索引,直接遍历,然后将符合条件的值移除呢?
- 这时我们发现,列表里最后一个值 8 明明小于 10,却没被删除,这是为什么呢?
- 我们通过 Python Tutor code visualizer 中的代码运行步骤图能看出,当遍历到第四个值时,整个列表由于不断删除,只剩下了四个值,作为此时第四个值的 8,由于前一个第四个值 7 已经被遍历过,所以根本没有进行遍历,也没有进行判断和删除
Break 和 Continue 语句
- Break 语句的作用是跳出最近的一层 for 或者 while 循环
- 下面这段代码的作用是打印 2 到 10中(不包括 10)的非素数数字,这里 break 语句只会跳出里面的那层 for 循环,外面的 for 循环仍然会继续
- Continue 语句的作用是跳过后续语句,进入下一次 for 或者 while 循环
- 我们可以用 continue 语句来完成上面这段代码的功能
- 由于 continue 语句只是跳过一次循环,所以会多对第二个 for 语句进行更多的循环次数,打印出这些数字的更多的因数
Else 语句
- Else 语句我们在上面其实已经用过了很多次,它的作用就是当循环或判断语句未在 break 语句下结束时继续执行后续的语句
- 我们尝试一下,用代码判断 2 到 10中的数字是否为素数
- 这段代码用语言概括,就是遍历 2 到 10 中的数字,并且让它将对 2 到它本身的数字进行整除,如果它能被其中的数字整除,就说明它不是素数,如果遍历完 2 到它本身,没有数字能被它整除,就说明它是素数
- Else 语句,其实就是在对 2 到判断的数字本身中的数字遍历后且未被 break 语句中断后执行的语句
- 另一个要注意的点就是 else 的对应层级,这段代码中,else 对应的是第二个 for 循环,不是上面的 if 语句
- If 语句中除了能用 else,还有 elif 语句,我们在 if 语句的介绍中已经用过,这里不再赘述
Pass 语句
- Pass 语句不执行任何动作,也不进行任何判断,当无需程序做任何操作时,可以用 pass 语句
Match 语句
- Match 语句接受一个表达式或值,然后与各个 case 子语句中的模式进行比较,基本格式如下:
- 我们定义了一个函数,接收一个名为 status 的参数,然后用 match 语句对 status 这个参数进行比较,如果 status 的值和某个 case 中的值匹配,则执行对应 case 中的语句,
case _代表除了已列出的 case 之外的其他所有情况,相当于 else 语句 - 函数定义时赋予了参数,那么在调用时也要传入参数,否则会报错
- 我们也可以用
|来在一个 case 语句中定义多种情况 - 当然,我们也可以用解包的方式比较多个值
- 这里大家要留个印象,后面我们会再次学习到类似的东西
格式化输出
- 我们已经学习过用
print()函数简单地输出语句,为了更好地将变量和语句一起打印出来,我们需要学习格式化输出 - 如果我们要想下面打印一个人的自我介绍,会很麻烦
- 有没有更方便的方法,把变量和要输出的字符串结合在一起呢?当然有!
- 我们使用
f-string方法,在字符串前面加上f,再把变量括上方括号{},就像这样 - 我们甚至可以在括号里使用索引
- 我们在遍历一个序列时,同样可以使用
f-string - 总而言之,
f-string地作用就是把变量(包括表达式或任何有返回值的)嵌入到要输出的字符串中 - 当然,有时我们会遇到更棘手的问题,当我们嵌入一个数字但只要它保留两位小数时,怎么办呢?字符串有索引,数字可没有
- 有些人会说将数字转换成字符串,再用索引取位数。这在某种程度上来说是可行的。而
f-string其实本来就有这个功能 :.3f的功能分解开来,:代表后面是要保留的位数,.3f表示小数点后保留三位,f代表的是浮点数类型,浮点数类型不指定小数点后的位数则最多保留六位小数- 除了位数,
f-string还支持对齐方式并用其他符号填充 - 我们对
f-string格式再次更新一下就是在:后一次是填充符、对齐方式、总宽度、小数点位数 - 除了
f-string之外,我们还能使用字符串的format方法来进行格式化字符串,当然,我还是更推荐大家使用f-string,两者之间在功能上并没有什么差异,而f-string用起来更简单便捷 format方法的占位和填充与f-string没有区别,唯一的区别就是传入变量的方式format()和f-string最大的区别是在传入多个变量时- 当我们需要对例如“A02”这种版本信息进行改动,比如下一版我们要得到“A03”这个值,我们就要用到格式化输出
old = "A03"
# 旧版本
new = old.split("A")[-1]
# 我们首先要做的是将字母和数字分隔开来,那就要用到字符串的split方法,该方法以分隔符将字符串分开,返回一个包含分割后字段的列表
# 这时候new的值是“03”,我们需要将它变成04,嫁入版本值始终是两位,我们就需要将字符串转成数字,并加一,且占两位
print(f"A{int(new) + 1:02d}")
# 这就是我们最后要的A04
读写文件
- 关于语句相关的基础部分,我们已经学完了,接下来,我们来学习略微进阶一些的文件读写操作
- 我们新建一个
tutorial.py和一个test.txt,在test.txt中随便写点什么 - 接下来,我们来读取
test.txt中的内容并进行输出 - 读写文件的核心就是
open()函数,我们将鼠标移到open上,查看一下它的说明文档 - 第一个参数
file指的自然是读取的文件目标路径 - 第二个参数
mode指的是读或写的模式,为了文件的安全,我们把mode设定成读,就可以防止文件出现不必要的改动r,读取,也是默认值w,清除文件的原本内容再写入x,创建文件,有同名文件则失败a,追加,和w不同的是,当文件有内容时,不会清除原本内容,而是在末尾写入b,二进制模式t,文本模式,默认。mode="r"和mode="rt"是一样的,文本模式返回的都是字符串+,打开用于读取和写入
- 第三个参数
buffering代表的是缓冲,通过数字来设置。0是关闭缓冲,1是按行进行缓冲,也可以通过其他数字来指定缓冲的区块大小 - 第四个参数
encoding代表文件编码或解码的格式,常用UTF-8。 - 第五个参数
errors是一个可选的字符串参数,用于指定如何处理编码和解码错误(不能在二进制模式下使用)- 如果存在编码错误,
'strict'会引发ValueError异常。 默认值None具有相同的效果 'ignore'忽略错误。请注意,忽略编码错误可能会导致数据丢失'replace'会将替换标记(例如'?')插入有错误数据的地方'surrogateescape'将把任何不正确的字节表示为 U+DC80 至 U+DCFF 范围内的下方替代码位。 当在写入数据时使用surrogateescape错误处理器时这些替代码位会被转回到相同的字节。 这适用于处理具有未知编码格式的文件'xmlcharrefreplace'仅在写入文件时才受到支持。 编码格式不支持的字符将被替换为相应的 XML 字符引用&#_nnn_;'backslashreplace'用Python的反向转义序列替换格式错误的数据'namereplace'(也只在编写时支持)用\N{...}转义序列替换不支持的字符
- 如果存在编码错误,
- 第六个参数
newline用来解析换行符,如果newline为None,则启用通用换行模式。输入中的行可以以'\n','\r'或'\r\n'结尾,如果是其他值,则文件中的行以指定字符结尾 - 第七个参数
closefd代表文件开关状态,默认为True,否则底层文件描述符将保持打开状态 - 第八个参数
opener代表调用自定义开启器 - 对
open()方法有了大致了解后,我们再来试一试除了读以外的其他操作 - 首先我们来试试将字符串写入进文件中
- 我们再最后加上了
f.close()来关闭文件,现在我们点开test.txt,可以发现内容已经变成我们写入的字符串 - 现在我们来试试追加
- 我们不光将
mode参数改成了a,还将一开始的语句改成了with open() as f,这样做最大的好处是在执行完语句后,文件会自动关闭 - 我们打开
test.txt,发现内容果然追加在了最后 - 注意,追加和光标位置无关,之和文件内容的末尾位置有关,空格和换行符会影响追加的位置
- 我们用
f.read()和f.write()方法进行了读取和写入,现在我们介绍一下文件对象的其他方法 f.readline()读取单行数据,以换行符为结尾- 我们也可以用
f.readlines()方法一次性读取多行,返回的是一个包含每一行内容的列表 f.tell()用来返回指针的当前位置- 注意,指针位置并不是代表第几个字符,它的计算是这样的
f.seek()来指定指针位置- 将光标移动到第二行开始,按行打印就会输出第二行的内容
- 以上是读取普通文件的方法,大部分是字符串,如果要对特殊的文件进行读写,我们需要用到其他的模块,例如
json,之后我们会在学习标准库时进行深入学习
错误和异常
- 我们在之前的学习中以及遇到过了一些报错信息,例如语法错误、括号未关闭、元组无法修改等
- 类似于下面这种在书写代码时出现的语法错误,是我们最常遇到的
- 当我们语法正确时,其他地方出现了错误,则会抛出各种异常
- 错误信息的最后一行通常会指出错误是什么类型的,并给出一定的提示信息
- 在经常遇到类似的异常后,我们就会知道如何去处理
- 但是,当我们要让程序对某些异常进行自动的处理,我们该怎么做呢?
- 我们写一个判断输入数字是奇数还是偶数的简单程序
- 我们输入正常的数字,程序会正常的返回奇数或偶数的结果,但是如果我们输入字符呢?
- 程序抛出了一个异常,值的异常
input()方法默认返回的就是字符串,为了对输入的数字进行计算,我们将字符串类型转换成了数字类型- 现在为了避免输入值是字符串,除了修改提示信息,我们还能怎么做呢?
- 答案是用
try-expect语句自动处理异常 try语句的区块中是我们要进行错误捕获的代码,except语句后跟着要捕获的异常以及捕获到异常之后要进行的操作- 现在,当我们运行程序,再次输入数字以外的值,程序不会报错,只会打印
except语句后的提示 except语句只能在语法正确的情况下捕获异常,无法捕获语法错误- 我们可以用多个
except语句捕获多个异常,但只有最先出现的那个异常会被处理 - 如果我们只想对多种异常进行单一的处理,我们可以用元组将多个异常组合起来,再用
except语句进行处理 except语句后也可以加上else子句,用来在没遇到指定异常后执行语句- 除了处理异常之外,我们还可以用
raise关键字来自己引发异常 - 如果在
except语句后有未处理或者我们自己引发的异常,那么它会将该异常报在try语句内的代码上 - 在
try-except语句中,我们可以用finally语句来定义无论如何都要执行的清理操作 finally语句不会忽略异常,而是在报出异常后也进行执行- 现在我们可以配合之前学的文件读写,将异常写入log文件
- 打开log文件发现异常已经写入,当然这里只是演示,写的比较简略
- 这些就是异常处理的基本
try-except-else-finally语句,之后我们会配合实例,学习具体的异常处理