文章目录

  • 第二章:变量和简单数据类型
    • 2.1 变量的命名
    • 2.2 字符串
      • 2.2.1 修改字符串大小写
      • 2.2.2 在字符串中使用变量
      • 2.2.3 制表符、换行符
      • 2.2.4 删除空白
      • 2.3 数
        • 2.3.1 整数
        • 2.3.2 浮点数
        • 2.3.3 数中的下划线
        • 2.3.4 常量
  • 第三章 列表
    • 3.1 列表
      • 3.1.1 访问列表中的元素
      • 3.1.2 列表中元素的使用
    • 3.2 修改、添加、删除列表元素
      • 3.2.1 修改列表
      • 3.2.2 添加元素
      • 3.2.3 删除元素
    • 3.3 组织列表
      • 3.3.1 sort() 对列表永久排序
      • 3.3.2 sorted() 对列表临时排序
      • 3.3.3 获取列表长度
  • 第四章 操作列表
    • 4.1 遍历列表
      • 4.1.1 在for循环中执行更多操作
      • 4.1.2 在for循环结束后的操作
    • 4.2 避免缩进错误
    • 4.3 创建数值列表
      • 4.3.1 使用函数 range()
      • 4.3.2 使用range()函数直接创建列表
      • 4.3.3 对数字列表进行简单的统计计算
      • 4.3.4 列表解析式
    • 4.4 列表的切片
      • 4.4.1 切片
      • 4.4.2 遍历切片
      • 4.4.3 复制列表
    • 4.5 元组
      • 4.5.1 定义元组
      • 4.5.2 元组的遍历
      • 4.5.3 修改元组变量
  • 第五章 if 语句
    • 5.1 一个简单的示例
    • 5.2 条件测试
      • 5.2.1 检查是否相等
      • 5.2.2 检查是否相等时忽略大小写
      • 5.2.3 检查是否不相等
      • 5.2.4 数值的比较
      • 5.2.5 检查多个条件
      • 5.2.6 检查特定值是否在列表中
      • 5.2.7 检查特定值是否不在列表中
      • 5.2.8 布尔表达式
    • 5.3 if 语句
      • 5.3.1 简单的if语句
      • 5.3.2 if-else语句
      • 5.3.3 if - elif - else结构
      • 5.3.4 使用多个elif 代码块
      • 5.3.5 省略else代码块
      • 5.3.6 测试多个条件
    • 5.4 使用 if 语句处理列表
      • 5.4.1 检查特殊元素
      • 5.4.2 确定列表不是空的
    • 5.5 设置 if 语句的格式
  • 第六章 字典
    • 6.1 一个简单的字典
    • 6.2 使用字典
      • 6.2.1 访问字典中的值
      • 6.2.2 添加键值对
      • 6.2.3 先创建一个空字典
      • 6.2.4 修改字典中的值
      • 6.2.5 删除键值对
      • 6.2.6 使用 get()来访问值
    • 6.3 遍历字典
      • 6.3.1 遍历键值对:
      • 6.3.2 遍历字典中的键
      • 6.3.3 按特定顺序遍历字典中的键
      • 6.3.4 遍历字典中的所有值
    • 6.4 嵌套
      • 6.4.1 字典列表
      • 6.4.2 在字典中存储列表
      • 6.4.3 在字典中存储字典
  • 第七章 用户输入和 while 循环
    • 7.1 函数 input()原理
      • 7.1.1 编写清晰的程序
      • 7.1 .2 使用input()函数获取数值输入
    • 7.2 while 循环简介
      • 7.2.1 使用 while 循环
      • 7.2.2 使用标志
      • 7.2.3 使用 break 退出循环
      • 7.2.4 在循环中使用continue
    • 7.3 使用 while 循环处理列表和字典
      • 7.3.1 在列表之间移动元素
      • 7.3.2 删除列表中特定值
  • 第八章 函数
    • 8.1 定义函数
      • 8.1.1 向函数传递信息
      • 8.1.2 实参和形参
    • 8.2 传递实参
      • 8.2.1 位置实参
      • 8.2.2 关键字实参
      • 8.2.3 默认值
    • 8.3 返回值
      • 8.3.1 返回简单值
      • 8.3.2 让实参可选
      • 8.3.3 返回字典
    • 8.4 传递列表
    • 8.5 传递任意数量的实参
      • 8.5.1 结合位置实参和任意数量实参
      • 8.5.2 使用任意数量的关键字实参
    • 8.6 将函数存储在模块中
      • 8.6.1 导入整个模块
      • 8.6.2 导入特定的函数
      • 8.6.3 使用 as 给函数指定别名
      • 8.6.4 使用 as 给模块指定别名
      • 8.6.5 导入模块中的所有函数
  • 第九章 类
    • 9.1 创建和使用类
      • 9.1.1 创建 Dog 类
      • 9.1.2 根据类创建实例
    • 9.2 使用类和实例
      • 9.2.1 Car 类
      • 9.2.2 给属性指定默认值
      • 9.2.3 修改属性的值
    • 9.3 继承
      • 9.3.1 子类的方法 __ init __()
      • 9.3.2 给子类定义属性和方法
      • 9.3.3 重写父类的方法
      • 9.3.4 将实例用作属性
    • 9.4 导入类
      • 9.4.1 导入单个类
      • 9.4.2 在一个模块中存储多个类
      • 9.4.3 从一个模块中导入多个类
      • 9.4.4 导入整个模块
      • 9.4.5 导入模块中的所有类
      • 9.4.6 在一个模块中导入另一个模块
      • 9.4.7 使用别名
    • 9.5 python 标准库
  • 第十章 文件和异常
    • 10.1 从文件中读取数据
      • 10.1.1 读取整个文件
      • 10.1.2 文件路径
      • 10.1.3 逐行读取
      • 10.1.4 创建一个包含文件各行内容的列表
    • 10.2 写入文件
      • 10.2.1 写入空文件
      • 10.2.2 写入多行文件
      • 10.2.3 附加到文件
    • 10.3 异常
      • 10.3.1 处理 ZeroDivisionError 异常
      • 10.3.2 使用 try - except 模块
      • 10.3.3 使用异常避免崩溃
      • 10.3.4 else 代码块
      • 10.3.5 处理 FileNotFoundError 异常
      • 10.3.6 静默失败
    • 10.4 存储数据
      • 10.4.1 使用 json.dump() 和 json.load()
  • 第 11 章 测试代码
    • 11.1 测试函数
      • 11.1.1 单元测试和测试用例
      • 11.1.2 可通过的测试

第二章:变量和简单数据类型

2.1 变量的命名

  • 变量名只能包含数字、字母、下划线
  • 变量名可以以字母或下划线开头,但不能以数字开头
  • 变量名中不能有空格
  • 变量名不能和python中的关键词一致
  • 变量名应简单、具有描述性
name = "xiao hong"            # name 就是一个变量
name_student = "xiao hong"    # name_student 也是一个变量2name = "xiao hong"           # 是错误的写法,数字不能放在变量的开头

2.2 字符串

在Python中,字符串就是一串用引号括起来的字符串,注意单引号、双引号都可以

"This is string"       # 双引号、单引号都可以表示一个字符串
'This is string'

2.2.1 修改字符串大小写

操作符 解释
title() 将单词首字母变为大写
upper() 将单词变为大写
lower() 将单词变为小写
name = "xiao hong"print(name.title())
print(name.upper())
print(name.lower())输出:
Xiao Hong
XIAO HONG
xiao hong

2.2.2 在字符串中使用变量

有时,我们需要将变量赋值给字符串,python中具体操作是:str = f"{变量名}"str = “{}”.format(变量名)

举例看看就懂:

name_1 = "xiao hong"                 # name_1 是变量
name_2 = "li gang"                   # name_2 是变量
student = f"{name_1} and {name_2} are students"      # student 中的字符串包含上面两个变量的值
print(student) 输出:
xiao hong and li gang are students

或者:

student = "{} and {} are students".format(name_1, name_2)
print(student) 输出:
xiao hong and li gang are students

2.2.3 制表符、换行符

制表符:\t

print("\tpython")      # 输出字符串会缩进输出:python

换行符:\n

print("\npython")       # 输出字符串会在下一行输出输出:python

制表符、换行符一起使用:

print("\npython")       # 输出字符串会在下一行缩进输出输出:python

2.2.4 删除空白

对于程序来说,"python"和"python "是不一样的,因为后者中包含空格,但有些场景我们认为他们是一致的,这时我们就应该将他们做一些处理,删除其中的空格!

操作符 解释
strip() 删除左右两边的空格
rstrip() 删除右边的空格
lstrip() 删除左边的空格

举例看看:

language = " python "          # 左右都有空格
print(language.strip())        # 删除左右空格
print(language.rstrip())       # 删除右边空格
print(language.lstrip())       # 删除左边空格输出:
pythonpython
python

2.3 数

2.3.1 整数

