python学习笔记
文章目录
1.python基础
python + selenium -> web自动化
python + appium -> 移动端自动化
python + requests -> 接口
语言分类:
编译型语言:C ->代码转换为二进制,效率高
解释型语言:python ->执行代码时,转化为二进制
1.1注释
-
单行注释:#
# 注释AAA 快捷键 Ctrl(cmd) /
-
多行注释:“”“/’‘’
""" print("AAA") """ ''' print('AAA') '''
-
cmd中运行python代码:
- python + 代码文件名
1.2变量
-
变量:
- 作用:是⽤来存储数据的(在程序代码中出现的数据,想要保存下
来使⽤, 就必须使⽤变量), 如: 测试数据, ⽤户名, 密码, 验
证码 - 注意:变量必须先定义(保存数据)后使⽤(取出数据)
- 作用:是⽤来存储数据的(在程序代码中出现的数据,想要保存下
-
定义变量:
- 变量名 = 数据值
- name = ‘张三’ # 定义变量name,存储的数据是张三
-
命名规范:
-
-
必须由字⺟ 数字和下划线组成, 并且不能以数字开头
-
不能使⽤ Python 中的关键字作为变量名
-
区分⼤⼩写
-
建议性的命名
-
驼峰命名法
⼤驼峰: 每个单词的⾸字⺟⼤写 MyName
⼩驼峰: 第⼀个单词的⾸字⺟⼩写,其余单词的⾸字⺟⼤写 myName
-
下划线连接法: 每个单词之间使⽤下划线连接 my_name
Python 中变量的定义使用的是下划线连接
-
⻅名知意:
name:名字 age:年龄
-
-
-
1.3数据类型
- 数字类型
- 整型 (int ) , 就是整数 , 即不带⼩数点的数
- 浮点型( float ), 就是⼩数
- 布尔类型(bool), 只有两个值
- 真 True , 1
- 假 False 0, ⾮ 0 即真
- 非数字类型
- 字符串: (str) 使⽤引号引起来的就是字符串
- 列表 (list) [1, 2, 3, 4]
- 元组(tuple) (1, 2, 4, 4)
- 字典 (dict) {‘name’: ‘⼩明’, ‘age’: 18}
- type() 函数: type(变量) 获取变量的数据类型
- 类型转换:变量 = 要转换为的类型(原数据)
- int() 将其他类型转换为 int 类型
- 可以将 float类型的数字转换为 整型
- 可以将 整数类型的字符串 转换为 整型 3 123
- float() 将其他类型转换为 浮点型
- 可以将 int 类型转换为 浮点型 float(3) —> 3.0
- 可以将 数字类型的字符串(整数类型和⼩数类型) 转换为浮点型
- str() 将其他类型转换为 字符串类型
- 任何类型都可以使⽤ str() 将其转换为字符串, ⼀般都是直接加上引号
- int() 将其他类型转换为 int 类型
1.4输入输出
-
输入:获取用户使用键盘录入的内容
- input()
- 变量 = input(‘提示信息:’)
- 变量的数据类型一定是str
-
输出:将数据结果打印到控制台
- print()
-
格式化输出
-
% 格式化输出占位符号
- %d 占位, 填充 整型数据 digit
- %0nd 指定占位
- %f 占位. 填充 浮点型数据 float
- %.nf 保留小数尾数
- %s 占位, 填充 字符串数据 string
name = '⼩明' # 可以使⽤ input 输⼊ age = 18 # 可以使⽤ input 输⼊ height = 1.71 # 可以使⽤ input 输⼊ print('我的名字是 %s, 年龄是 %d, 身⾼是 %f m' %(name, age, height))
- %d 占位, 填充 整型数据 digit
-
F-string( f字符串的格式化⽅法) python>=3.6
- 需要在字符串的前边加上 f"" 或者 F""
- 占位符号统⼀变为 {}
- 需要填充的变量 写在 {} 中
name = '⼩明' # 可以使⽤ input 输⼊ age = 18 # 可以使⽤ input 输⼊ height = 1.71 # 可以使⽤ input 输⼊ print(f'我的名字是 {name}, 年龄是 {age}, 身⾼是{height} m')
-
字符串.format()
- 任意版本
- 需要用变量的地方使用 {} 占位
- ‘{}, {}, …’.format(变量, 变量, …)
print('我的名字是 {}, 年龄是 {}, 身高是 {} m'.format(name,age, height))
-
1.5运算符
-
比较运算符
-
⽐较运算符得到都是 bool 类型
> < >= <=
== 判断两个数是否相等, 相等为 True, 不相等为 False
!= 判断两个数是否不相等, 不相等为 True, 相等为 False
-
-
逻辑运算符:
- and 逻辑与 和,并且 and 连接两个条件,都必须为 True, 整体结果才为 True, 即一假为假 (当第一个条件为False 的时候,第二个条件就不再判断)
- or 逻辑或 或者 or 连接的两个条件, 只要有一个条件为 True , 整体结果就为 True, 即 一真为真 (当第一个条件为 True的时候,第二个条件就不再判断)
- not 逻辑非 取反 not 后边的条件, 如果本来是 True,变为 False, 本来是 False,变为 True
-
赋值运算符:
-
赋值运算符 =, 作用就是将等号右边的值保存到等号左边的变量中
复合赋值运算符(将算术运算符和赋值运算符进行结合)
+= -= *= /= //= %=
a += b ===> a = a + b
-
1.6判断
-
基本语法:
if 判断条件: 书写条件成立(真),执行的代码 书写条件成立(真),执行的代码 顶格书写,没有缩进的代码,和 if无关, 不管条件是否成立,都会执行
-
if else结构:
if 判断条件1: 书写条件1成立(真),执行的代码 elif 判断条件2: 条件2成立,代码 else: 书写条件1,2不成立(假), 执行的代码
-
if嵌套:
if 判断条件1: 判断条件1成立,执行的代码 if 判断条件2: 判断条件2成立,执行的代码 else: 判断条件2不成立,执行的代码 else: 判断条件1不成立,执行的代码
1.7循环
-
while循环:
1. 设置循环的初始条件(计数器) 2. 书写循环的判断条件 while 判断条件: # 3. 需要重复执行的代码 # 4. 改变循环的初始条件(计数器) # 1. while 是关键字
- break: 终⽌循环, 即代码执⾏遇到 break, 循环不再执⾏,⽴即结束
- continue: 跳过本次循环. 即代码执⾏遇到 continue,本次循环剩下的代码不再执⾏, 继续下⼀次循环
-
for循环:
for循环也可以让指定的代码重复执⾏ (循环) for循环可以遍历容器中的数据( 遍历: 从容器中把数据⼀个⼀个取出 容器: 可以简单理解为盒⼦, 盒⼦中可以存放很多的数据 (字符串 str, 列表 list, 元组 tuple, 字典 dict) ) for 循环 也可以称为 for 遍历 ------------- for 变量名 in 容器: 重复执⾏的代码 --------- for 变量 in range(n): 重复执⾏的代码
- range() 是 Python 中的函数, 作⽤使⽤可以⽣成[0, n) 之间的整数, 不包含 n 的,有 n 个数字, 所以这个循环循环 n 次
- 想让 for 循环循环多少次,n 就写⼏
- 变量的值 也是每次循环从 [0, n) 取出⼀个值, 第⼀次取得是 0 ,最后⼀次取得是 n-1
- range(a, b) 作⽤是⽣成 [a, b) 之间的整数数字, 不包含 b
1.8字符串
1.8.1字符串
- 字符串:
- 使⽤引号(单引号, 双引号, 三引号)引起来的内容就是字符串
- 字符串本身包含单引号, 则在定义的时候不能使⽤单引号
- 转义字符 \
- 字符串本身包含双引号, 则在定义的时候不能使⽤双引号
- 字符串本身包含单引号, 则在定义的时候不能使⽤单引号
- 使⽤引号(单引号, 双引号, 三引号)引起来的内容就是字符串
- 下标:
- 就是指字符在字符串中的位置编号, 这个编号就是下标
- 正向从左到右,从0开始(Python 中⽀持负数下标,从右到左进⾏编号的, 从-1 开始)
1.8.2切片
-
概念:可以获取字符串中多个字符(多个字符的下标是有规律的,等差数列)
-
语法:字符串[start : end : step]
-
start 是开始位置的下标, end 是结束位置的下标(注意,不能取到这个位置的字符) step 步⻓,等差数列的差值, 所取的相邻字符下标之间的差值,默认是 1, 可以不写
-
例:
- [1:5:1] # 1 2 3 4
- [1:5:2] # 1 3
str1 = 'abcdefg' # 1. 获取 abc 字符 print(str1[0:3:1]) # abc # 1.1 如果步⻓是 1 可以不写, 最后⼀个冒号也不写 print(str1[0:3]) # abc # 1.2 如果开始位置为 0 ,可以不写, 但是冒号必须有 print(str1[:3]) # abc # 2. 获取 efg 字符 print(str1[4:7]) # efg print(str1[-3:7]) # efg # 2.1 如果最后⼀个字符也要取, 可以不写, 但是冒号必须有 print(str1[4:]) # efg # 2.2 如果开始和结束都不写, 获取全部内容, 但是冒号必须有 print(str1[:]) # abcdefg # 3. 获取 aceg # 0 2 4 6, 所以步⻓为 2 print(str1[0:7:2]) # aceg print(str1[::2]) # aceg # 4. 特殊应⽤, 步⻓为负数, 开始和结束不写,意思全变, ⼀般 不⽤管,只有⼀种使⽤场景 # 反转(逆置) 字符串 字符串[::-1] print(str1[::-1]) # gfedcba
-
1.8.3方法
- find()方法
- 字符串.find(sub_str, start, end)
- 作⽤: 在字符串中查找是否存在 sub_str 这样的字符串
- sub_str: 要查找的⼩的字符串
- start: 开始位置, 从哪个下标位置开始查找, ⼀般不写,默认是 0
- end: 结束位置, 查找到哪个下标结束, ⼀般不写,默认是len()
- 返回(代码执⾏之后会得到什么, 如果有返回,就可以使⽤变量保存):
- 如果在字符串中找到了 sub_str , 返回 sub_str第⼀次出现的正数下标(sub_str 中第⼀个字符在⼤字符串中的下标)
- 如果没有找到,返回 -1
- replace()方法
- 字符串.replace(old_str, new_str, count) # 将字符串中old_str 替换为 new_str
- old_str: 被替换的内容
- new_str: 替换为的内容
- count: 替换的次数, ⼀般不写,默认是全部替换
- 返回: 替换之后的完整的字符串, 注意: 原来的字符串没有发⽣改变
- 字符串.replace(old_str, new_str, count) # 将字符串中old_str 替换为 new_str
- split()拆分方法
- 字符串.split(sep, maxsplit) # 将字符串按照 sep 进⾏分割(拆分)
- sep, 字符串按照什么进⾏拆分, 默认是空⽩字符(空格, 换⾏\n, tab键\t)
- max_split, 分割次数,⼀般不写, 全部分割
- 返回: 将⼀个字符串拆分为多个,存到列表中
- 注意: 如果 sep 不写, 想要指定分割次数 则需要按照如下⽅式使⽤
- 字符串.split(maxsplit=n) # n 是次数
- 字符串.split(sep, maxsplit) # 将字符串按照 sep 进⾏分割(拆分)
- join()链接方法
- 字符串.join(列表) # 括号中的内容主要是列表,可以是其他容器
- 作⽤: 将字符串插⼊到列表中每相邻的两个数据之间, 组成⼀个新的字符串
- 列表中的数据使⽤使⽤ 逗号隔开的
- 注意点: 列表中的数据必须都是字符串, 否则会报错
2.容器和函数
2.1 列表
-
定义:
- 变量 = [数据, 数据, …]
- 列表 list, 是使⽤最多的⼀种容器(数据类型)
- 列表中可以存储多个数据, 每个数据之间使⽤逗号隔开
- 列表中可以存放任意类型的数据
-
列表支持下标和切片长度
list1 = ['⼩明', 18, 1.71, True] # 获取第⼀个数据,名字 print(list1[0]) # 获取最后⼀个数据 print(list1[-1]) # 第⼀第⼆个数据 print(list1[0:2]) # ['⼩明', 18] # 列表⻚⽀持 len() 求⻓度的, 求数据元素个数 print(len(list1)) # 4
-
查找
- 查找列表数据下标
- 列表.index(数据, start, end) 使⽤和 find ⽅法⼀样,同时在字符串中也有 index ⽅法
- 区别: 返回, index() ⽅法,找到返回第⼀次出现的下标, 没有找到代码直接报错
- 判断存在
- 判断容器中某个数据是否存在可以使⽤ in 关键字
- 数据 in 容器 # 如果存在返回 True ,如果不存在,返回 False
- 统计出现次数
- 统计出现的次数,使⽤的是 count() ⽅法
- 列表.count(数据) # 返回 数据出现的次数
my_list = [1, 3, 5, 7, 2, 3] # 找 数据 3 出现的下标 num = my_list.index(3) print(num) # 1 # 找 数据 4 出现的下标 # num1 = my_list.index(4) # 代码会报错 if 4 in my_list: num1 = my_list.index(4) print(num1) else: print('不存在数据 4') # my_list.count(4) 统计 数据 4 出现的次数 if my_list.count(4) > 0: num1 = my_list.index(4) print(num1) else: print('不存在数据 4')
- 查找列表数据下标
-
添加数据
- 尾部添加
- 列表.append(数据) # 将数据添加到列表的尾部
- 返回: 返回的 None(关键字,空), ⼀般就不再使⽤ 变量 来保存返回的内容
- 想要查看添加后的列表,需要打印的是列表
- 指定下标添加
- 列表.insert(下标, 数据) # 在指定的下标位置添加数据,如果指定的下标位置本来有数据, 原数据会后移
- 返回: 返回的 None(关键字,空), ⼀般就不再使⽤ 变量 来保存返回的内容
- 想要查看添加后的列表,需要打印的是列表
- 列表合并
- 列表1.extend(列表2) # 将列表 2 中的所有数据逐个添加的列表1 的尾部
- 返回: 返回的 None(关键字,空), ⼀般就不再使⽤ 变量 来保存返回的内容
- 想要查看添加后的列表,需要打印的是列表
my_list = [] print(my_list) # [] # 1. 想列表中添加数据 郭德纲 my_list.append('郭德纲') print(my_list) # ['郭德纲'] # 2. 向列表的尾部添加 郭麒麟 my_list.append('郭麒麟') print(my_list) # ['郭德纲', '郭麒麟'] # 3. 在下标位置为 1 的位置添加数据 '岳岳 my_list.insert(1, '岳岳') print(my_list) # ['郭德纲', '岳岳', '郭麒麟'] # 4. 在下标位置为 1 的位置添加数据 于谦 my_list.insert(1, '于谦') print(my_list) # ['郭德纲', '于谦', '岳岳', '郭麒麟'] # 5. 定义新的列表 list1 list1 = ['孙越', '烧饼'] # 将 list1 中数据逐个添加到 my_list 中 my_list.extend(list1) print(my_list) # ['郭德纲', '于谦', '岳岳', '郭麒麟','孙越', '烧饼'] # 将 list1 作为⼀个整体添加到 my_list my_list.append(list1) print(my_list) # ['郭德纲', '于谦', '岳岳', '郭麒麟','孙越', '烧饼', ['孙越', '烧饼']]
- 尾部添加
-
修改:
- 想要修改列中的指定下标位置的数据, 使⽤的语法是:
- 列表[下标] = 数据 # 字符串中字符不能使⽤下标修改
- 想要修改列中的指定下标位置的数据, 使⽤的语法是:
-
删除:
- 在列表中删除中间的数据, 那么后⾯的数据会向前移动
- 根据下标删除
- 列表.pop(下标) # 删除指定下标位置对应的数据
- 下标不写,默认删除最后⼀个数据(常⽤
- 书写存在的下标, 删除对应下标位置的数据
- 返回: 返回的删除的数据
- 根据数值删除
- 列表.remove(数据值) # 根据数据值删除
- 返回: None
- 注意: 如果要删除的数据不存在, 会报错
- 清空
- 列表.clear()
-
反转(倒置)
- 字符串中 反转倒置: 字符串[::-1]
- 列表中 反转和倒置:
- 列表[::-1] # 使⽤切⽚的⽅法,会得到⼀个新列表, 原列表不会发⽣改变
- 列表.reverse() # 直接修改原列表, 返回 None
-
复制:
- 使⽤切⽚
- 变量 = 列表[:]
- 使⽤ copy ⽅法
- 变量 = 列表.copy()
- 使⽤切⽚
-
排序:
- 列表.sort() # 按照升序排序, 从⼩到⼤
- 列表.sort(reverse=True) # 降序排序, 从⼤到⼩
- 字符⽐⼤⼩,是⽐较字符对应的 ASCII 码值
- A < Z < a < z
- ord(字符) # 获取字符对应的 ASCII 的值
- chr(ASCII 值) # 获取对应的 字符
- 字符串⽐⼤⼩:对应下标位置字符的⼤⼩, 直到⽐出⼤⼩, 如果全部⽐完了,还没有⽐出⼤⼩,就是相等
-
嵌套:
- 列表嵌套, 列表中的内容还是列表
person_info = [["张三", "18", "功能测试"], ["李四","20", "⾃动化测试"]] print(len(person_info)) # 2 print(person_info[0]) # ['张三', '18', '功能测试'] print(person_info[0][0]) # '张三' print(person_info[0][0][0]) # 张
2.2 元组
-
定义:
- 元组: tuple, 元组的特点和列表⾮常相似
- 元组中可以存放任意类型的数据
- 元组中可以存放任意多个数据
- 区别:
- 元组中的数据内容不能改变, 列表中的可以改变的
- 元组使⽤ (), 列表 使⽤ []
- 应⽤: 在函数的传参或者返回值中使⽤, 保证数据不会被修改
- 定义方式:
- 类实例化 : my_tuple = tuple()
- 直接() : my_tuple = ()
- 元组: tuple, 元组的特点和列表⾮常相似
-
方法:
-
-
在元组中也可以使⽤ 下标和切⽚获取数据
-
在元组中存在 index ⽅法, 查找下标, 如果不存在,会报错
-
在元组中存在 count ⽅法, 统计数据出现的次数
-
在元组中可以使⽤ in 操作, 判断数据是否存在
-
len() 统计个数
-
-
以上⽅法的使⽤ 和列表中⼀样的
# 1, 类实例化的⽅式 # 1.1 定义空元祖(不会使⽤的) my_tuple1 = tuple() print(type(my_tuple1), my_tuple1) # <class 'tuple'>() # 1.2 类型转换 # 可以将列表转换为元组, 只需要将 [], 变为 (), 同时 可以将元组转换列表 , 将() 变为 [] my_tuple2 = tuple([1, 2, 3]) print(my_tuple2) # (1, 2, 3) # 转换字符串, 和列表中⼀样,只是将列表的[] 变为() my_tuple3 = tuple('hello') print(my_tuple3) # ('h', 'e', 'l', 'l', 'o') # 2. 直接使⽤ () 定义 my_tuple4 = (1, "⼩王", 3.14, False) print(my_tuple4) # 3. 特殊点, 定义只有⼀个数据的元组时, 数据后边必须有⼀个逗号 my_tuple5 = (1,) print(my_tuple5) # (1,) print(my_tuple4[1]) # ⼩王
-
2.3 字典
-
定义:
-
-
字典 dict, 字典中的数据是由键(key)值(value)对组成的
(键表示数据的名字, 值就是具体的数据)
-
在字典中⼀组键值对是⼀个数据, 多个键值对之间使⽤ 逗号隔开
变量 = {key: value, key:value, …}
-
⼀个字典中的键是唯⼀的,不能重复的, 值可以是任意数据
-
字典中的键 ⼀般都是 字符串,可以是数字, 不能是列表
-
-
定义方式:
-
- 类实例化
- {}定义
-
# 1. 使⽤ 类实例化的⽅法 my_dict = dict() print(type(my_dict), my_dict) # <class 'dict'> {} # dict() 不能转列表和元组,字符串 # 2. 直接使⽤{} 定义 # 2.1 空字典 my_dict1 = {} print(type(my_dict1), my_dict1) # <class 'dict'> {} # 2.2 ⾮空字典, ⼩明('name') 18('age') 1.71('height')True(is_men) 抽烟 喝酒 烫头('like') my_dict2 = {"name": "⼩明", "age": 18, "height":1.71, "is_men": True, "like": ["抽烟", "喝酒", "烫头"]} print(my_dict2) print(len(my_dict2)) # 5
-
-
增加,修改字典
- 语法:
- 字典[键] = 数据值
- 如果键已经存在,就是修改数据值
- 如果键不存在,就是添加数据(即添加键值对)
- 语法:
-
删除:
- 删除指定键值对
- del 字典[键]
- 字典.pop(键) # 键必须书写
- 清空
- 字典.clear()
- 删除指定键值对
-
查询:
- 使用 字典[键]
- 字典[键]
- 如果键存在 返回键对应的数据值
- 如果键不存在, 会报错
- 字典[键]
- 使用 字典.get(键)
- 字典.get(键, 数据值)
- 数据值⼀般不写, 默认是 None
- 返回:
- 如果键存在 返回键对应的数据值
- 如果键不存在, 返回的是 括号中书写的数据值(None)
- ⼀般建议使⽤ get ⽅法
- 字典.get(键, 数据值)
- 使用 字典[键]
-
遍历:
- 对键遍历
- for 变量 in 字典: # 变量就是字典的 key, 键
- for 变量 in 字典.keys(): # 字典.keys() 可以获取字典中所有的键
- 对值遍历
- for 变量 in 字典.values(): # 字典.values() 可以获取字典中所有的值
- 对键值对遍历
- # 变量1 就是 键, 变量2 就是键对应的值
- for 变量1, 变量2 in 字典.items(): # 字典.items() 获取键值对
# 1. 字符串, 列表, 元组 ⽀持加法运算
str1 = ‘hello’ + ’ world’ # ‘hello world’
list1 = [1, 2] + [3, 4] # [1, 2, 3, 4]
tuple1 = (1, 2) + (3, 4) # (1, 2, 3, 4)
# 2. 字符串 列表 元组 ⽀持 乘⼀个数字
'hello ’ * 3 # ===> 'hello hello hello ’
[1, 2] * 3 # ===> [1, 2, 1, 2, 1, 2]
(1, 2) * 3 # ===> (1, 2, 1, 2, 1, 2)
# 3. len() 在 容器中都可以使⽤
# 4. in 关键字在容器中都可以使⽤, 注意, 在字典中判断的是字典的键是否存在
列表去重:列表中存在多个数据, 需求, 去除列表中重复的数据.
⽅式1. 思路
遍历原列表中的数据判断在新列表中是否存在, 如果存在,不管,
如果不存在放⼊新的列表中
遍历: for 循环实现
判断是否存在: 可以 使⽤ in
存⼊数据: append()
⽅法 2:
在 Python 中还有⼀种数据类型(容器) ,称为是 集合(set)
特点: 集合中不能有重复的数据(如果有重复的数据会⾃动去重)可以使⽤集合的特点对列表去重
\1. 使⽤ set() 类型转换将列表转换为 集合类型
\2. 再使⽤ list() 类型转换将集合 转换为列表
缺点: 不能保证数据在原列表中出现的顺序(⼀般来说,也不考虑这件事)
- 对键遍历
2.4 集合
-
概念:用来保存不重复的元素,即集合中的元素都是唯一的,无序的,互不相同。
-
创建方式:
- 1.set()函数
- setname = set(iteration)
- iteration 就表示字符串、列表、元组、range 对象等数据。
- 2.{}
- setname = {element1, element2, … , elementn}
- 如果要创建空集合,只能使用
set() 函数
实现。因为直接使用一对{}
,Python 解释器会将其视为一个空字典。 - 同一集合中,只能存储不可变的数据类型,包括整形、浮点型、字符串、元组,
无法存储
列表、字典、集合这些可变的数据类型
- 1.set()函数
-
访问方式:
- 集合中元素是无序的,一般使用循环结构遍历
-
删除集合:del()
-
添加元素:setname.add(element)
-
删除元素:setname.remove(element)
-
运算:
-
有 2 个集合,分别为 set1={1,2,3} 和 set2={3,4,5},它们既有相同的元素,也有不同的元素。以这两个集合为例,分别做不同运算的结果如下表所示。
运算操作 Python运算符 含义 例子 交集 & 取两集合公共的元素 >>> set1 & set2 {3} 并集 | 取两集合全部的元素 >>> set1 | set2 {1,2,3,4,5} 差集 - 取一个集合中另一集合没有的元素 >>> set1 - set2 {1,2} 对称差集 ^ 取集合 A 和 B 中不属于 A&B 的元素 >>> set1 ^ set2 {1,2,4,5}
-
3.面向对象
3.1 函数
-
概念:
- 函数,就是把 具有独⽴功能的代码块 组织为⼀个⼩模块,在需要的时候调⽤
- 函数好处: 减少代码的冗余(重复的代码不⽤多写), 提⾼程序的编写效率
-
定义:
- 将多⾏代码放在⼀块,起名字的过程, 称为函数定义
- 函数必须先定义后调⽤
-
语法:
def 函数名(): 函数中的代码 函数中的代码 # 1. def 是关键字, ⽤来定义函数的 define 的缩写 # 2. 函数名需要遵守标识符的规则 # 3. 处于 def 缩进中的代码,称为函数体 # 4. 函数定义的时候, 函数体中的代码不会执⾏, 在调⽤的时候才会执⾏ 函数名() # 1. 函数调⽤的时候会执⾏函数体中代码 # 2. 函数调⽤的代码,要写在 函数体外边
-
文档注释:
-
-
书写位置, 在函数名的下⽅使⽤ 三对双引号进⾏的注释
-
作⽤: 告诉别⼈这个函数如何使⽤的, ⼲什么的
-
查看, 在调⽤的时候, 将光标放到函数名上,使⽤快捷键
-
-
-
函数嵌套调用:
- 在⼀个函数定义中调⽤另⼀个函数
- 函数定义不会执⾏函数体中的代码
- 函数调⽤会执⾏函数体中的代码
- 函数体中代码执⾏结束会回到函数被调⽤的地⽅继续向下执⾏
- 在⼀个函数定义中调⽤另⼀个函数
-
返回值:
-
在函数中想要将⼀个数据作为返回值 返回, 需要使⽤ return关键字(只能在函数中使⽤)
-
作⽤:
- 将数据值作为返回值返回
- 函数代码执⾏遇到 return, 会结束函数的执⾏
- 将 多个数据值组成容器进⾏返回, ⼀般是元组(组包)
def 函数名(): # 返回值 None pass # 代码中没有 return def 函数名(): return # return 后边没有数据, 返回值 None def 函数名(): return xx # 返回值是 xx
-
-
变量引用
-
-
在定义变量的时候 变量 = 数据值, Python 解释器会在内存中开辟两块空间
-
变量和数据都有⾃⼰的空间
-
⽇常简单理解, 将数据保存到变量的内存中, 本质是 将 数据的地址保存到变量对应的内存中
-
变量中存储数据地址的⾏为 就是引⽤ (变量引⽤了数据的地址, 简单说就是变量中存储数据), 存储的地址称为 引⽤地址
-
可以使⽤ id() 来获取变量中的引⽤地址(即数据的地址),如果两个变量的 id() 获取的引⽤地址⼀样, 即代表着, 两个变量引⽤了同⼀个数据,是同⼀个数据
-
只有 赋值运算符=, 可以改变变量的引⽤(等号左边数据的引⽤)
-
python 中数据的传递,都是传递的引⽤
-
-
-
可变类型和不可变类型:
- 概念:数据所在的内存是否允许修改, 允许修改就是可变类型, 不允许修改就是不可变类型
- 可变类型:列表 list, 字典 dict, 集合 set
- 不可变类型:int float bool str tuple
-
组包和拆包:
- 组包(pack): 将多个数据值使⽤逗号连接, 组成元组
- 拆包(unpack): 将容器中的数据值使⽤多个变量分别保存的过程,注意: 变量的个数和容器中数据的个数要保持⼀致
- 赋值运算符, 都是先执⾏等号右边的代码, 执⾏的结果,保存到等号左边的变量中
# 组包 c = b, a # 组包 print(type(c), c) # <class 'tuple'> (10, 20) # 拆包 a, b = c print(a, b) x, y, z = [1, 2, 3] print(x, y, z)
-
局部变量和全局变量:
- 局部变量:
- 在函数内部(函数的缩进中)定义的变量,称为是局部变量
- 特点:
- 局部变量只能在当前函数内部使⽤, 不能在其他函数和函数外部使⽤
- 在不同函数中,可以定义名字相同的局部变量, 两者之间没有影响
- ⽣存周期(⽣命周期, 作⽤范围)–> 在哪 能⽤在函数被调⽤的时候,局部变量被创建, 函数调⽤结束, 局部变量的值被销毁(删除), 不能使⽤
- 所以函数中的局部变量的值, 如果想要在函数外部使⽤, 需要使⽤ return 关键字, 将这个值进⾏返回
- 全局变量:
- 定义位置: 在函数外部定义的变量, 称为是 全局变量
- 特点:
- 可以在任何函数中读取(获取) 全局变量的值
- 如何在函数中存在和全局变量名字相同的局部变量, 在函数中使⽤的是 局部变量的值(就近)
- 在函数内部想要修改全局变量的引⽤(数据值), 需要添加global 关键字, 对变量进⾏声明为全局变量
- ⽣命周期: 代码执⾏的时候被创建, 代码执⾏结束,被销毁(删除)
- 局部变量:
-
函数参数:
- 位置传参:在函数调⽤的时候, 按照形参的顺序, 将实参值传递给形参
- 关键字传参:在函数调⽤的时候, 指定数据值给到那个形参
- 混合使用:
- 关键字传参必须写在位置传参的后⾯
- 不要给⼀个形参传递多个数据值
def func(a, b, c): print(f'a: {a}, b: {b}, c: {c}') # 位置传参 func(1, 2, 3) # 关键字传参 func(a=2, b=3, c=1) # 混合使⽤ func(1, 3, c=5)
-
缺省参数(默认参数:
- 定义⽅式
- 在函数定义的时候, 给形参⼀个默认的数据值, 这个形参就变为缺省参数, 注意, 缺省参数的书写要放在普通参数的后边
- 特点(好处)
- 缺省参数, 在函数调⽤的时候, 可以传递实参值, 也可以不传递实参值
- 如果传参,使⽤的就是传递的实参值, 如果不传参,使⽤的就是默认值
def show_info(name, sex='保密'): print(name, sex) show_info('⼩王') show_info('⼩王', '男')
- 定义⽅式
-
多值参数:
- 不定长位置参数(元组
- 书写, 在普通参数的前边,加上⼀个 *, 这个参数就变为不定⻓位置参数
- 特点, 这个形参可以接收任意多个 位置传参的数据
- 数据类型, 形参的类型是 元组
- 注意, 不定⻓位置参数 要写在普通的参数的后⾯
- ⼀般写法, 不定⻓位置参数的名字为 args, 即(*args) # arguments
- 不定长关键字参数(字典
- 书写, 在普通参数的前边,加上 两个 *, 这个参数就变为不定⻓关键字参数
- 特点, 这个形参可以接收任意多个 关键字传参的数据
- 数据类型, 形参的类型是 字典
- 注意, 不定⻓关键字参数,要写在所有参数的最后边
- ⼀般写法, 不定⻓关键字参数的名字为 kwargs,即(**kwargs), keyword arguments
def 函数名(普通函数, *args, 缺省参数, **kwargs): pass # ⼀般在使⽤的时候, 使⽤ 1-2种, 按照这个顺序挑选书写即可 def func(*args, **kwargs): print(type(args), args) print(type(kwargs), kwargs) print('-' * 30) func() func(1, 2, 3) # 位置传参, 数据都给 args func(a=1, b=2, c=3) # 关键字传参, 数据都给 kwargs func(1, 2, 3, a=4, b=5, c=6)
- 不定长位置参数(元组
-
匿名函数:
- 概念:就是使⽤ lambda 关键字定义的函数
- ⼀般称为使⽤def 关键字定义的函数为, 标准函数
- 特点:
- 匿名函数只能书写⼀⾏代码
- 匿名函数的返回值不需要 return, ⼀⾏代码(表达式) 的结果就是返回值
- 使⽤场景: 作为函数的参数, 这个函数⽐较简单,值使⽤⼀次,没有必要使⽤ def 定义
- 语法:
- lambda 参数: ⼀⾏代码 # 这⼀⾏代码,称为是表达式
- 变量 = lambda 参数: ⼀⾏代码 #使用变量进行调用变量()
- 概念:就是使⽤ lambda 关键字定义的函数
3.2 面向对象
-
⾯向对象是⼀个编程思想(写代码的套路)
-
编程思想:
- ⾯向过程
- 关注的是 具体步骤的实现, 所有的功能都⾃⼰书写,亲⼒亲为
- 定义⼀个个函数, 最终按照顺序调⽤函数
- ⾯向对象
- 关注的是结果, 谁(对象) 能帮我做这件事偷懒
- 找⼀个对象(), 让对象去做
- ⾯向过程
-
类和对象:
- 类
- 抽象的概念, 对 多个 特征和⾏为相同或者相似事物的统称
- 泛指的(指代多个,⽽不是具体的⼀个)
- 对象
- 具体存在的⼀个事物, 看得⻅摸得着的
- 特指的,(指代⼀个)
- 类
-
类的组成:
- 类名 (给这多个事物起⼀个名字, 在代码中 满⾜⼤驼峰命名法(每个单词的⾸字⺟⼤写))
- 属性 (事物的特征, 即有什么, ⼀般⽂字中的名词)
- ⽅法 (事物的⾏为, 即做什么事, ⼀般是动词)
-
面向对象基本代码:
-
1.定义类:
class 类名: # 在缩进中书写的内容,都是类中的代码 def ⽅法名(self): # 就是⼀个⽅法 pass
-
2.创建对象
类名() # 创建⼀个对象, 这个对象在后续不能使⽤ # 创建的对象想要在后续的代码中继续使⽤, 需要使⽤⼀个变量,将这个对象保存起来 变量 = 类名() # 这个变量中保存的是对象的地址, ⼀般可以成为这个变量为对象 # ⼀个类可以创建多个对象, 只要出现 类名() 就是创建⼀个对象,每个对象的地址是不⼀样的
-
示例代码:
class Cat: # 在缩进中书写 ⽅法 def eat(self): # self 会⾃动出现,暂不管 print('⼩猫爱吃⻥...') def drink(self): print('⼩猫要喝⽔----') # 2. 创建对象 blue_cat = Cat() # 3. 通过对象调⽤类中的⽅法 blue_cat.eat() blue_cat.drink() # 创建对象 black_cat = Cat() black_cat.eat() black_cat.drink() Cat() # 是 a = black_cat # 不是 b = Cat # 不是 -----self------- 1. 从函数的语法上讲, self是形参, 就可以是任意的变量名,只不过我们习惯性将这个形参写作 self 2. self 是普通的形参, 但是在调⽤的时候没有传递实参值,原因是, Python 解释器在执⾏代码的时候, ⾃动的将调⽤这个⽅法的对象 传递给了 self, 即 self 的本质是对象 3. 验证, 只需要确定 通过哪个对象调⽤, 对象的引⽤和 self的引⽤是⼀样的 4. self 是函数中的局部变量, 直接创建的对象是全局变量 //有点像this,指代当前对象
-
-
对象属性操作:
- 添加属性:对象.属性名 = 属性值
- 类内部添加:
- self.属性名 = 属性值
- 在类中添加属性⼀般写在 init ⽅法中
- 类外部添加:
- 对象.属性名 = 属性值 # ⼀般不使⽤
- 类内部添加:
- 获取属性:对象.属性名
- 类内部:
- self.属性名
- 类外部:
- 对象.属性名 # ⼀般很少使⽤
- 类内部:
- 添加属性:对象.属性名 = 属性值
3.3 魔法方法
-
概念:
- python 中有⼀类⽅法, 以两个下划线开头,两个下划线结尾,并且在满⾜某个条件的情况下, 会⾃动调⽤, 这类⽅法称为 魔法方法
-
_init_ ⽅法:
- 创建对象之后会⾃动调⽤
- 给对象添加属性的, (初始化⽅法, 构造⽅法)
- 某些代码, 在每次创建对象之后, 都要执⾏,就可以将这⾏代码写在 init ⽅法
- 如果 init ⽅法中,存在除了 self之外的参数, 在创建对象的时候必须传参
class Cat: # 定义添加属性的⽅法 def __init__(self, name, age): # 这个⽅法是创建对象之后调⽤ self.name = name # 给对象添加 name 属性 self.age = age # 给对象添加 age 属性 # 输出属性信息 def show_info(self): print(f'⼩猫的名字是: {self.name}, 年龄是:{self.age}') # 创建对象,不要在⾃⼰类缩进中创建 # Cat() # 创建对象 ,会输出 blue_cat = Cat('蓝猫', 2) blue = blue_cat blue.show_info() # 创建⿊猫 black_cat = Cat('⿊猫', 3) black_cat.show_info()
-
__str__方法
- 使⽤ print(对象) 打印对象的时候 会⾃动调⽤
- 在这个⽅法中⼀般书写对象的 属性信息的, 即打印对象的时候想要查看什么信息,在这个⽅法中进⾏定义的
- 如果类中没有定义 str ⽅法, print(对象) ,默认输出对象的引⽤地址
- 这个⽅法必须返回 ⼀个字符串
class Cat: # 定义添加属性的⽅法 def __init__(self, n, age): # 这个⽅法是创建对象之后调⽤ self.name = n # 给对象添加 name 属性 self.age = age # 给对象添加 age 属性 def __str__(self): # ⽅法必须返回⼀个字符串, 只要是字符串就⾏, return f'⼩猫的名字是: {self.name}, 年龄是:{self.age}' # 创建对象,不要在⾃⼰类缩进中创建 # Cat() # 创建对象 ,会输出 blue_cat = Cat('蓝猫', 2) print(blue_cat) # 创建⿊猫 black_cat = Cat('⿊猫', 3) print(black_cat)
-
__del__方法
- _init_ ⽅法, 创建对象之后,会⾃动调⽤ (构造⽅法)
- _del_ ⽅法, 对象被删除销毁时, ⾃动调⽤的(遗⾔, 处理后事) (析构⽅法)
- 调⽤场景, 程序代码运⾏结束, 所有对象都被销毁
- 调⽤场景, 直接使⽤ del 删除对象(如果对象有多个名字(多个对象引⽤⼀个对象),需要吧所有的对象都删除才⾏ )
3.4 封装继承多态
-
私有和公有
-
在 Python 中定义的方法和属性, 可以添加访问控制权限(即在什么地方可以使用这个属性和方法)
-
访问控制权限分为两种, 公有权限, 私有权限
-
公有权限
- 直接书写的方法和属性, 都是公有的
- 公有的方法和属性, 可以在任意地方访问和使用
-
私有权限
- 在类内部, 属性名或者方法名 前边加上两个 划线 , 这个属性或者方法 就变为 私有的
- 私有的方法和属性, 只能在当前类的内部使用
-
什么时候定义私有
-
某个属性或者方法,不想在类外部被访问和使用, 就将其定义为私有即可
-
测试中,一般不怎么使用, 直接公有即可
-
开发中,会根据需求文档, 确定什么作为私有
-
-
如果想要在类外部操作私有属性, 方法是, 在类内部定义公有的方法, 我们通过这个公有方法去操作
# 补充:
# 对象.dict 魔法属性, 可以将对象具有的属性组成字典返回
class Person: def __init__(self, name, age): self.name = name # 姓名 # 私有的本质, 是 Python 解释器执行代码,发现属性名或者方法名前有两个_, 会将这个名字重命名 # 会在这个名字的前边加上 _类名前缀,即 self.__age ===> self._Person__age self.__age = age # 年龄, 将其定义为私有属性, 属性名前加上两个 _ def __str__(self): # 在类内部可以访问私有属性的 return f'名字: {self.name}, 年龄: {self.__age}' xm = Person('小明', 18) print(xm) # 在类外部直接访问 age 属性 # print(xm.__age) # 会报错, 在类外部不能直接使用私有属性 # 直接修改 age 属性 xm.__age = 20 # 这个不是修改私有属性, 是添加了一个公有的属性 __age print(xm) # 名字: 小明, 年龄: 18 print(xm._Person__age) # 能用但是不要用 18 xm._Person__age = 19 print(xm) # 名字: 小明, 年龄: 19
-
-
继承:
-
-
继承描述的是类与类之间的关系
-
继承的好处: 减少代码的冗余(相同的代码不需要多次重复书写), 可以直接使用
# class A(object): class A: # 没有写父类,但也有父类, object, object 类是 Python 中最顶级(原始)的类 pass class B(A): # 类 B, 继承类 A pass ------------- 术语: 1. A 类, 称为是 父类(基类) 2. B 类, 称为是 子类(派生类) 单继承: 一个类只继承一个父类,称为单继承 继承之后的特点: > 子类(B)继承父类(A)之后, 子类的对象可以直接使用父类中定义的公有属性和方法
-
-
-
重写:
-
重写: 在子类中定义了和父类中名字相同的方法, 就是重写
-
重写的原因: 父类中的方法,不能满足子类对象的需求,所以重写
-
重写之后的特点: 调用子类字节的方法, 不再调用父类中的方法
-
重写的方式:
-
覆盖(父类中功能完全抛弃,不要,重写书写)
- 直接在子类中 定义和父类中名字相同的方法
- 直接在方法中书写新的代码
-
扩展(父类中功能还调用,只是添加一些新的功能) (使用较多)
- 直接在子类中 定义和父类中名字相同的方法
- 在合适的地方调用 父类中方法 super().方法()
- 书写添加的新功能
-
-
-
多态:
-
-
是一种写代码,调用的一种技巧
-
同一个方法, 传入不同的对象, 执行得到不同的结果, 这种现象称为是多态
-
多态 可以 增加代码的灵活度
--------
哪个对象调用方法, 就去自己的类中去查找这个方法, 找不到去父类找
-
-
-
对象划分:
-
实例对象:
-
-
通过 类名() 创建的对象, 我们称为实例对象,简称实例
-
创建对象的过程称为是类的实例化
-
我们平时所说的对象就是指 实例对象(实例)
-
每个实例对象, 都有自己的内存空间, 在自己的内存空间中保存自己的属性(实例属性)
-
-
类对象:
-
-
类对象 就是 类, 或者可以认为是 类名
-
类对象是 Python 解释器在执行代码的过程中 创建的
-
类对象的作用: ① 使用类对象创建实例 类名(), ② 类对象 也有自己的内存空间, 可以保存一些属性值信息(类属性)
-
在一个代码中, 一个类 只有一份内存空间
-
-
-
属性划分:
- 实例属性:是实例对象 具有的属性
- 定义使用:
- 在 init 方法中, 使用 self.属性名 = 属性值 定义
- 在方法中是 使用 self.属性名 来获取(调用)
- 定义使用:
- 类属性:是 类对象 具有的属性
- 定义使用:
- 在类内部,方法外部,直接定义的变量 ,就是类属性
- 使用: 类对象.属性名 = 属性值 or 类名.属性名 = 属性值
- 类对象.属性名 or 类名.属性名
- 定义使用:
- 实例属性:是实例对象 具有的属性
-
方法划分:
-
实例方法:
-
定义:
# 在类中直接定义的方法 就是 实例方法 class Demo: def func(self): # 参数一般写作 self,表示的是实例对象 pass # 如果在方法中需要使用实例属性(即需要使用 self), 则这个方法必须定义为 实例方法
-
调用:对象.方法名() #不用给self参
-
-
类方法:
-
定义:
# 在方法名字的上方书写 @classmethod 装饰器(使用 @classmethod 装饰的方法) class Demo: @classmethod def func(cls): # 参数一般写作 cls, 表示的是类对象(即类名) class pass
-
调用:
- 类名.方法名()
- 实例.方法名()
-
-
静态方法(基本不用:
-
定义:
# 在方法名字的上方书写 @staticmethod 装饰器(使用 @staticmethod 装饰的方法) class Demo: @staticmethod def func(): # 一般没有参数 pass
-
调用:
-
# 1. 通过类对象调用
类名.方法名()
# 2. 通过实例对象调用
实例.方法名()
-
-
-
-
补充:
- is 可以用来判断两个对象是不是同一个对象,即 两个对象的引用是否相同
- a is b === > id(a) == id(b)
- is 和 == 的区别?
- == 只判断数据值是否相同, is 判断引用是否相同
- is 可以用来判断两个对象是不是同一个对象,即 两个对象的引用是否相同
4.文件
4.1 普通文件
-
文件分类:
- 文本文件
- 能够使⽤记事本软件打开(能够使⽤记事本转换为⽂字)
- txt, md, py , html, css, js , json
- 二进制文件
- 不能使⽤记事本软件打开的
- exe, mp3, mp4, jpg, png
- 文本文件
-
文件操作:
-
-
打开⽂件
-
读或者写⽂件
-
关闭⽂件
-
-
-
打开文件
- 打开⽂件: 将⽂件从磁盘(硬盘) 中 读取到内存中
- 语法:open(file, mode=‘r’, encoding=None)
- 参数 file: 是要打开的⽂件, 类型是字符串, ⽂件的路径可以是相对路径,也可以是绝对路径(从根⽬录开始书写的路径),建议使⽤相对路径(相对于当前代码⽂件所在的路径, ./…/ )
- 参数 mode: 默认参数(缺省参数), 表示的是打开⽂件的⽅式
- r: read 只读打开
- w: write 只写打开
- a: append 追加打开, 在⽂件的末尾写⼊内容
- 参数 encoding: 编码⽅式,(⽂字和⼆进制如何进⾏转换的)
- gbk: 将⼀个汉字转换为 2 个字节⼆进制
- utf-8: 常⽤, 将⼀个汉字转换为 3 个字节的⼆进制
- 返回值: 返回的是 ⽂件对象, 后续对⽂件的操作,都需要这个对象
-
读或写文件
- 写文件:
- 向⽂件中写⼊指定的内容。前提: ⽂件的打开⽅式是 w 或者 a
- ⽂件对象.write(‘写⼊⽂件的内容’)
- 返回值: 写⼊⽂件的字符数,⼀般不关注
- 注意 w ⽅式打开⽂件:
- ⽂件不存在,会直接创建⽂件
- ⽂件存在,会覆盖原⽂件(将原⽂件中的内容清空)
- 读文件:
- 将⽂件中的内容读取出来,前提: ⽂件的打开⽅式需要是 r
- ⽂件对象.read(n)
- 参数 n 表示读取多少个字符, ⼀般不写,表示读取全部内容
- 返回值: 读取到的⽂件内容, 类型 字符串
- 写文件:
-
关闭文件
- 关闭⽂件: 将⽂件占⽤的资源进⾏清理,同时会保存⽂件, ⽂件关闭之后,这个⽂件对象就不能使⽤了
- ⽂件对象.close()
-
with open打开文件
-
with open() 打开⽂件的好处: 不⽤⾃⼰去书写关闭⽂件的代码, 会⾃动进⾏关闭
-
with open(file, mode, encoding=‘utf-8’) as 变量:
# 在缩进中去读取或者写⼊⽂件
# 缩进中的代码执⾏结束, 出缩进之后, ⽂件会⾃动关闭
-
-
按行读取文件内容
- 按⾏读取⽂件: ⼀次读取⼀⾏内容
- ⽂件对象.readline()
# read() 和 readline() 读到⽂件末尾, 返回⼀个空字符串,即⻓度为 0 # 在容器中 , 容器为空,即容器中的数据的个数为 0 ,表示False, 其余情况都是 True with open('b.txt', encoding='utf-8') as f: while True: buf = f.readline() if len(buf) == 0: break else: print(buf, end='')
4.2 json文件
-
基本介绍:
-
json 基于⽂本,独⽴于语⾔的轻量级的数据交换格式
- 基于⽂本, 是⼀个⽂本⽂件, 不能包含图⽚,⾳视频等
- 独⽴于语⾔, 不是某个语⾔特有的, 每种编程语⾔都可以使⽤
的
- 轻量级, 相同的数据, 和其他格式相⽐,占⽤的⼤⼩⽐较⼩
- 数据交换格式, 后端程序员 给前端的数据 (json, html,xml)
-
-
json文件语法:
-
-
json ⽂件的后缀是 .json
-
json 中主要数据类型为 对象({} 类似 Python 中 字典)和 数组([], 类似 Python 中的列表), 对象和 数组可以互相嵌套
-
⼀个json ⽂件是⼀个 对象或者数组(即 json ⽂件的最外层要么是⼀个 {}, 要么是⼀个 数组 [])
-
json 中的对象是由键值对组成的, 每个数据之间使⽤ 逗号隔开,但是最后⼀个数据后边不要写逗号
-
json 中的字符串 必须使⽤ 双引号
-
json 中的其他数据类型
> 数字类型 ----> int float
> 字符串 string —> str
> 布尔类型 true, false -----> True, False
> 空类型 null ----> None
-
-
-
json文件书写:
-
我叫⼩明,我今年 18 岁,性别男, 爱好 听歌, 游戏,购物,吃饭,睡觉,打⾖⾖,我的居住地址为 国家中国, 城市上海
{ "name": "⼩明", "age": 18, "isMen": true, "like": [ "听歌", "游戏", "购物", "吃饭", "睡觉", "打⾖⾖" ], "address": { "country": "中国", "city": "上海" } }
-
-
python读取json文件
-
-
导包 import json
-
读打开⽂件
-
读⽂件
json.load(⽂件对象)
# 返回的是 字典(⽂件中是对象)或者列表(⽂件中是数组)
# 1, 导⼊ json import json # 2, 读打开⽂件 with open('info.json', encoding='utf-8') as f: # 3. 读取⽂件 result = json.load(f) print(type(result)) # <class 'dict'> # 姓名 print(result.get('name')) # 年龄 print(result.get('age')) # 城市 print(result.get('address').get('city'))
-
-
-
json写入文件
-
⽂件对象.write(字符串) 不能直接将 Python 的列表 和字典作为参数传递
-
想要将 Python 中的数据类型存为 json ⽂件, 需要使⽤ json提供的⽅法, 不再使⽤ write
-
步骤:
-
导包 import json
-
写(w) ⽅式打开⽂件
-
写⼊ json.dump(Python 中的数据类型, ⽂件对象)
-
import json my_list = [('admin', '123456', '登录成功'), ('root','123456', '登录失败'), ('admin', '123123', '登录失败')] with open('info4.json', 'w', encoding='utf-8') as f: # json.dump(my_list, f) # json.dump(my_list, f, ensure_ascii=False) #直接显示中⽂,不以 ASCII 的⽅式显示 # 显示缩进 # json.dump(my_list, f, ensure_ascii=False,indent=2) json.dump(my_list, f, ensure_ascii=False,indent=4)
-
5.异常
-
异常捕获基本语法:
try: 书写可能发⽣异常的代码 except: # 任何类型的异常都能捕获 发⽣了异常执⾏的代码 try: 书写可能发⽣异常的代码 except 异常类型: # 只能捕获指定类型的异常, 如果不是这个异常,还是会报错 发⽣了异常执⾏的代码 ------------------------ try: 书写可能发⽣异常的代码 except 异常类型1: # 只能捕获指定类型的异常, 如果不是这个异常,还是会报错 发⽣了异常1执⾏的代码 except 异常类型2: 发⽣了异常2执⾏的代码 except 异常类型...: 发⽣了异常...执⾏的代码 ----------------- try: 可能发⽣异常的代码 except 异常类型1: 发⽣异常类型1执⾏的代码 # Exception 是常⻅异常类的⽗类, 这⾥书写 Exception,可以捕获常⻅的所有异常, as 变量, 这个变量是⼀个异常类的对象, print(变量) 可以打印异常信息 except Exception as 变量: 发⽣其他类型的异常,执⾏的代码 else: 没有发⽣异常会执⾏的代码 finally: 不管有没有发⽣异常,都会执⾏的代码
-
模块和包
-
导入方式
-
import 模块名
# 使⽤模块中的内容
模块名.⼯具名
-
from 模块名 import ⼯具名
# 使⽤
⼯具名 # 如果是函数和类需要加括号
-
from 模块名 import * # 将模块中所有的内容都导⼊
-
-
对于导⼊的模块和⼯具可以使⽤ as 关键字给其起别名,注意: 如果起别名,原来的名字就不能⽤了, 只能使⽤别名
-
模块查找顺序:当前目录-》系统目录
-
-
__name__作用
-
每个代码⽂件都是⼀个模块,在导⼊模块的时候, 会执⾏模块中的代码(三种⽅法都会)
-
_name_ 变量 是 python 解释器⾃动维护的变量
-
__name__ 变量,如果代码是直接运⾏, 值是 “__main__”
-
_name_ 变量, 如果代码是被导⼊执⾏, 值是 模块名(即代码⽂件名)
在代码⽂件中, 在被导⼊时不想被执⾏的代码,可以写在 if__name__ == “__main__”: 代码的缩进中
-
6.Unittest
6.1 Unitttest
-
概念:UnitTest是Python⾃带的⼀个单元测试框架,⽤它来做单元测试。
-
优点:
-
-
能够组织多个⽤例去执⾏
-
提供丰富的断⾔⽅法(让程序代码代替⼈⼯⾃动的判断预期结果和实际结果是否相符)
-
能够⽣成测试报告
-
-
-
组成部分
- TestCase(最核⼼的模块)
- TestCase(测试⽤例), 注意这个测试⽤例是 unittest 框架的组成部分
- 主要作⽤: 每个 TestCase(测试⽤例) 都是⼀个代码⽂件, 在这个代码⽂件中 来书写真正的⽤例代码
- TestSuite
- TestSuite(测试套件), ⽤来 管理 组装(打包)多个TestCase(测试⽤例) 的
- TestRunner
- TestRunner(测试执⾏,测试运⾏), ⽤来 执⾏TestSuite(测试套件)的
- TestLoader
- TestLoader(测试加载), 功能是对 TestSuite(测试套件) 功能的补充,管理 组装(打包)多个 TestCase(测试⽤例) 的
- Fixture
- Fixture(测试夹具), 书写在 TestCase(测试⽤例) 代码中, 是⼀个代码结构, 可以在每个⽅法执⾏前后都会执⾏的内容
- TestCase(最核⼼的模块)
-
TestCase(测试用例)
-
步骤:
-
- 导包(unittest)
- 自定义测试类
- 测试类中书写测试方法
- 执行用例
# 1, 导包 import unittest # 2, ⾃定义测试类, 需要继承 unittest 模块中的TestCase 类即可 class TestDemo(unittest.TestCase): # 3, 书写测试⽅法, 即 ⽤例代码. ⽬前没有真正的⽤例代码, 使⽤ print 代替 # 书写要求, 测试⽅法 必须以 test_ 开头(本质是以test 开头) def test_method1(self): print('测试⽅法 1') def test_method2(self): print('测试⽅法 2') # 4, 执⾏⽤例(⽅法) # 4.1 将光标放在 类名的后边 运⾏, 会执⾏类中的所有的测试⽅法 # 4.2 将光标放在 ⽅法名的后边 运⾏, 只执⾏当前的⽅法
-
-
-
TestSuite(测试套件) & TsetRunner(测试执行)
-
步骤:
-
-
导包(unittest)
-
实例化(创建对象)套件对象
-
使⽤套件对象添加⽤例⽅法
-
实例化运⾏对象
-
使⽤运⾏对象去执⾏套件对象
# 1. 导包(unittest) import unittest from hm_07_testcase1 import TestDemo1 from hm_07_testcase2 import TestDemo2 # 2. 实例化(创建对象)套件对象, suite = unittest.TestSuite() # 3. 使⽤套件对象添加⽤例⽅法 # ⽅式⼀, 套件对象.addTest(测试类名('⽅法名')) #建议测试类名和⽅法名直接去复制,不要⼿写 suite.addTest(TestDemo1('test_method1')) suite.addTest(TestDemo1('test_method2')) # ⽅式⼆ 将⼀个测试类中的所有⽅法进⾏添加 suite.addTest(unittest.makeSuite(TestDemo2)) # 4. 实例化运⾏对象 runner = unittest.TextTestRunner() # 5. 使⽤运⾏对象去执⾏套件对象 # 运⾏对象.run(套件对象) runner.run(suite)
-
-
-
-
TestLoader(测试加载)
-
概念:TestLoader (测试加载), 作用和 TestSuite 的作用是一样的, 对 TestSuite 功能的补充,用来组装测试用例的
-
步骤:
-
- 导包
- 实例化测试加载对象并添加用例 —> 得到的是 suite 对象
- 实例化 运行对象
- 运行对象执行套件对象
"""TestLoader 的使用""" # 1, 导包 import unittest # 2, 实例化加载对象并添加用例 # unittest.TestLoader().discover('用例所在的路径', '用例的代码文件名') # 用例所在的路径,建议使用相对路径, 用例的代码文件名可以使用 *(任意多个任意字符) 通配符 suite = unittest.TestLoader().discover('./case', '*case1.py') # 3, 实例化运行对象 # runner = unittest.TextTestRunner() # # 4, 执行 # runner.run(suite) # 可以将 3 4 步 变为一步 unittest.TextTestRunner().run(suite)
-
-
-
Fixture(测试夹具)
-
概念:在每个测试方法(用例代码)、测试类、测试模块 执行前后都会自动调用的结构
-
方法级别:
# 方法执行之前--c def setUp(self): 每个测试方法执行之前都会执行 pass # 方法执行之后--销毁 def tearDown(self): 每个测试方法执行之后都会执行 pass
-
类级别:
# 类级别的Fixture 方法, 是一个 类方法 # 类中所有方法之前 @classmethod def setUpClass(cls): pass # 类中所有方法之后 @classmethod def tearDownClass(cls): pass
-
模块级别:
# 模块级别的需要写在类的外边直接定义函数即可 # 代码文件之前 def setUpModule(): pass # 代码文件之后 def tearDownModule(): pass
-
6.2 断言
-
概念:让程序代替人工自动的判断预期结果和实际结果是否相符.
-
断言的结果有两种:
> True, 用例通过
> False, 代码抛出异常, 用例不通过
-
assertEqual:
-
self.assertEqual(预期结果, 实际结果) # 判断预期结果和实际结果是否相等
-
如果相等, 用例通过
-
如果不相等,用例不通过, 抛出异常
-
-
-
assertIn:
-
self.assertIn(预期结果, 实际结果) # 判断预期结果是否包含在实际结果中
-
包含 ,用例通过
-
不包含, 用例不通过, 抛出异常
-
-
-
参数化:
-
概念:在测试方法中, 使用 变量 来代替具体的测试数据, 然后使用传参的方法将测试数据传递给方法的变量好处: 相似的代码不需要多次书写.
-
工作中场景:
-
测试数据一般放在 json 文件中
-
使用代码读取 json 文件,提取我们想要的数据 —> [(), ()] or [[], []]
-
-
安装插件
-
unittest 框架本身是不支持 参数化, 想要使用参数化,需要安装插件来完成
- 联网安装(在 cmd 窗口安装 或者 )
pip install parameterized
-
-
参数化代码
-
-
导包 unittest/ paramaterized
-
定义测试类
-
书写测试方法(用到的测试数据使用变量代替)
-
组织测试数据并传参
-
json文件 [ { "desc": "正确的用户名和密码", "username": "admin", "password": "123456", "expect": "登录成功" }, { "desc": "错误的的用户名", "username": "root", "password": "123456", "expect": "登录失败" }, { "desc": "错误的的密码", "username": "admin", "password": "123123", "expect": "登录失败" } ] ------------------------- # 1.导包unittest/ pa import json import unittest from parameterized import parameterized from tools import login # 组织测试数据 [(), (), ()] or [[], [], []] def build_data(): with open('data.json', encoding='utf-8') as f: result = json.load(f) # [{}, {}, {}] data = [] for i in result: # i {} data.append((i.get('username'), i.get('password'), =i.get('expect'))) return data # 2. 定义测试类 class TestLogin(unittest.TestCase): # 3. 书写测试方法(用到的测试数据使用变量代替) @parameterized.expand(build_data()) def test_login(self, username, password, expect): self.assertEqual(expect, login(username, password)) # 4. 组织测试数据并传参(装饰器 @
-
-
-
跳过:
- 对于一些未完成的或者不满足测试条件的测试函数和测试类, 不想执行,可以使用跳过使用方法, 装饰器完成,代码书写在 TestCase 文件
- @unittest.skip(‘跳过原因’) # 直接将测试函数标记成跳过
- @unittest.skipIf(判断条件, ‘跳过原因’) # 根据条件判断测试函数是否跳过 , 判断条件成立, 跳过