python中整数的操作:(+)加、(-)减、(*)乘、(/)除、(//)整除、(**)乘方、(%)取余

具体举例看看就懂:

print(1 + 2)         # 加
print(2 - 1)         # 减
print(2 * 3)         # 乘
print(3 / 2)         # 除
print(3 // 2)        # 整除:3除以2是1.5,再对1.5取整就是1
print(3 ** 2)        # 乘方: 这里是3的2次方。同理(3 ** 4)表示:3的4次方,结果是81
print(3 % 2)         # 取余:3除以2,余数是1输出:
3
1
6
1.5
1
9
1

注意:空格不影响上面的计算表达式

2.3.2 浮点数

小数点的数称为浮点数,浮点数的操作和上面一致!注意:任意两个数相除都是浮点数,即是这两个数可以整除,举例看看:

print(4 / 2)       # 可以整除,结果也是浮点数!输出:
2.0

2.3.3 数中的下划线

当数字很大时,可以使用下划线,让数字显示的更加清晰明了:

number = 14_000_000_000     # 140亿,这样表示很清晰明了,其中下划线不影响数字的大小、存储等!
print(number)               # 打印时,是不会显示下划线的输出:
14000000000注意:
1_000 和 10_00 大小是一样的

2.3.4 常量

常量即在程序运行中大小保持不变。一般使用全部大写来表示常量

NUMBER = 100        # 一般用这种全部大写的来表示常量!

第三章 列表

3.1 列表

列表是由一系列按特定顺序排列的元素组成!在python中用 [] 表示列表,其中各元素由逗号隔开

举例看看:

name = ["xiao hong", "li gang"]  # name 是一个列表,包含两个元素,元素之间由逗号隔开
print(name)输出:
['xiao hong', 'li gang']

3.1.1 访问列表中的元素

列表中的元素是有序的,我们可以根据元素的位置(索引)找到具体的元素!如:列表名[索引]

注意:python中的索引从0开始,即0表示第一个元素

举例看看就懂:

name = ["xiao hong", "li gang"]   # 列表
print(name[0])                    # 返回列表第一个元素,索引从0开始
print(name[1])                    # 返回列表第二个元素输出:
xiao hong
li gang

如何获取最后的元素呢?

name = ["xiao hong", "li gang"]
print(name[-1])                # -1 表示访问列表中最后一个元素输出:
li gang

同理,倒数第二的元素用-2表示,以此类推!

3.1.2 列表中元素的使用

我们对于获取的元素可以进一步操作,如:

name = ["xiao hong", "li gang"]
print(name[0].title())          # 将第一个元素变为首字母大写的字符串输出:
Xiao Hong
name = ["xiao hong", "li gang"]             # 列表
result = f"{name[0]} is a good student"     # 将列表元素放入字符串中!
print(result)输出:
xiao hong is a good student

3.2 修改、添加、删除列表元素

我们一般会对创建的列表进行改动,来符合我们想要的列表,包括对列表元素的修改、添加、删除等操作!

3.2.1 修改列表

修改列表中某元素的操作:列表名[索引] = 新值

举例看看就懂:

name = ["xiao hong", "li gang"]  # 原始列表
print(name)name[0] = "da zhuang"            # 修改第一个元素
print(name)输出:
['xiao hong', 'li gang']
['da zhuang', 'li gang']

我们不仅可以修改第一个元素,同理可以修改任意位置的元素!

3.2.2 添加元素

有时我们需要在列表中添加新的元素,具体操作如下:

  • 列表末尾添加元素:列表名.append(元素)
name = ["xiao hong", "li gang"]  # 原始列表
print(name)name.append("da zhuang")         # 添加元素
print(name)输出:
['xiao hong', 'li gang']
['xiao hong', 'li gang', 'da zhuang']
  • 在列表中插入元素:列表名.insert(插入位置,插入元素)
name = ["xiao hong", "li gang"]   # 原始列表
print(name)name.insert(1, "da zhaung")       # 在第一个位置插入“da zhuang”
print(name)输出:
['xiao hong', 'li gang']
['xiao hong', 'da zhaung', 'li gang']

3.2.3 删除元素

对于不同场景,我们删除元素的方法是不一样的,具体分为:

  • 已知要删除元素的索引del 列表名[索引]
name = ["xiao hong", "li gang", "da zhuang"]  # 原始列表
print(name) del name[2]                # 删除第三个元素
print(name)输出:
['xiao hong', 'li gang', 'da zhuang']
['xiao hong', 'li gang']
  • 已知要删除元素的值列表名.remove(元素)
name = ["xiao hong", "li gang", "da zhuang"]   # 原始列表
print(name)name.remove("da zhuang")    # 删除第三个元素
print(name)输出:
['xiao hong', 'li gang', 'da zhuang']
['xiao hong', 'li gang']

若列表中出现多个相同元素,remove操作只能删除第一个指定的元素!

以上操作,删除元素后,被删除的元素就找不到了,无法再去访问了,而有时我们需要刚刚删除的元素,这时我们可以弹出要删除的元素

  • 弹出要删除的元素列表名.pop(索引)
name = ["xiao hong", "li gang", "da zhuang"]   # 原始列表
print(name)item = name.pop()    # 默认弹出最后一个元素,我们也可以指定索引来弹出具体位置的元素
print(name)
print(item)输出:
['xiao hong', 'li gang', 'da zhuang']
['xiao hong', 'li gang']
li gang

通过上面的操作发现,popdel 的作用基本一致,但是del删除元素后就不能再访问该元素了,而pop可以再访问这个元素!

3.3 组织列表

当我们创建好一个列表时!其中元素的顺序可能不是我们想要的,我们可能想升序或降序元素值,那么具体如何操作呢!

3.3.1 sort() 对列表永久排序

我们可以使用sort()方法对列表进行排序:列表名.sort()

  • 列表名.sort()序(默认升序)
  • 列表名.sort(reverse=True)

具体举例看看就懂:

age = [23, 18, 19, 20, 22, 18, 20]  # 原始列表
print(age)          age.sort()        # 排序,默认升序
print(age)
age.sort(reverse=True)   # 降序
print(age)输出:
[23, 18, 19, 20, 22, 18, 20]
[18, 18, 19, 20, 20, 22, 23]
[23, 22, 20, 20, 19, 18, 18]

3.3.2 sorted() 对列表临时排序

如果我们在排序后,还要保留以前的列表,就应该使用sorted()方法:sorted(列表名)

  • sorted(列表名)序(默认升序)
  • sorted(列表名, reverse=True)
age = [23, 18, 19, 20, 22, 18, 20]  # 原始列表
print(age)
print(sorted(age))         # 升序后的临时列表
print(sorted(age, reverse=True))    # 降序后的临时列表
print(age)                 # 原始列表,没有改变输出:
[23, 18, 19, 20, 22, 18, 20]
[18, 18, 19, 20, 20, 22, 23]
[23, 22, 20, 20, 19, 18, 18]
[23, 18, 19, 20, 22, 18, 20]

3.3.3 获取列表长度

一般使用函数 len() 获取列表长度,具体看看:

age = [23, 18, 19, 20, 22, 18, 20]
print(len(age)) 输出:
7

第四章 操作列表

第三章,我们学习了如何创建列表、以及对列表中元素的简单操作,如果我们要对列表中每个元素进行某个操作,那么就需要遍历列表,具体看看:

4.1 遍历列表

我们可以使用for循环来不断遍历列表中的元素,举例看看:

names = ["xiao hong", "li gang", "da zhuang"]for i in names:       # for循环会不断遍历列表中的元素,并赋值给变量iprint(i)输出:
xiao hong
li gang
da zhuang

上述代码中的 i 是我们指定的临时变量,也可以写成其他任意值,一般应该具有一定的指代意义,所以最合适的代码如下:

names = ["xiao hong", "li gang", "da zhuang"]for name in names:print(name)输出:
xiao hong
li gang
da zhuang

4.1.1 在for循环中执行更多操作

我们可以在打印同学名字时,给他们加上一定的信息,如每位同学都是好学生,我们只需要在循环中不断的输出每位同学都是好学校即可!

names = ["xiao hong", "li gang", "da zhuang"]    # 列表for name in names:                        # 循环print(f"{name} is a good student")    # 缩进,表示在for的循环体内输出:
xiao hong is a good student
li gang is a good student
da zhuang is a good student

4.1.2 在for循环结束后的操作

我们还可以在for循环结束后,做一些操作

names = ["xiao hong", "li gang", "da zhuang"]    # 列表for name in names:                        # 循环print(f"{name} is a good student")    # 缩进,表示在for的循环体内
print("everyone is a good student")       # 在循环体外!输出:
xiao hong is a good student
li gang is a good student
da zhuang is a good student
everyone is a good student

4.2 避免缩进错误

python中主要以缩进来划分模块,如上面例子,在for循环语句之后,缩进的表示循环体,没有缩进的表示不是for循环体的!

注意:for循环后面要加冒号(:),表示下面的语句是循环体!

4.3 创建数值列表

上面我们创建了字符串列表,但很多场景下,我们需要一组元素为数字的列表,像班级学生年龄、一年的温度等等,这些都可以用列表来存储!

4.3.1 使用函数 range()

对于连续的一段数,我们可以用 range()函数 来生成,如:

for value in range(1, 3):   print(value)输出:
1
2

range()函数 括号内的数是 左闭右开 的,即从括号左边数开始,直到右边界,但不包含右边界!我们再看个例子:

for value in range(3):print(value)输出:
0
1
2

上面的数,从0开始到2,不包括3!

4.3.2 使用range()函数直接创建列表

我们可以将range()函数创建的数直接传入list()函数中,如下:

numbers = list(range(1, 6))    # 将range生成的一系列数直接传入list中,生成列表
print(numbers)输出:
[1, 2, 3, 4, 5]

当然我们也可以先申请一个空列表,再利用for循环不断的添加元素,具体如下:

numbers = []              # 先申请一个空列表for value in range(1, 6):      # 循环numbers.append(value)      # 添加元素到列表中,append函数上面我们提到过!print(numbers)输出:
[1, 2, 3, 4, 5]

当然我们再添加元素时,也可以对元素进行一些操作:

numbers = []              # 先申请一个空列表for value in range(1, 6):      # 循环numbers.append(value ** 2)      # 将元素平方,再添加到列表中!print(numbers)输出:
[1, 4, 9, 16, 25]

4.3.3 对数字列表进行简单的统计计算

操作 解释
min() 返回最小值
max() 返回最大值
sum() 返回列表元素之和

举例看看:

numbers = [1, 2, 3, 4, 5]   # 列表print(min(numbers))     # 打印最小值
print(max(numbers))     # 打印最大值
print(sum(numbers))     # 打印列表元素之和输出:
1
5
15

4.3.4 列表解析式

上述生成期望列表,一般需要多行代码,采用列表解析式我们可以一行代码搞定,具体为:列表名 = [表达式 循环体 条件] ,具体我们举例看看就懂。

假如我们想要1 - 10之间的偶数

numbers = [value for value in range(1, 11) if value % 2 == 0]
print(numbers)输出:
[2, 4, 6, 8, 10]

上述代码中:

  • value就是表达式,我们也可以对其再进一步操作,如value**2 ,就是再平方
  • for value in range(1, 11)就是循环体,不断的迭代输出数
  • if value % 2 == 0就是过滤条件,可以不要,即不过滤数据

4.4 列表的切片

上面我们提到了如何用for循环对列表所有元素进行操作,但有时只需要对列表中的部分进行操作,这时就可以用列表的切片操作!

4.4.1 切片

我将通过举例,来解释切片的具体操作:列表名[左索引 :右索引]

注意:

  • 和range()函数一样,左闭右开,即右索引对应的元素取不上!
  • 索引从0开始,即第一个位置元素的索引是0

下面五个例子包括了所有的切片操作:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]      # 原始列表print(numbers[1: 5])      # 取索引1-5的元素
print(numbers[:5])        # 从头开始,一直到索引为5的元素
print(numbers[5:])        # 从索引为5的元素开始,一直到结束
print(numbers[:])         # 从头到尾,即取所有元素!
print(numbers[1:10:2])    # 取索引1-10的元素,步长为2来取数输出:
[2, 3, 4, 5]
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[2, 4, 6, 8, 10]

上面我们还提到过 负号(-) 的使用,表示倒数,如:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]     # 原始列表print(numbers[:-2])         # 从头开始,到倒数第2个元素结束输出:
[1, 2, 3, 4, 5, 6, 7, 8]

4.4.2 遍历切片

上面我们对列表所有元素进行了遍历,当然可以对切片的列表进行遍历,我们举例看看:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]   # 原始列表for value in numbers[5:]:         # 循环遍历切片后的列表print(value)                  # 不断打印出来输出:
6
7
8
9
10

4.4.3 复制列表

列表的复制有两种方式:

  1. 我们复制原始列表中的元素,到新列表中
  2. 我们直接将新的列表名,指向原始的列表名

上述两种方式有什么不同呢?我们举例看看就懂:

  • 方式一:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]     # 原始列表
numbers_copy = numbers[:]               # 复制原始列表中的元素到新列表print(numbers)
print(numbers_copy)输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

我们对两个列表再进行操作看看:

numbers.append(100)           # 原始列表添加元素100print(numbers)
print(numbers_copy)输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

通过方式一,原始列表添加元素后,新列表不变,说明原始列表和新列表是两个列表,即深拷贝

  • 方式二:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]   # 原始列表
numbers_copy = numbers              # 指定新列表名,指向原始列表print(numbers)
print(numbers_copy)输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.append(100)      # 原始列表添加元素100print(numbers)
print(numbers_copy)输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100]

通过方式二,原始列表添加元素后,新列表也添了元素,说明原始列表和新列表其实是一个列表!,即浅拷贝

4.5 元组

列表适用于在程序运行中,其元素不断发生改变的场景,但有时我们也需要创建一系列值不变的列表,而元素不可变的列表就叫元组

4.5.1 定义元组

元组和列表很像,元组是用 ()圆括号 定义的!我们可以向列表中元素的访问一样,去访问元组中的元素!

我们举例看看就懂:

dimensions = (100, 200)    # 元组
print(dimensions[0])       # 打印第一个元素输出:
100
# 元素的值是不能改变!改变的话,就会报错!dimensions = (100, 200)  # 元组
dimensions[0] = 300      # 改变第一个元素的值输出:
TypeError: 'tuple' object does not support item assignment

4.5.2 元组的遍历

元组的遍历和列表的遍历一样,我们举例看看:

dimensions = (100, 200)      # 元组for value in dimensions:     # 循环,遍历print(value)             # 打印输出:
100
200

4.5.3 修改元组变量

虽然元组中元素是不能修改的,但是元组变量是可以修改,我们举例看看就懂:

dimensions = (100, 200)     # 元组
print(dimensions)dimensions = (300, 400)     # 给元组变量重新赋值新的元组
print(dimensions)输出:
(100, 200)
(300, 400)

第五章 if 语句

前面我们学会列表、元组的创建,以及其遍历方式,但有时我们在遍历时,只需要其中一部分数据,如一组数中的偶数;这时,我们就应该不断对列表中元素进行判断!

5.1 一个简单的示例

numbers = [1, 2, 3, 4, 5]    # 原始列表for value in numbers:         # 循环if value % 2 == 0:        # 当除以2余数为0时,即偶数时,打印print(value)输出:
2
4

5.2 条件测试

if 语句的核心就是一个值为 True 或 False 的表达式,当为True时,继续往下走,否则跳出!

5.2.1 检查是否相等

一般用 == 来检查左右两边是否相等

numbers = [1, 2, 3, 4, 5]for value in numbers:if value == 2:        # 等于 2,打印print(value)

5.2.2 检查是否相等时忽略大小写

对于字符串检查相等时,“A” 和 “a”是不一样,如果我们在判断时,想忽略大小写的影响,我们可以用 lower()函数 ,对元素统一变为小写后比较!

names = ["Xiao Hong", "Li Gang", "Da Zhuang"]for name in names:if name.lower() == "li gang":   # 若元素统一小写后print(name)输出:
Li Gang

5.2.3 检查是否不相等

一般用 != 来检查左右两边是否不相等

numbers = [1, 2, 3, 4, 5]for value in numbers:if value != 2:print(value)输出:
1
3
4
5

5.2.4 数值的比较

有一系列的比较数值大小的符号,如: >、<、>=、<=、==,和上面的同理!

5.2.5 检查多个条件

有时我们需要同时满足好几个条件,才能得到我们想要的数据,这时可以用 and 和 or来连接这些条件!

  1. 使用 and 连接多个条件:
numbers = [1, 2, 3, 4, 5]for value in numbers:if value > 2 and value < 5:   # 同时满足这两个条件的, 就打印出来print(value)
输出:
3
4
  1. 使用 or 连接多个条件:
numbers = [1, 2, 3, 4, 5]for value in numbers:if value < 2 or value > 4:    # 满足任意一个条件的,就打印出来print(value)
  1. 使用圆括号,调整优先级:
numbers = [1, 2, 3, 4, 5]for value in numbers:if (value < 2 or value > 3) and value % 2 == 0:  # 满足圆括号内的和括号外的所有条件,就打印print(value)

5.2.6 检查特定值是否在列表中

我们用 in 来检查元素是否在列表中,举例看看:

numbers = [1, 2, 3, 4, 5]print(2 in numbers)输出:
True

5.2.7 检查特定值是否不在列表中

我们用 not in 来检查元素是否不在列表中,举例看看:

numbers = [1, 2, 3, 4, 5]print(8 not in numbers)输出:
True

5.2.8 布尔表达式

布尔表达式和条件测试表达式一样,只是布尔表达式结果要么是True,要么是False

game_start = True

5.3 if 语句

前面举例中,已经可以看出if语句的写法,其中最简单的为:

5.3.1 简单的if语句

if 条件表达式:           # 如果条件测试满足,则执行下面缩进的代码do something

例如:

age = 100
if age > 80:               # 满足条件,才执行下面缩进的语句!print("This is a man who lived a long life")输出:
This is a man who lived a long life

5.3.2 if-else语句

对于 if-else 语句,一般在条件满足时,执行 if 语句后面的操作;条件不满足时,执行else后的操作。

if 条件表达式:     某些操作
else:另外一些操作

例如:

age = 50
if age > 80:print("This is a man who lived a long life")else:print("…………………………")输出:
…………………………

5.3.3 if - elif - else结构

我们一般会检查超过两个情形的条件,这时就需要使用 if - elif - else结构 ,python会依次检查每个条件测试语句,测试通过,就会执行其后面的语句,并跳过其他的测试!

age = 12if age < 4:                # 年龄 < 4岁, 门票免费print("Your admission cost is 0 yuan")
elif age < 18:             # 4 <= 年龄 < 18,门票50元 print("Your admission cost is 50 yuan")
else:                      # 年龄 >= 18,门票100元print("Your admission cost is 100 yuan")输出:
Your admission cost is 50 yuan

上面的例子中,先检查 if 语句中的表达式是否满足,发现不满足;继续看elif中的语句是否满足,发现满足,就执行其后面的操作(打印);由于elif语句满足了,就不再往下看了,即不会再执行else中的操作。

5.3.4 使用多个elif 代码块

我们可以根据需要,使用多个elif来划分我们的情况,举例如下:

age = 50if age < 4:print("Your admission cost is 0 yuan")
elif age < 15:print("Your admission cost is 20 yuan")
elif age < 40:print("Your admission cost is 50 yuan")
else:print("Your admission cost is 60 yuan")输出:
Your admission cost is 60 yuan

5.3.5 省略else代码块

if-else结构中,else并不是必须存在的,我们也可以将其忽略的,例如:

names = ["Xiao Hong", "Li Gang", "Da Zhuang"]for name in names:if name.lower() == "li gang":      # 满足条件,则执行下面操作(打印),对于不满足条件的,我们不做处理!print(name)输出:
Li Gang

5.3.6 测试多个条件

if - elif - else结构,仅仅适用于测试一个条件是否满足,若满足条件,python会跳过剩下的测试。但有时我们需要测试多个条件,这时怎么办呢?

我们可以使用多个 if 语句来做,具体我们举例看看:

information = ["order", "noodles", "rice"]if "order" in information:            # 这三个测试条件都会进行检查print("The customer has placed an order")
if "noodles" in information:print("customers eat noodles!")
if "rice" in information:print("customers eat rice!")输出:
The customer has placed an order
customers eat noodles!
customers eat rice!

总结:

  • 若只想执行一个代码块,就使用if - elif - else结构
  • 若要执行多个代码块,就使用多个if语句

5.4 使用 if 语句处理列表

可以对列表中的元素使用 if 语句,对特定值做动态变化,有助于列表的管理等等!

5.4.1 检查特殊元素

age = [12, 10, 13, 1200, 14]    # 初中某班学习年龄的列表数据for value in age:          # 循环遍历if  10 < value < 20:        # 若在10-20岁之间,正常print("True")else:                       # 范围之外的,不正常print("False")输出:
True
True
True
False
True

5.4.2 确定列表不是空的

age = [12, 10, 13, 14]      # 列表if age:                 # 若列表存在, 则遍历打印for value in age:print(value)
else:                   # 若列表不存在,则打印 “数据不存在”print("The data doesn't exist!")输出:
12
10
13
14

5.5 设置 if 语句的格式

在编程习惯,我们一般会在一些地方加空格,来使得代码看起来更加明朗,例如:

if age < 4:    #这个要比下面的好!
if age<4:

第六章 字典

和列表不同,python中的字典可以表示的含义更加的广泛!例如我们可以创建一个表示人的字典,并可以在其中存储人的姓名、年龄、职业等等信息!

字典是以键值对存储的,例如 字典名 = {键:值,键:值,等等}

6.1 一个简单的字典

假如我们要存储一个人的姓名和年龄,我们试着用字典来表示:

# 字典 information 中存储了姓名和年龄的信息!
information = {"name": "da zhuang", "age": 18}print(information["name"])
print(information["age"])输出:
da zhuang
18

6.2 使用字典

在python中,字典是一系列 键值对组成 的。每个键都有一个值对应,我们可以使用键来访问对应的值。与键对应的 值可以使数、字符串、列表、字典 都可以!

字典用 {} 来表示,键和值用冒号分隔,键值对之间用逗号隔开!

6.2.1 访问字典中的值

如果想要获取某个键所对应的值,我们可以用: 字典名[键名]

information = {"name": "da zhuang", "age": 18}print(information["name"])     # 获取键name对应的值
print(information["age"])      # 获取键age对应的值输出:
da zhuang
18

6.2.2 添加键值对

字典是动态结构,对于建好的字典,我们可以继续往里面添加键值对,方法为: 字典名[新的键名] = 新的值 , 举例看看就懂:

information = {"name": "da zhuang", "age": 18}
print(information)information['height'] = 165
print(information)输出:
{'name': 'da zhuang', 'age': 18}
{'name': 'da zhuang', 'age': 18, 'height': 165}

6.2.3 先创建一个空字典

很多时候,我们都会先创建一个空的字典,再往里面添加键值对,来达到我们最终要的字典

information = {}                      # 创建一个空字典
information["name"] = "da zhuang"     # 添加键值对
information["age"] = 18               # 添加键值对print(information)输出:
{'name': 'da zhuang', 'age': 18}

6.2.4 修改字典中的值

对于建立好的字典,我们要修改某个键对应的值时,只需要重新赋值即可:字典名[键] = 新值

information = {'name': 'da zhuang', 'age': 18}
information["age"] = 20      # 我们对键age的值,进行修改print(information)输出:
{'name': 'da zhuang', 'age': 20}

6.2.5 删除键值对

对于不要的键值对,我们直接用 del 来删除:del 字典名[键]

information = {'name': 'da zhuang', 'age': 18}    # 原始字典
del information["age"]       # 删除键值对print(information)输出:
{'name': 'da zhuang'}

删除后的键值对,永远消失,不会再出现的!

6.2.6 使用 get()来访问值

上面我们提到了,可以使用字典中的键来访问其对应的值,若字典中没有这个键,就会报错,我们举例看看:

information = {'name': 'da zhuang', 'age': 18}print(information["color"])     # 字典中没有键color,就会报错!输出:
Traceback (most recent call last):File "C:/Users/Administrator/PycharmProjects/LeetCode/venv/1.py", line 3, in <module>print(information["color"])
KeyError: 'color'

为了防止报错,我们使用 get()函数 来访问键对应的值:值 = 字典 . get(键,默认值) ! 若字典中的键存在,直接返回其对应的值。若没有没有该键,则直接返回默认值!

information = {'name': 'da zhuang', 'age': 18}    # 字典age_value = information.get("age")       # 键“age”存在,直接返回其值
color_value = information.get("color", "No Value!")  # 键“color”不存在,返回默认值(自己定义),不会报错!!!
print(age_value)
print(color_value)输出:
18
No Value!

若我们不知道字典中某个键是否存在,就应该用get()函数!
get(键,默认值):若其中默认值没有定义,并且该键不存在,python会默认返回None!

6.3 遍历字典

字典中存在的键值对可能会很多,我们有时需要对其进行遍历,而字典的遍历方式有多种:键的遍历、值的遍历、键值对的遍历!

6.3.1 遍历键值对:

information = {'name': 'da zhuang', 'age': 18}   # 字典for key, value in information.items():      # 遍历键值对print("key: ",key)print("value: ", value)输出:
key:  name
value:  da zhuang
key:  age
value:  18

6.3.2 遍历字典中的键

仅仅访问字典中所以的键: 字典名 . keys()

information = {"1":"aa", "2":"dhe"}   # 字典print(information.keys())    # 返回所有的键输出:
dict_keys(['1', '2'])
information = {'name': 'da zhuang', 'age': 18}for key in information.keys():print("key: ",key)输出:
key:  name
key:  age

6.3.3 按特定顺序遍历字典中的键

可以使用sorted()函数

information = {'name': 'da zhuang', 'age': 18}for key in sorted(information.keys()):    # 对键排序(升序)print("key: ",key)输出:
key:  age
key:  name
information = {'name': 'da zhuang', 'age': 18}for key in sorted(information.keys(), reverse=True):    # 对键排序(降序)print("key: ",key)输出:
key:  name
key:  age

6.3.4 遍历字典中的所有值

仅仅访问字典中的所有值:字典名 . values()

information = {'name': 'da zhuang', 'age': 18}print(information.values())输出:
dict_values(['da zhuang', 18])
information = {'name': 'da zhuang', 'age': 18}for v in information.values():print("value: ", v)输出:
value:  da zhuang
value:  18

6.4 嵌套

为了表示更多的信息,有时我们需要将字典存储在列表中、将列表作为值存储到字典中,这种方式就叫做 嵌套

6.4.1 字典列表

将字典存储到列表中!

student_1 = {'name': 'da zhuang', 'age': 18}      # 学生1的信息
student_2 = {'name': 'li ming', 'age': 19}        # 学生2的信息
student_3 = {'name': 'xiao hong', 'age': 18}      # 学生3的信息student = [student_1, student_2, student_3]       # 将学生的信息放一起
print(student)输出:
[{'name': 'da zhuang', 'age': 18}, {'name': 'li ming', 'age': 19}, {'name': 'xiao hong', 'age': 18}]

6.4.2 在字典中存储列表

可以将列表作为值,存储到字典中

student = {'name': ["da zhuang", 'li ming', 'xiao hong'], 'age': [18, 19, 18]} print(student)                # 整体字典
print(student["name"])        # 键name对应的值输出:
{'name': ['da zhuang', 'li ming', 'xiao hong'], 'age': [18, 19, 18]}
['da zhuang', 'li ming', 'xiao hong']

6.4.3 在字典中存储字典

可以将字典作为值,存储到另一个字典中

li_ming = {'name': "da zhuang", 'age': 18}     # 字典
xiao_hong = {'name': "da lao", 'age': 20}      # 字典Class = {"user1": li_ming, "user2": xiao_hong}    # 字典嵌套字典
print(li_ming)
print(xiao_hong)
print(Class)输出:
{'name': 'da zhuang', 'age': 18}
{'name': 'da lao', 'age': 20}
{'user1': {'name': 'da zhuang', 'age': 18}, 'user2': {'name': 'da lao', 'age': 20}}

第七章 用户输入和 while 循环

  • 很多时候,我们需要用户自己输入一些信息,来处理具体问题!
  • 使用while循环,可以让程序一直执行下去,知道指定的条件不满足为止!

7.1 函数 input()原理

函数input()会暂停程序,等待用户输入,获取用户的输入后,会赋值给指定的变量,然后执行后面的程序!

input_value = input()print("information: ", input_value)输出:
liming           # liming 是我们输入的信息
information:  liming

通过上面的例子,我们将输入的信息赋值给变量 input_value ,然后打印这个变量!

7.1.1 编写清晰的程序

我们可以在input()函数中加上,用户输入信息的提示符。如:

input_value = input("please enter your name:")  # 括号中是提示信息,让用户输入自己名字, input_value 变量为用户输入信息,不会有提示信息的!print("hello! ", input_value)输出:
please enter your name:liming     # liming 是我们输入的
hello!  liming

7.1 .2 使用input()函数获取数值输入

对于 input()函数 ,python会将用户的 输入 解读为 字符串 , 我们可以用 int()函数 将字符串转换为数值,

age = int(input("please enter your age:"))  # int()将字符串15,变为整型15if age >= 18:print("成年人")
else:print("未成年人")输出:
please enter your age:15            # 15是我们输入的
未成年人

7.2 while 循环简介

前面我们提到了for循环,其会遍历集合中的所有元素,而while循环则不断运行,直到指定的条件不满足为止!

7.2.1 使用 while 循环

我们用while循环实现一个简单的数数问题:

count = 1      # 定义变量while count <= 5:    # 若count <= 5,就一直执行下面的程序print(count)     # 打印count值count += 1       # count 加一输出:
1
2
3
4
5

上面程序,一旦count大于5,不满足循环条件,就不会再执行的!

7.2.2 使用标志

while循环在满足条件时,会一直执行,若需要满足多个条件时,只用一条while检查所有条件会很复杂。

我们可以使用一个变量(标志),来统一所有条件是否都满足,若标志为True,则循环执行,否则跳出!

action = True     # 作为标志while action:     # 为True,就一直执行print("action something!")

7.2.3 使用 break 退出循环

我们可以使用 break函数停止while循环,不论循环条件是否满足!

count = 12while count >= 10:         # 满足条件,循环if count < 15:         # 满足条件,执行,count自身加一print("action something!")count += 1else:                  # count 大于等于15,就跳出循环break   输出:
action something!
action something!
action something!

7.2.4 在循环中使用continue

continue仅仅跳出本次循环,在从头开始循环(若条件满足)

7.3 使用 while 循环处理列表和字典

前面提到用for循环来遍历列表中的元素,如果我们想修改列表中的元素时,for循环难以确定元素,我们可以使用while循环来遍历并修改元素!

7.3.1 在列表之间移动元素

student = ["li hong", "xiao ming", "da zhuang"]   # 学生姓名
new_class = []         # 新的班级
while student:         # 循环(若学生列表有元素)temp_name = student.pop()     # 不断弹出new_class.append(temp_name)   # 添加到新的班级列表中
print(student)
print(new_class)输出:
[]
['da zhuang', 'xiao ming', 'li hong']

7.3.2 删除列表中特定值

student = ["xiao ming", "li hong", "xiao ming", "da zhuang", "xiao ming"]  # 有重复
while "xiao ming" in student:       # 若 xiao ming 在学习列表中student.remove("xiao ming")     # 删除
print(student)输出:
['li hong', 'da zhuang']

第八章 函数

函数是带名字的代码块,用于完成具体的任务。要执行函数定义的任务,只需要调用该函数就行!

8.1 定义函数

我们以下面的程序为例,关键词def 用来定义函数,其后面紧greet_user函数名, 圆括号()中执行函数所需的信息,这里不需要额外信息。 greet_user() 是函数的调用,最终直接返回函数结果

def greet_user():          # def 函数名(形参):"""显示问候语"""       # 注释,写函数功能等print("hello!!!")      greet_user()输出:
hello!!!

8.1.1 向函数传递信息

def 函数名(参数):      函数体

name就是我们想函数中传递的参数!

def greet_user(name):    """显示问候语"""            print("hello ", name)greet_user("li ming")

8.1.2 实参和形参

上面代码中,变量name是函数中的形参, 即函数完成任务所需的信息;“li ming” 是一个 实参,即调用函数时,传递给函数的信息。

实际执行时,函数greet_user会将实参“li ming”赋值给形参name,然后完成函数!

8.2 传递实参

函数中所需的形参有时很多,我们在调用函数时,需要传递多个实参给函数:

  • 位置实参:实参的顺序和形参的顺序一致
  • 关键字实参:其中每个实参由变量名和值组成
  • 列表以及字典传递

8.2.1 位置实参

我们举例看看:

def student(name, age):print("学生姓名: ", name)print("学生年龄: ", age)student("li ming", 18)输出:
学生姓名:  li ming
学生年龄:  18

上面函数有两个形参,所有我们调用函数时,需要传递两个实参,根据位置顺序,实参"li ming"传递给形参name,实参18传递给形参age;位置不能错!!!

函数也可以多次调用!如下面所示:

def student(name, age):print("学生姓名: ", name)print("学生年龄: ", age)student("li ming", 18)
student("da zhuang", 20)输出:
学生姓名:  li ming
学生年龄:  18
学生姓名:  da zhuang
学生年龄:  20

8.2.2 关键字实参

关键字实参是将参数名关联起来,这样可以不受顺序的影响,举例看看就懂:

def student(name, age):print("学生姓名: ", name)print("学生年龄: ", age)student(name = "li ming", age = 18)   # 调用时,直接赋值,student(age = 18, name = "li ming") 返回的结果一样!输出:
学生姓名:  li ming
学生年龄:  18

8.2.3 默认值

在函数编写时,可以给形参传递默认值,在调用函数时,若给这个形参传递了值,则用该值,若没有赋值,则函数会使用默认值!举例看看:

def student(name, age = 15):print("学生姓名: ", name)print("学生年龄: ", age)student(name = "li ming")输出:
学生姓名:  li ming
学生年龄:  15

上述代码:形参age的默认值是15, 函数调用时没有给形参赋值实参,所以按默认值!

def student(name, age = 15):print("学生姓名: ", name)print("学生年龄: ", age)student(name = "li ming", age = 18)输出:
学生姓名:  li ming
学生年龄:  18

上述代码:函数调用时,给所以形参都传递了实参,所以不会按照默认值!

8.3 返回值

函数并不是像上面直接显示值,还可以处理数据后,返回一个值或一组值,函数返回的值称为返回值。我们可以用 return语句 将函数处理结果返回出来!

8.3.1 返回简单值

def student(first_name, last_name):name = f"{first_name} {last_name}"return name       # 返回函数最终结果(name变量)result_name = student('li', 'ming')  # 将函数返回值 name 赋值给 变量 result_name
print(result_name)输出:
li ming

8.3.2 让实参可选

根据上面的代码,有时名字有三个字,我们需要加上一个形参,但名字还有两个字的,所以第三个形参就是可选的,我们可以给它一个默认值!防止报错,并将其放在形参列表的末尾!,放中间会报错!

def student(first_name, last_name, middle_name = ""):if middle_name:name = f"{first_name} {middle_name} {last_name}"else:name = f"{first_name} {last_name}"return nameresult_name = student('li', 'ming')
print(result_name)
result_name = student("xiao", 'ke', 'ai')
print(result_name)输出:
li ming
xiao ai ke

8.3.3 返回字典

函数不仅可以一个值,也可以返回一组值,如列表、字典等等!

def student(first_name, last_name, age = None):         # age是可选形参person = {"first": first_name, "last": last_name}if age:person['age'] = agereturn personresult = student('li', 'ming', 17)
print(result)输出:
{'first': 'li', 'last': 'ming', 'age': 17}

8.4 传递列表

有时我们很多信息存储在列表中,这时将信息传递给函数就很方便,我们来看看:

def student(names):      for name in names:temp = f"hello {name}"print(temp)usernames = ['li ming', 'xiao hong', 'da zhuang']
student(usernames)输出:
hello li ming
hello xiao hong
hello da zhuang

8.5 传递任意数量的实参

有时,我们不知道函数需要多少个实参,而python可以从调用的函数中取任意数量的实参,具体看看:

def student(*names):print(names)student("li ming")     # 传递一个实参和三个实参,可以的
student('li ming', 'xiao hong', 'da zhuang')输出:
('li ming',)
('li ming', 'xiao hong', 'da zhuang')

上述代码中, 形参names前面的 * 会创建一个名为names的空元组,并接受任意传进来的实参封装到元组中。然后传递给函数!

8.5.1 结合位置实参和任意数量实参

注意:

若要让函数接受不同类型的实参,必须在函数定义中将接受任意数量实参的形参放在最后。python先匹配位置参数和关键字参数,再将余下的实参都收集到最后一个形参中!

def student(age, *names):print(age, names)student(18, "li ming")   # 将18传给age,剩下的实参传递给names
student(16, 'li ming', 'xiao hong', 'da zhuang') # 将16传给age,剩下的所有实参传递给names输出:
18 ('li ming',)
16 ('li ming', 'xiao hong', 'da zhuang')

8.5.2 使用任意数量的关键字实参

有时,需要接受任意数量的实参,但不知道传递给函数的是什么信息。这时我们可以将函数写为接受任意数量的键值对,调用函数时,传递多少实参就接受多少!举例看看

def student(first, last, **user_info):user_info['first_name'] = firstuser_info['last_name'] = lastreturn user_infouser = student('li', 'ming', age = 18, location = 'princeton')
print(user)输出:
{'age': 18, 'location': 'princeton', 'first_name': 'li', 'last_name': 'ming'}

上述代码中,形参**user_info 中的两个 **会创建一个名为user_info的空字典,并将接收函的所有键值对放入里面!

8.6 将函数存储在模块中

使用函数可以将 代码块主程序 分离开,这样使得主程序显的清晰明了!我们将函数存储在称为模块独立文件夹中,再将模块导入主程序中。 import 语句可以将模块导入到当前程序中!

8.6.1 导入整个模块

我们首先创建模块。模块的扩展名是 .py文件 ,其中有我们提前写好的一个功能函数。我们举个例子看看:

我们写一个函数如下,文件命名为 print_name.py

def print_information(student):print("student information: \n")print(student)

在主程序中,用import语句导入模块(代码),然后

import print_name       # print_name 是要导入的文件名student = ['li hong', 'xiao ming', 'da zhuang']   # 定义列表print_name.print_information(student)  # 文件名.函数名 就可以调用函数了输出:
student information: ['li hong', 'xiao ming', 'da zhuang']

8.6.2 导入特定的函数

上面我们通过 import语句 导入了整个模块,然后再调用其中具体的函数。我们也可以直接导入我们要使用的具体函数: from 模块文件名 import 函数名

若要导入多个函数可以使用逗号隔开:from 模块文件名 import 函数名,函数名,函数名

所有上面的例子,我们可以直接导入要使用的函数:

from print_name import print_information        # 直接导入我们要的函数
student = ['li hong', 'xiao ming', 'da zhuang']print_information(student)输出:
student information: ['li hong', 'xiao ming', 'da zhuang']

8.6.3 使用 as 给函数指定别名

有时导入的函数名和主程序的名称重复,或本身名称过长,这时我们就可以使用as关键词改名!

from print_name import print_information as pi    # 使用as改名为pi
student = ['li hong', 'xiao ming', 'da zhuang']pi(student)

8.6.4 使用 as 给模块指定别名

也可以直接对模块改名!

import print_name as pn      # 直接改名模块的名称!student = ['li hong', 'xiao ming', 'da zhuang']pn.print_information(student)

8.6.5 导入模块中的所有函数

使用 * 来导入模块中的所有函数!

from print_name import *     # 导入模块中的所有函数!student = ['li hong', 'xiao ming', 'da zhuang']print_information(student)    # 直接调用就行!

第九章 类

面向对象编程是最有效的软件编写方法之一,在面向对象编程中,我们可以构建一个表现任何事物或情境的类,并根据类创建对象。编写类时,我们所定义的具有所有对象的通用行为

基于类创建的对象,都自动具有类的通用行为,然后根据需要赋予每个对象独立的特征,来完成具体任务!

根据类来创建对象称为实例化 , 这样就可以使用类的实例!

9.1 创建和使用类

使用类几乎可以模拟任何东西,我们编写一个小狗的类Dog,这个类不是指特定的小狗,而是任何小狗。 对于小狗来说,它们有名字、年龄,它们还会蹲下、打滚。由于小狗具有上述两个信息(名字、年龄)和两种行为(蹲下、打滚),所有我们的类Dog将包含这些信息!

9.1.1 创建 Dog 类

具体如下:

class Dog:                                  # 定义一个名为Dog的类"""对小狗的简单模拟"""                   # 对类的功能做说明def __init__(self, name, age):          # 初始化方法"""初始化属性name和age"""self.name = name                      # 定义属性nameself.age = age                   # 定义属性agedef sit(self):                          # 定义方法(蹲下)"""模拟小狗收到命令时蹲下!"""print(f"{self.name} is now sitting.")def roll_over(self):                 # 定义方法(打滚)"""模拟小狗收到命令时打滚"""print(f"{self.name} rolled over")

方法 __ init __() :

  • 类中的函数称为方法。前面学到的函数都适用于方法,仅仅是调用方法的方式不同!__ init __() 是一种特殊的方式,每当我们根据Dog类创建新实例时,python都会自动运行它。在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,避免python默认方法和普通方法发生名称冲突。
  • 上面我们将方法 __ init __() 定义成包含三个形参:self、name、age,其中形参 self 必不可少,并且需要在 其他形参之前 ! 在python调用这个方法来创建Dog实例时,将 自动传入 实参self 。因此在创建实例时,不需要传递self,只需要给最后两个形参(name、age)提供值!

self.name = name 解释说明:

  • 以self为前缀的变量可以供类中的所有方法使用,可以通过类的所有实例来访问。self.name = name 获取和形参name相关联的值,并将其赋值给变量name,然后该变量被关联到当前创建的实例中!像这样可以通过实例访问的变量称为属性

Dog类还定义了另外两个方法,sit() 和 roll_over() ,这些方法执行时不需要额外的信息,因此只有一个形参self。之后创建的实例都能够访问这些方法,即小狗都会下蹲和打滚。当前的两个方法只是打印出来具体的状态,我们也可以对这块复杂化,加一个具体的行动等等!

9.1.2 根据类创建实例

我们创建一个具体的小狗:

# Dog类的创建代码在上面my_dog = Dog("xiao hei", 3)
print(my_dog.name)
print(my_dog.age)输出:
xiao hei
3

my_dog = Dog(“xiao hei”, 3) :

创建了一条名为“xiao hei”、年龄是3的小狗。执行这行代码后,python使用实参“xiao hei”和“3”来调用Dog类的方法 __ init () 。方法 init __()创建一个特定小狗的实例,并将实参传递给形参name和age,之后python返回一个表示这个小狗的实例,而我们将实例赋值给变量 my_dog

  1. 访问属性
    要访问实例的属性:实例 . 属性名 , 如:my_dog.name
  2. 调用方法
    根据类创建实例后,就能使用类中定义的任何方法了:实例 . 方法名 , 具体如下:
my_dog = Dog("xiao hei", 3)
my_dog.sit()
my_dog.roll_over()输出:
xiao hei is now sitting.
xiao hei rolled over
  1. 创建多个实例
    可以按照任务,创建任意数量的实例:
my_dog = Dog("xiao hei", 3)       # 创建实例 my_dog
your_dog = Dog("da zhuang", 5)    # 创建实例 your_dog print(my_dog.name)        # 实例 my_dog 的属性
print(my_dog.age)         # 实例 my_dog 的属性
print(your_dog.name)      # 实例 your_dog 的属性
print(your_dog.age)       # 实例 your_dog 的属性my_dog.sit()               # 实例 my_dog的方法
my_dog.roll_over()         # 实例 my_dog的方法
your_dog.sit()             # 实例 your_dog 的方法
your_dog.roll_over()       # 实例 your_dog 的方法输出:
xiao hei
3
da zhuang
5
xiao hei is now sitting.
xiao hei rolled over
da zhuang is now sitting.
da zhuang rolled over

上面,我们定义了两个实例,每个实例都有自己特定的属性,并能够执行相同的方法!

9.2 使用类和实例

可以使用类来描述现实世界的很多事物和情景。类编写好后,我们可以创建很多的实例,我们常常会依据任务来修改实例的属性、方法等等!

9.2.1 Car 类

编写一个表示汽车的类:

class Car:"""模拟汽车"""def __init__(self, make, model, year):"""初始化描述汽车的属性"""self.make = make              # 制造商self.model = model            # 型号self.year = year              # 生产年份def get_descriptive_name(self):"""返回清晰的信息"""lone_name = f"{self.year} {self.make} {self.model}"     # 汽车整体信息return lone_name.title()        # 首字母大写my_new_car = Car("audi", 'a4', '2019')       # 创建实例,赋值给 my_new_car
print(my_new_car.get_descriptive_name())     # 调用类中的方法 get_descriptive_name输出:
2019 Aodi A4

上述代码中,我们创建了一个Car类,给了其三个属性(make、model、year)和一个方法(get_descriptive_name),下面我们对它继续修改

9.2.2 给属性指定默认值

创建实例时,有些属性无需通过形参定义,可在方法 __ init __() 中为其指定默认值

下面添加一个名为 odometer_reading 的属性,其初始值为0,。我们还添加一个名为read_odometer()的方法,用于读取汽车的里程表:

class Car:"""模拟汽车"""def __init__(self, make, model, year):"""初始化描述汽车的属性"""self.make = make              # 制造商self.model = model            # 型号self.year = year              # 生产年份self.odometer_reading = 0              # 里程数 默认为0def get_descriptive_name(self):"""返回清晰的信息"""lone_name = f"{self.year} {self.make} {self.model}"return lone_name.title()def read_odometer(self):"""打印一条汽车公里数的消息"""print(f"This car has {self.odometer_reading} miles on it.")my_new_car = Car("audi", 'a4', '2019')       # 创建实例,赋值给 my_new_car
print(my_new_car.get_descriptive_name())     # 调用类中的方法 get_descriptive_name
my_new_car.read_odometer()                   # 调用类中的方法 read_odometer输出:
2019 Audi A4
This car has 0 miles on it.

上述代码中,我们给属性 odometer_reading 了一个默认值 0 !即汽车出厂的公里数为0,这一般是不合理的,所以需要对该属性的值进行修改

9.2.3 修改属性的值

一般有三种修改的方法:

  1. 直接修改属性的值
    我们可以通过实例直接对它修改
# Car类 代码和上面相同
my_new_car = Car("audi", 'a4', '2019')       # 创建实例,赋值给 my_new_car
print(my_new_car.get_descriptive_name())     # 调用类中的方法 get_descriptive_namemy_new_car.odometer_reading = 23    # 直接对属性修改
my_new_car.read_odometer()          # 调用方法输出:
2019 Audi A4
This car has 23 miles on it.
  1. 通过方法修改属性的值
    如果可以让某个方法在内部直接对值进行修改,我们就可以不用直接访问属性了
class Car:"""模拟汽车""""""中间同上"""def updata_odometer(self, mileage):       # 通过方法直接对属性进行修改!"""将里程数设置为指定值"""self.odometer_reading = mileagemy_new_car = Car("audi", 'a4', '2019')       # 创建实例,赋值给 my_new_car
print(my_new_car.get_descriptive_name())     # 调用类中的方法 get_descriptive_namemy_new_car.updata_odometer(23)          # 调用方法来直接修改属性值
my_new_car.read_odometer()              输出:
2019 Audi A4
This car has 23 miles on it.
  1. 通过方法对属性的值进行递增
    有时我们需要对属性值进行递增,而不是赋予新的值。
class Car:"""模拟汽车""""""中间同上"""def updata_odometer(self, mileage):"""将里程数设置为指定值"""self.odometer_reading = mileagedef increase_odometer(self, miles):"""将里程数增加一定量"""self.odometer_reading += milesmy_new_car = Car("audi", 'a4', '2019')       # 创建实例,赋值给 my_new_car
print(my_new_car.get_descriptive_name())     # 调用类中的方法 get_descriptive_namemy_new_car.updata_odometer(2300)        # 修改属性(指定里程数)
my_new_car.read_odometer()my_new_car.increase_odometer(100)       # 修改属性(增加里程数)
my_new_car.read_odometer()输出:
2019 Audi A4
This car has 2300 miles on it.
This car has 2400 miles on it.

通过上面三种方式:

  • 调用实例,直接对属性进行修改
  • 通过方法,修改属性
  • 通过方法,对属性值进行递增(也可以进行其他操作)

9.3 继承

编写类时,并不是从空白开始,如果我们编写的 类B 是从 类A 改变过来的,可使用继承类B继承类A时,将自动获得类A的所有属性和方法。这时类A叫做父类,而类B叫做子类

子类继承了父类的所有属性和方法,同时还可以定义自己的属性和方法 !

9.3.1 子类的方法 __ init __()

在现有类的基础上建立新类时,一般要调用父类的方法 __ init __(),这将初始化在父类 __ init __() 方法中定义的所有属性,从而让子类包含这些属性!

上面我们建立了Car类,模拟了汽车,若我们要模拟电动汽车呢?电动汽车具备一般汽车的属性,还有自己的独有属性和方法!

# 定义父类 Car
class Car:"""模拟汽车"""def __init__(self, make, model, year):"""初始化描述汽车的属性"""self.make = make              # 制造商self.model = model            # 型号self.year = year              # 生产年份self.odometer_reading = 0              # 里程数 默认为0def get_descriptive_name(self):"""返回清晰的信息"""lone_name = f"{self.year} {self.make} {self.model}"return lone_name.title()def read_odometer(self):"""打印一条汽车公里数的消息"""print(f"This car has {self.odometer_reading} miles on it.")def updata_odometer(self, mileage):"""将里程数设置为指定值"""self.odometer_reading = mileagedef increase_odometer(self, miles):"""将里程数增加一定量"""self.odometer_reading += miles# 定义子类 ElectricCar
class ElectricCar(Car):"""电动汽车"""def __init__(self, make, model, year):"""初始化父类的属性"""super().__init__(make, model, year)         # 让子类包含父类的所有属性my_tesla = ElectricCar("tesla", 'model s', '2019')       # 创建实例
print(my_tesla.get_descriptive_name())                   # 调用父类中的方法输出:
2019 Tesla Model S
  • 对于 父类Car 代码,我们在创建子类时,父类必须包含在当前文件中,并且位于子类之前
  • 定义子类ElectricCar时,必须在圆括号内指定父类的名称。方法 __ init __() 接受创建Car实例所需的信息!
  • super() 是一个特殊函数,让你可以调用父类的方法,上面super()那行代码让python调用Car类的方法__ init __(),让 ElectricCar 实例包含这个方法中定义的所有属性。父类也称为超类,super()就是这么来的!
  • 测试继承是否正确,创建实例 my_tesla ,我们给的信息和创建一般车的信息一致(make, model, year),在类ElectricCar中创建实例时,会调用类ElectricCar中的方法__ init __(),然后类中的方法会调用父类Car中定义的方法 __ init __()!
  • 对于类ElectricCar,除了方法__ init __()外,没有其他的属性和方法,我们仅仅确定了电动汽车具备一般汽车的属性等!

接下来,我们可以赋予电动车一些自己独特的属性和方法

9.3.2 给子类定义属性和方法

class Car:"""模拟汽车""""""中间同上"""class ElectricCar(Car):"""电动汽车的独特之处"""def __init__(self, make, model, year):super().__init__(make, model, year)       # 初始化父类的属性self.battery_size = 75                    #  初始化电动汽车独有的属性def describe_battery(self):"""打印一条描述电池容量的消息"""print(f"This car has a {self.battery_size} -kwh battery.")my_tesla = ElectricCar("tesla", 'model s', 2019)       # 创建实例,赋值给 my_new_car
print(my_tesla.get_descriptive_name())     # 调用类中的方法 get_descriptive_namemy_tesla.describe_battery()输出:
2019 Tesla Model S
This car has a 75 -kwh battery.

上面代码中,根据类ElectricCar创建的所有实例都将包含属性 battery_size , 而父类Car的所有实例都不会包含这个属性。

对子类ElectricCar的特殊程度没有任何限制(可以加入电动车自身独有的任何属性和方法)。但当某个属性或方法是任何汽车都有的,并不是电动车独有的,这时应该将其加入Car类 而不是类ElectricCar中。

9.3.3 重写父类的方法

若父类中的方法不符合子类中的要求,比如Car类中有油箱,但是ElectricCar类中是没有的,这时我们可以定义一个和该方法同名的方法。这样,python就会优先考虑子类中的方法!

例如Car类中有一个名为 fill_gas_tank()的方法,电动车是没有油箱的!因此我们可以重写该方法:

class Car:
"""模拟汽车""""""中间同上"""class ElectricCar(Car):"""电动汽车的独特之处"""def __init__(self, make, model, year):super().__init__(make, model, year)      self.battery_size = 75def describe_battery(self):"""打印一条描述电池容量的消息"""print(f"This car has a {self.battery_size} -kwh battery.")def fill_gas_tank(self):              # 直接对方法fill_gas_tank重写!"""电动车没有油箱"""print("This car doesn't need a gas tank.")

这时,若调用 类ElectricCar中的 fill_gas_tank()方法,python将忽略父类Car中的 fill_gas_tank()方法,而直接调用子类 fill_gas_tank()中的方法!

9.3.4 将实例用作属性

用代码模拟事物时,随着事物的复杂度,我们会添加很多的属性和方法,使得这个文件很长。这种情况下,可能需要将类的一部分提取出来,作为一个新类。

例如描述电动汽车ElectricCar,我们可能会将电池的情况描述的很详细,这时就可以让电池作为新的类Battery,并将一个实例Battery作为类ElectricCar类的属性!具体如下:

class Car:
"""模拟汽车""""""中间同上"""class Battery:             """对电池的模拟"""def __init__(self, battery_size = 75):"""初始化电池的大小"""self.battery_size = battery_sizedef describe_battery(self):"""打印一条有关电瓶大小的消息"""print(f"This car has a {self.battery_size} -kwh battery.")class ElectricCar(Car):"""电动汽车的独特之处"""def __init__(self, make, model, year):super().__init__(make, model, year)       # 初始化父类的属性(Car类)self.battery = Battery()                  # 初始化电动车的特有属性(battery类)my_tesla = ElectricCar("tesla", 'model s', 2019)   # 创建实例(电动汽车的示例)
print(my_tesla.get_descriptive_name())             # 调用父类中的方法
my_tesla.battery.describe_battery()                # 实例my_tesla查找属性battery,然后对存储在属性中的Battery实例调用方法describe_battery()

上述代码中:

  • 类Battery 定义了电池的一些属性和方法,它没有继承任何类!
  • self.battery = Battery()
    • 这里Python会创建一个新的 Battery() 的实例,并将该实例赋值属性self.battery
    • ElectricCar 中的方法 __ init __ () 每次调用时,都将初始化属性self.battery,即每个ElectricCar实例都包含一个自动创建的Battery实例

9.4 导入类

上面提到,我们可以拆分类来实现整体代码的阅读性,但由于描述的事物过于复杂,整体文件还是会很长,这里我们也可以像函数一样,先将类存储到模块中,再将其导入到主程序中!

9.4.1 导入单个类

我们创建一个 car.py 的文件(模块),来描述汽车!

"""一个用来表示汽车的类"""             # 对该文档的说明描述(好的编程习惯,就应该加上具体的描述)class Car:"""模拟汽车"""def __init__(self, make, model, year):"""初始化描述汽车的属性"""self.make = make              # 制造商self.model = model            # 型号self.year = year              # 生产年份self.odometer_reading = 0              # 里程数 默认为0def get_descriptive_name(self):"""返回清晰的信息"""lone_name = f"{self.year} {self.make} {self.model}"return lone_name.title()def read_odometer(self):"""打印一条汽车公里数的消息"""print(f"This car has {self.odometer_reading} miles on it.")def updata_odometer(self, mileage):"""将里程数设置为指定值"""self.odometer_reading = mileagedef increase_odometer(self, miles):"""将里程数增加一定量"""self.odometer_reading += miles

然后创建另一个文件 my_car.py,并在其中导入Car类并创建具体实例:

from car import Car           # 打开文件(模块)car 导入其中的 Car 类my_new_car = Car("audi", "a8", "2020")       # 初始化实例
print(my_new_car.get_descriptive_name())     # 调用方法my_new_car.odometer_reading = 52        # 属性赋值
my_new_car.read_odometer()              # 调用方法输出:
2020 Audi A8
This car has 52 miles on it.

9.4.2 在一个模块中存储多个类

同一个模块中的类有一定的相关性,但也可以根据需要在一个模块中存储任意数量的类。我们在上面Car类的基础上再加 Battery类和ElectricCar类

"""一组用于表示燃油车和电瓶汽车的类"""       # 对文件(模块)的描述class Car:"""模拟汽车"""def __init__(self, make, model, year):"""初始化描述汽车的属性"""self.make = make              # 制造商self.model = model            # 型号self.year = year              # 生产年份self.odometer_reading = 0              # 里程数 默认为0def get_descriptive_name(self):"""返回清晰的信息"""lone_name = f"{self.year} {self.make} {self.model}"return lone_name.title()def read_odometer(self):"""打印一条汽车公里数的消息"""print(f"This car has {self.odometer_reading} miles on it.")def updata_odometer(self, mileage):"""将里程数设置为指定值"""self.odometer_reading = mileagedef increase_odometer(self, miles):"""将里程数增加一定量"""self.odometer_reading += milesclass Battery:"""对电池的模拟"""def __init__(self, battery_size = 75):"""初始化电池的大小"""self.battery_size = battery_sizedef describe_battery(self):"""打印一条有关电瓶大小的消息"""print(f"This car has a {self.battery_size} -kwh battery.")def get_range(self):"""打印一条描述电瓶容量的消息"""if self.battery_size == 75:range = 260elif self.battery_size == 100:range = 315print(f"This car can go about {range} miles on a full charge.")class ElectricCar(Car):"""电动汽车的独特之处"""def __init__(self, make, model, year):super().__init__(make, model, year)       # 初始化父类的属性self.battery = Battery()                  # 初始化电动车的特有属性

现在创建一个名为 my_electric_car.py 的文件,将上面的导入:

from car import ElectricCar         # 打开文件(模块)导入 类ElectricCar     my_tesla = ElectricCar("tesla", "model s", 2020)   # 创建实例
print(my_tesla.get_descriptive_name())             # 调用方法my_tesla.battery.describe_battery()     # 调用方法
my_tesla.battery.get_range()            # 调用方法输出:
2020 Tesla Model S
This car has a 75 -kwh battery.
This car can go about 260 miles on a full charge.

9.4.3 从一个模块中导入多个类

可以在主程序中导入任意数量的类,比如我们要创建一个普通汽车和电动汽车,那么我们就要导入Car类和ElectricCar类:

from car import Car, ElectricCar                    # 从文件(模块)导入类Car、类ElectricCarmy_beetle = Car("volkswagen", "beetle", 2020)       # 创建实例
print(my_beetle.get_descriptive_name())             # 调用方法my_tesla = ElectricCar("tesla", "model s", 2020)    # 创建实例
print(my_tesla.get_descriptive_name())              # 调用方法输出:
2020 Volkswagen Beetle
2020 Tesla Model S

9.4.4 导入整个模块

上面我们导入模块中的一个类、多个类,当然也可以导入整体模块,然后根据句点法调用具体的类!

import car           # 导入整个模块my_beetle = car.Car("volkswagen", "beetle", 2020)      # 创建实例(调用具体类)
print(my_beetle.get_descriptive_name())my_tesla = car.ElectricCar("tesla", "model s", 2020)   # 创建实例(调用具体类)
print(my_tesla.get_descriptive_name())输出:
2020 Volkswagen Beetle
2020 Tesla Model S

9.4.5 导入模块中的所有类

要导入模块(文件)中的所有类,可以用:

from model_name import *        # 这样导入了模块(文件)中的所有类

这种做法的有一些缺点

  • 我们不知道具体导入的类名称
  • 导入的类名 可能会和主程序中某些命名冲突,不易发现

我们可以用9.4.4中的做法,导入模块后,用句点法来使用具体的类!

9.4.6 在一个模块中导入另一个模块

有时,我们会把类存储在多个模块中,以免模块太多!将类存储在多个模块中,有时一个模块中的类可能会依赖其他模块中的类,这时可在前一个模块中导入必要的类!举例说明:

我们将Car类存储在一个模块car.py中,ElectricCar类、Battery类存储在另一个模块electric_car.py中:

模块 car.py:

"""用于表示汽车的类"""       # 对文件(模块)的描述class Car:"""模拟汽车"""def __init__(self, make, model, year):"""初始化描述汽车的属性"""self.make = make              # 制造商self.model = model            # 型号self.year = year              # 生产年份self.odometer_reading = 0              # 里程数 默认为0def get_descriptive_name(self):"""返回清晰的信息"""lone_name = f"{self.year} {self.make} {self.model}"return lone_name.title()def read_odometer(self):"""打印一条汽车公里数的消息"""print(f"This car has {self.odometer_reading} miles on it.")def updata_odometer(self, mileage):"""将里程数设置为指定值"""self.odometer_reading = mileagedef increase_odometer(self, miles):"""将里程数增加一定量"""self.odometer_reading += miles

模块 electric_car.py:

  • 由于ElectricCar类用到了类Car,所有应先将类Car导入
"""用于表示电动汽车和电池的类"""       # 对文件(模块)的描述from car import Car        # 先将类Car 导入class Battery:"""对电池的模拟"""def __init__(self, battery_size = 75):"""初始化电池的大小"""self.battery_size = battery_sizedef describe_battery(self):"""打印一条有关电瓶大小的消息"""print(f"This car has a {self.battery_size} -kwh battery.")def get_range(self):"""打印一条描述电瓶容量的消息"""if self.battery_size == 75:range = 260elif self.battery_size == 100:range = 315print(f"This car can go about {range} miles on a full charge.")class ElectricCar(Car):"""电动汽车的独特之处"""def __init__(self, make, model, year):super().__init__(make, model, year)       # 初始化父类的属性self.battery = Battery()                  # 初始化电动车的特有属性

主程序 my_cars.py:

from car import Car
from electric_car import ElectricCarmy_beetle = Car("volkswagen", "beetle", 2020)
print(my_beetle.get_descriptive_name())my_tesla = ElectricCar("tesla", "model s", 2020)
print(my_tesla.get_descriptive_name())输出:
2020 Volkswagen Beetle
2020 Tesla Model S

9.4.7 使用别名

上一章中,函数导入时可以将函数名改为其他名称,对于类也是可以的!举例如下:

from electric_car import ElectricCar as EC    # 将类ElectricCar 改为 EC

若要创建电动车实例时,只需要调用 EC就行

my_tesla = EC("tesla", "model s", 2020)

9.5 python 标准库

python标准库是一组模块,我们安装好python后就包含它了。我们对函数和类的模块原理已经了解了,同理也使用其他人编写好的模块,我们只需要: import 模块名

random模块 为例,它其中有一个函数为 randint()

from random import randint   # 导入模块result = randint(1, 10)      # 传入两个整数,返回其范围中任意数字
print(result)输出:
4

模块random中,另外一个函数choice()。它将一个列表或元组作为参数,返回其中随机一个元素:

from random import choiceresult = choice(["li ming", "xiao hong", "da zhuang"])
print(result)输出:
xiao hong

第十章 文件和异常

本章学习python对文件的处理、对程序运行错误的处理以及json模块,用来保存数据防止程序停止运行后丢失!

10.1 从文件中读取数据

日常中,文本文件最多,我们应该学会如何去处理这些文件,在使用或处理这文本时,我们应先读取这些文件,可以一次性全部读取,也可以逐行的读取

10.1.1 读取整个文件

首先我们创建一个文本文件 pi_digits.txt ,其内容为:

3.1415926535
8979323846
2643383279

我们一次性读取文本中所有内容

with open("pi_digits.txt") as file_object:   # 打开文件contents = file_object.read()            # 读取文件所有内容print(contents)输出:
3.1415926535
8979323846
2643383279

我们解读一下上面的代码:

  • open(文件目录):会打来要读取的文件,并返回该文件的一个对象
  • as 变量名:会将上面的对象赋值给变量 file_object
  • with:可以让python自动的判断什么时候打开文件,什么时候关闭文件
  • 有个文件的对象之后,就可以用 read()函数 读取文件的全部内容

10.1.2 文件路径

上面代码中,open()函数中传递的文件目录是相对路径,即该文件所在目录相对于当前程序运行所在的目录!有时为了防止出错,可以使用绝对路径,即文件在计算机中的位置!

10.1.3 逐行读取

有时我们需要对文件中的内容进行逐行的读取,用于修改或查看等等!我们继续用上面的例子来说;

filename = "pi_digits.txt"             # 文件的路径with open(filename) as file_object:    # 打开文件for line in file_object:           # 逐行读取(通过循环)print(line)                    # 打印输出:
3.141592653589793238462643383279

上述打印出来的有很多的空行,和文件中的不一样,因为文件中每行的末尾都有一个换行符,而print()在读取时也会加上一个换行符,这时就有两个换行符:一个来自文件,一个来自print()函数,我们可以使用rstrip()函数来消除

filename = "pi_digits.txt"with open(filename) as file_object:for line in file_object:print(line.rstrip())输出:
3.1415926535
8979323846
2643383279

10.1.4 创建一个包含文件各行内容的列表

使用关键词with时,open()返回的文件对象只能在with代码块中使用。若要在with代码块外面访问文件内容,可以在with代码块中将文件各行存储在一个列表中,然后在with代码块外面使用!

filename = "pi_digits.txt"              # 文件目录with open(filename) as file_object:     # 打开文件lines = file_object.readlines()     # 读取文件,存放到列表中print(lines)for line in lines:           # 通过循环打印出文件信息print(line.rstrip())输出:
['3.1415926535\n', '8979323846\n', '2643383279']    # 整个文件存储在列表中,每行作为列值中一个元素
3.1415926535
8979323846
2643383279

10.2 写入文件

当我们想要保存某些数据时,通常的做法就是直接对其保存,将数据写到一个文件中!举例看看:

10.2.1 写入空文件

filename = "programming.txt"      # 文件目录with open(filename, "w") as file_object:      # 打开文件,写入模式file_object.write("I love programming")   # 写入数据(此处是一个字符串)
# programming.txt 文件中的内容
I love programming

解释上述代码:

  • open(文件目录, “w”):函数 open() 中包含两个参数:一个文件目录一个是写入模式(告诉python要往文件中写入数据);当然还有其他的模式,例如读取模式(“r”)、附加模式(“”)、读写模式(“r+”)
  • 若在写入时不存在文件 programming.txt,python会自动创建一个名为programming.txt的文件,并往里面写入数据
  • 若在写入时存在文件programming.txt,python会自动删除文件中的内容,再往里面写入数据!

10.2.2 写入多行文件

函数 write()不会在写入的文件末尾添加换行符,若要写入多行文件时,可能达不到预期想要的!举例看看:

filename = "programming.txt"with open(filename, "w") as file_object:file_object.write("I love programming.")file_object.write("I love creating new games.")

查看文件,发现上面写入的两句话变成一行了!

# programming.txt 文件中的内容
I love programming.I love creating new games.

要让每个字符串占一行,就应该在字符串后面加换行符

filename = "programming.txt"with open(filename, "w") as file_object:file_object.write("I love programming.\n")     # 字符串后面加换行符file_object.write("I love creating new games.\n")
# programming.txt 文件中的内容
I love programming.
I love creating new games.

10.2.3 附加到文件

上面提到,在 写入模式(“w”) 中,若文件已经存在,python会将文件中的内容删除,再写入数据。那若要在原有文件继续写入数据呢?这时就要使用附加模式(“s”),当然文件若不存在,python也是会提前创建一个空文件的!

我们对上面的文件 programming.txt 继续修改,给它添加一些信息:

filename = "programming.txt"with open(filename, "a") as file_object:file_object.write("I also love finding meaning in large datasets.\n")file_object.write("I love creating apps that can run in a browser.")
# programming.txt 文件中的内容
I love programming.
I love creating new games.
I also love finding meaning in large datasets.
I love creating apps that can run in a browser.

我们发现,原本的文件信息还在,下面两行是刚添加上的!

10.3 异常

程序发生错误后,会停止运行并报错;但是有时我们不知道程序还有什么问题,为了提前避免程序发生错误停止运行,python中有称为异常的一个对象可以管理程序发生错误!当程序发生错误后,会走我们提前指定的路线执行

异常吹模块: try - except

10.3.1 处理 ZeroDivisionError 异常

我们知道除法中,除数不能为零,程序碰到这种情况会报错,我们看看:

print(5/0)输出:
Traceback (most recent call last):File "C:/Users/Administrator/PycharmProjects/venv/my_cars.py", line 1, in <module>print(5/0)
ZeroDivisionError: division by zero

python一旦遇到错误就会停止执行!

10.3.2 使用 try - except 模块

一般就代码块放在try语句下,若代码块报错,将执行except下的代码,若代码块没有报错,就忽略except下的代码!

try:print(5/0)                   # 代码在try中,报错则执行except;否则忽略except
except ZeroDivisionError:        print("You can't divide by zero")

由于知道try中程序可能报ZeroDivisionError错误,若不知道将会报什么错,也可以不写,如下:

try:print(5/0)
except:                         # 直接写except         print("You can't divide by zero")

10.3.3 使用异常避免崩溃

有时程序在执行过程中,为了防止报错而导致后续程无法执行,就应该加上try-except:

print("这是一个简单的除法计算器")while True:first_number = input("请输入第一个数: ")second_number = input("请输入第二个数: ")answer = float(first_number) / float(second_number)print(answer)输出:这是一个简单的除法计算器
请输入第一个数: 5
请输入第二个数: 0
Traceback (most recent call last):File "F:/py_object/alien_invasion/1.py", line 6, in <module>answer = float(first_number) / float(second_number)
ZeroDivisionError: float division by zero

上述代码中,当除数为零时就会报错,导致程序后续无法执行,这时就应该用异常处理模块!

10.3.4 else 代码块

在python中,若将代码块放在try中,若程序报错,就执行except中的代码,若执行成功,我们可以在else中进行打印或执行:

print("这是一个简单的除法计算器")while True:first_number = input("请输入第一个数: ")second_number = input("请输入第二个数: ")try:answer = float(first_number) / float(second_number)except ZeroDivisionError:print("除数不应该为零")else:print(answer)输出:这是一个简单的除法计算器
请输入第一个数: 5
请输入第二个数: 0
除数不应该为零

10.3.5 处理 FileNotFoundError 异常

处理文件数据时,若程序找不到文件一般会报错,

filename = "ceshi.txt"try:with open(filename, encoding='UTF-8') as file:        # 打开文件lines = file.read()
except FileNotFoundError:                                 # 报错print(f"Sorry, The file {filename} does not exist")输出:
Sorry, The file ceshi.txt does not exist

我们还会遇到很多的错误,基本都可以使用这样的方式去处理!

10.3.6 静默失败

前面程序中,程序遇到错误后,都会去执行excep中的程序,我们都会打印一个报错的信息,但有时我们想一直去执行,不需要打印什么报错信息,这时就可以使用 pass

filename = "ceshi.txt"try:with open(filename, encoding='UTF-8') as file:        # 打开文件lines = file.read()
except FileNotFoundError:                                 # 若出错,什么都不打印!pass    输出:

10.4 存储数据

我们经常需要把程序中的一些数据如:列表、字典等数据保存在文件中!一种简单的方式是使用 json模块 存储数据!

JSON数据格式并非python专用,可以和其他编程语言一起共享数据!

10.4.1 使用 json.dump() 和 json.load()

我们举例看看:

# 写文件
import json           # 导入json模块numbers = [1, 2, 3, 4, 5]             # 要存储的列表
filename = "numbers.json"             # 文件
with open(filename, 'w') as file:     # 打开文件json.dump(numbers, file)          # 写入列表到文件中
# 读取文件
import jsonfilename = "numbers.json"                    # 文件
with open(filename, 'r') as file:            # 打开文件numbers = json.load(file)                # 加载文件print(numbers)输出:
[1, 2, 3, 4, 5]

第 11 章 测试代码

我们写好的代码,都应该经过一系列的测试去看是否达到我们的预期!

11.1 测试函数

我们先写一个简单的代码:

# 传入姓和名,打印出完整的姓名,首字母大写
def get_formatted_name(first, last):"""生成完整的姓名"""full_name = f"{first} {last}"return full_name.title()

我们重新建立一个python脚本,将上面函数导入。并编写测试函数:

from name_function import get_formatted_name        # 导入函数print("Enter 'q' at any time to quit.\n")        while True:first = input("Please give me a first name: ")if first == "q":breaklast = input("Please give me a last name: ")if last == "q":breakformatted_name = get_formatted_name(first, last)print(f"Neatly formatted name: {formatted_name}")

11.1.1 单元测试和测试用例

python中的 模块unittext 提供了代码测试工具。

单元测试:核实函数的某些方面没有问题
测试用例:是一组测试单元,用来核实函数在各种情形下的行为都符合要求!

11.1.2 可通过的测试

我们使用python中的unittest模块!

import unittest                                      # python标准库
from name_function import get_formatted_name         # 被测试的函数class NameTestCase(unittest.TestCase):               # 要继承unittest.TestCase这个类def test_first_last_name(self):"""测试像姓和名为 'janis' 和 'joplin' 的用例"""formatted_name = get_formatted_name('janis', 'joplin')self.assertEqual(formatted_name, 'Janis Joplin')       # assertEqual:断言方法,用来核实输出和期望是否一致if __name__ == '__main__':unittest.main()输出:
============================= test session starts =============================
platform win32 -- Python 3.7.4, pytest-5.2.1, py-1.8.0, pluggy-0.13.0 -- D:\Anaconda\python.exe
cachedir: .pytest_cache
rootdir: F:\py_object\alien_invasion
plugins: arraydiff-0.3, doctestplus-0.4.0, openfiles-0.4.0, remotedata-0.3.2
collecting ... collected 1 itemtest_name_function.py::NameTestCase::test_first_last_name PASSED         [100%]============================== 1 passed in 0.02s ==============================

《python编程:从入门到实战》学习笔记相关推荐

  1. 第二行代码学习笔记——第六章:数据储存全方案——详解持久化技术

    本章要点 任何一个应用程序,总是不停的和数据打交道. 瞬时数据:指储存在内存当中,有可能因为程序关闭或其他原因导致内存被回收而丢失的数据. 数据持久化技术,为了解决关键性数据的丢失. 6.1 持久化技 ...

  2. 第一行代码学习笔记第二章——探究活动

    知识点目录 2.1 活动是什么 2.2 活动的基本用法 2.2.1 手动创建活动 2.2.2 创建和加载布局 2.2.3 在AndroidManifest文件中注册 2.2.4 在活动中使用Toast ...

  3. 第一行代码学习笔记第八章——运用手机多媒体

    知识点目录 8.1 将程序运行到手机上 8.2 使用通知 * 8.2.1 通知的基本使用 * 8.2.2 通知的进阶技巧 * 8.2.3 通知的高级功能 8.3 调用摄像头和相册 * 8.3.1 调用 ...

  4. 第一行代码学习笔记第六章——详解持久化技术

    知识点目录 6.1 持久化技术简介 6.2 文件存储 * 6.2.1 将数据存储到文件中 * 6.2.2 从文件中读取数据 6.3 SharedPreferences存储 * 6.3.1 将数据存储到 ...

  5. 第一行代码学习笔记第三章——UI开发的点点滴滴

    知识点目录 3.1 如何编写程序界面 3.2 常用控件的使用方法 * 3.2.1 TextView * 3.2.2 Button * 3.2.3 EditText * 3.2.4 ImageView ...

  6. 第一行代码学习笔记第十章——探究服务

    知识点目录 10.1 服务是什么 10.2 Android多线程编程 * 10.2.1 线程的基本用法 * 10.2.2 在子线程中更新UI * 10.2.3 解析异步消息处理机制 * 10.2.4 ...

  7. 第一行代码学习笔记第七章——探究内容提供器

    知识点目录 7.1 内容提供器简介 7.2 运行权限 * 7.2.1 Android权限机制详解 * 7.2.2 在程序运行时申请权限 7.3 访问其他程序中的数据 * 7.3.1 ContentRe ...

  8. 第一行代码学习笔记第五章——详解广播机制

    知识点目录 5.1 广播机制 5.2 接收系统广播 * 5.2.1 动态注册监听网络变化 * 5.2.2 静态注册实现开机广播 5.3 发送自定义广播 * 5.3.1 发送标准广播 * 5.3.2 发 ...

  9. 第一行代码学习笔记第九章——使用网络技术

    知识点目录 9.1 WebView的用法 9.2 使用HTTP协议访问网络 * 9.2.1 使用HttpURLConnection * 9.2.2 使用OkHttp 9.3 解析XML格式数据 * 9 ...

  10. 安卓教程----第一行代码学习笔记

    安卓概述 系统架构 Linux内核层,还包括各种底层驱动,如相机驱动.电源驱动等 系统运行库层,包含一些c/c++的库,如浏览器内核webkit.SQLlite.3D绘图openGL.用于java运行 ...

最新文章

  1. 算法--------旋转数组
  2. ubuntu文件权限解析
  3. C#使用NPOI导出Excel文件
  4. 微软Connect(); 2017大会梳理:Azure、数据、AI开发工具
  5. C++ 标准输入流01
  6. 注意力机制-深度学习中的注意力机制+注意力机制在自然语言处理中的应用
  7. java中nonce_java如何获取微信timestamp,nonceStr,signature参数
  8. 按钮点击打开新页面_PDF怎么打开?如何制作一个PDF格式的文档?
  9. Linux简单实用小技巧
  10. Python工程师必看的面试问题与解答(中) 1
  11. python爬虫实践
  12. 怎么调html分辨率,屏幕分辨率怎么调
  13. 英汉词典 JaVa_一个Java编写的英汉词典
  14. 天下3为啥不显示服务器列表,69级封顶,孩子、画卷系统关闭……《天下3》全新主题服务器玩法全公开!...
  15. 大数据精准营销数据分析处理(一)
  16. 美通企业日报 | 拜耳健康消费品中国研发中心开幕;TCL上半年电视机销量稳居全球第二...
  17. 各种生物识别的优缺点
  18. 算法笔记 刷题2.6
  19. BZOJ1023 [SHOI2008]仙人掌图
  20. Linux 网桥配置br-lan、eth0、eth1、ra0、rai0

热门文章

  1. (转)人工智能步入金融领域的主流玩法
  2. OpenAnolis社区致Linux开发者的一封信
  3. 【基础处理】基于matlab Fxlms算法有源噪声控制系统【含Matlab源码 1394期】
  4. 【图像几何】基于matlab GUI图像拉东变换【含Matlab源码 848期】
  5. 树莓派开发界面显示温度_关于树莓派linux开发板
  6. cpu内存和线程和pool多进程池 Python
  7. 用DFS深度优先搜索求 1~n 的全排列
  8. js 多个定时器_《进击的前端工程师》Node.js事件循环
  9. table()函数--R语言
  10. 「干货」模拟信号和数字信号的差异