文章目录
- 一、python 的安装
- 二、基本数据类型
- 1. 数字类型
- 2. 非数字类型
- 3. type()函数
- 三、语法的使用
- 1. 输入print
- 2. 类型的转换
- 1. 转int()类型
- 2. 转float()类型
- 3. 转str()类型
- 3.输出 print()
- 1. 基本输出
- 2. % 格式化输出
- f 字符串
- 4. if 判断
- 5.if else 判断
- 6. if elif else 判断
- 7.random 随机数
- 四、循环
- 1. while循环
- 2. for循环
- for的基本使用
- for做指定次数的循环range()
- 3. break 和 continue
- 五、容器
- 1. 字符串
- 1. 切片
- 2. 查找方法find
- 3. 替换方法replace
- 4. 拆分 split
- 5. 字符串拼接 join
- 2. 列表
- 1. 下标和切片
- 2. index()查找列表中数据下标的方法
- 3. 判断数据是否存在
- 4. 统计出现的次数
- 5. append尾部添加数据的方法
- 6. insert指定下标位置添加数据
- 7. extend列表合并
- 8. 修改操作
- 9. 删除操作
- 10.列表的反转(倒置)
- 11.列表的复制
- 12.列表的排序
- 13.列表去重
- 3. 元组
- 4. 字典
- 1. 增加和修改操作
- 2. 删除指定键值对
- 3. 根据键获取对应的值
- 4. 字典了遍历
- 容器部分总结
- 六、函数
- 1. 函数基本使用
- 2. 函数传参
- 3. 数据类型的改变
- 4. 变量值的交换
- 5. 局部变量和全局变量
- 6. 函数返回多个数据值
- 7. 函数的传参
- 缺省参数
- 不定长参数
- 8. 匿名函数 lambda
- 字典排序
- 七、面向对象
- 1. 封装
- 1. 魔法方法
- __init__方法
- __str__
- __del__
- 2. 案例
- 3. 私有和公有权限
- 2. 继承
- 1. 重写
- 3. 多态
- 4. 类方法和静态方法
- 5. 补充
- 八、文件
- 1. 文件的操作
- 1. 使用with open 打开文件(推荐)
- 2. 按行读取文件内容
- 2. json文件的处理
- 1. json文件的语法
- 2. json 文件的书写
- 3. json 文件的读取
- 案例
- 4. json 文件的写入
- 九、异常
- 1. 异常的捕获(重点)
- 2. 捕获异常的完整版本
- 3. 异常的传递(了解)
- 十、模块和包
- 1. 模块
- 1. 模块的查找顺序
- 十一、unitTest 框架
- 1. UnitTest核心要素(unitest的5大组成)
- TestCase(测试用例)
- TestSuite(测试套件) & TestRunner(测试执行)
- 登录测试案例
- TestLoader(测试加载)
- Fixture(测试夹具)
- 登录案例
- 2. 断言
- 登录案例
- 3. 参数化
- 4. 跳过
- 5. 测试报告
- 第三方测试报告 HTMLTestRunner
一、python 的安装
官网:https://www.python.org/downloads
尽量避开最新版,也不要低于3.6版本,其他任意都可。
安装后,python没有桌面快捷方式,需要在pycharm(vscode等编辑器)或者cmd中使用。
cmd中打开使用 python 文件.py
pycharm安装:https://www.jetbrains.com/pycharm/download
最后在编辑器中配置路径解释器就ok了
二、基本数据类型
1. 数字类型
- 整型(
int
),就是整数,即不带小数点的数 - 浮点型(
float
),就是小数 - 布尔类型(
bool
),只有两个值:真True
(1), 假False
(0),非0即真
True和False 都是Python 中的关键字,注意大小写
,不要写错了 - 复数类型3 + 4i,不会用的
2. 非数字类型
- 字符串:(
str
)使用引号引起来的就是字符串'name'
- 列表(
list
)[1, 2, 3,4]
- 元组(
tuple
)(1, 2, 4, 4)
- 字典(
hict
){'name': mario','age': 18}
3. type()函数
可以获取变量的数据类型
type (变量)
想要将这个变量的类型在控制台显示,需要使用print 输出
print(type(变量))
a=3
print(type(a)) # <class 'int'>
print(type('a')) # <class 'str'>
三、语法的使用
两个注释:
# 注释
''' 注释内容 xxxxx '''
快捷键补充:
复制粘贴一行:ctrl + d
快速在代码下方,新建一行:shift + 回车
1. 输入print
获取用户使用键盘录入的内容:
使用的函数是input()
语法:变量= input( '提示的信息')
- 代码从上到下执行,遇到input 函数之后,会暂停执行,等待用户的输入,如果不输入会一直等待
- 在输入的过程中,遇到回车,代表本次输入结束
- 会将你输入的内容保存到等号左边的变量中,并且变量的数据类型一定是
str
res = input('请输入你的姓名:')
# 不管输入的内容是什么,最后的类型都是 字符串str
print(type(res),res) # <class 'str'> momo
2. 类型的转换
根据代码的需要,将一种数据类型转换另一种数据类型
语法: 变量 = 要转换的类型(原数据)
1.数据原来是什么类型
2.你要转换为什么类型
注意点
:数据类型转换,不会改变原来的数据的类型,会生成一个新的数据类型
1. 转int()类型
int()将其他类型转换为int整型
1.可以将float类型的数字转换为整型
2.可以将整数类型的字符串转换为整型3 123
2. 转float()类型
float()将其他类型转换为浮点型
1.可以将int类型转换为浮点型float(3)---> 3.0
2.可以将数字类型的字符串(整数类型和小数类型)转换为浮点型
3. 转str()类型
str()将其他类型转换为字符串类型
任何类型都可以使用str()将其转换为字符串,一般都是直接加上引号
print(float(3)) # 3.0
print(int(3.52)) # 3
print(int('momo')) # 报错
3.输出 print()
1. 基本输出
输出使用的函数是 print()
函效。
作用: 将程序中的数据或者结果打印到控制台(屏幕)
print('hello python!!')
2. % 格式化输出
在字符串中指定的位置,输出变量中存储的值:
1.在需要使用变量的地方,使用特殊符号占位
2.使用变量填充占位的数据
%格式化输出占位符号
- %d:占位,填充整型数据
- %f:占位,填充浮点型数据
- %s:占位,填充字符串数据string
其实%s的占位符,可以填充任意类型的数据,但最好遵循标准的占位格式
name = input('请输入你得姓名:')
age = int(input('请输入你得年龄:'))
height = float(input('请输入你得身高:'))print('你的姓名是:%s,年龄为:%d,身高为:%.2f cm' %(name,age,height))# 补充:
# 1.小数显示默认为 6 位,如果要指定显示小数点后几位 %.nf ,n需要换成具体的数字,即保留的小数位数。# 显示学号为:0001
stu_num = 1
# 2. %0nd ,n需要换成具体的数字,表示整数一共占几位
print('我的学号ID为 %04d' %stu_num)num = 86
# 3.特殊符号用 %
print('成绩及格率为%%%d' %num)
f 字符串
1.需要在字符串的前边加上f" "
或者F" "
2.占位符号统一变为 { }
3.需要填充的变量写在{ xx }
中
name='momo'
age=19
height=1.77
stu_num = 1
num = 86# \n 为换行(转义符)
print(f'你的姓名是{name},年龄为{age},身高为{height} cm \n学号{stu_num:03d},及格率为{num}')
4. if 判断
缩进的语句都属于if判断的语句,符合判断即执行。
age = 18
if int(age) >= 18:print('符合年龄要求')print('我也属于判断句!')print('我不属于判断句,一定会执行的语句')
5.if else 判断
只会执行其中一个语句结果,else要结合if使用!
name = input('please input your name:')
pwd = input('please input your password:')if name=='admin' and pwd =='123456':print(f'欢迎回来:{name}')
else:print('错误!')
6. if elif else 判断
如果某个判断条件有多个,此时建议使用if elif else
结构来实现
1.elif也是关键字,后边和判断条件之间需要一 个空格, 判断条件之后需要冒号
2.冒号之后回车需要缩进,处在这个缩进中的的代码表示是elif 的代码块
3.在一个if判断中,可以有很多个elif
4.只有if的条件不成立,才会去判断elif的条件
5.在一个if中,如果有多个elif,只要有一个条件成立,后续的所有都不再判断
7.random 随机数
# 1. 导入随机数工具包
import random
# 2. 使用工具包中的工具产生指定范围内的数字
num = random.randint(1,10) # 产生[a, b]之间的随机整数,包含a b的
print(num)
四、循环
循环就是让指定的代码循环执行。
1. while循环
确定这行代码执行几次,如果执行多次,就放在循环的缩进中,如果只执行一次,就不要放在循环的缩进中。
while True:... if 判断条件:break # 关键字的作用就是终止循环,当代码执行遇到break ,这个循环就不再执行了if 判断条件:...
# 1.定义循环获取 1- 100之间的数字并求和
num = 0
i = 1
while i <= 100:num += ii+=1
print(num) # 5050# 2.使用循环求 1-100之间偶数的和
num = 0
i = 1
while i <= 100:if i % 2 == 0:num += i i+=1
print(num) # 2550num = 0
i = 2
while i <= 100:num += i i+=2
print(num) # 2550
2. for循环
for的基本使用
a = 'hello'for i in a:print(i)
for做指定次数的循环range()
for 变量 in range(n):...for 变量 in range(a,b):...
- range() 是Python 中的函数,作用使用可以生成[0,n)之间的整数,
range(n) 不包含n的,一个有n个数字,所以这个循环循环n次
range(a, b)作用是生成 [a, b)之间的整数数字,不包含b - 想让for循环 循环多少次,n就写几
- 变量的值也是每次循环从[0,n)取出一个值,第一次取得是0 ,最后一次取得是n-1
3. break 和 continue
这两个关键字只能在循环中使用!
- break:终止循环,即代码执行遇到break, 循环不再执行,立即结束
- continue:跳过本次循环。即代码执行遇到continue ,本次循环剩下的代码不再执行,继续下一次循环
五、容器
1. 字符串
注意:空格也算字符串。
1. 切片
切片:可以获取字符串中多个字符(多个字符的下标是有规律的,等差数列)
语法: 字符串[start : end : step]
start是开始位置的下标,end 是结束位置的下标(注意,不能取到这个位置的字符) step步长,等差数列的差值,所取的相邻字符下标之间的差值,默认是1,可以不写
num = '123456'# 1.如果最后一个字符也要取,可以不写,但是冒号必须有
print(num[1:]) # 23456
# 2.如果开始位置为0,可以不写,但是冒号必须有
print(num[:3]) # 123
# 3.如果开始和结束都不写。获取全部内容,但是冒号必须有
print(num[:]) # 123456
# 4.获取123字符
print(num[0:3:1]) # 123
# 5.如果步长是1可以不写,最后一个冒号也不写
print(num[0:2]) # 12
# 6.获取456字符
print(num[3:6]) # 456
print(num[-3:6]) # 456# 7.获取135,对应下标0 2 4,所以步长为2
print(num[0:6:2]) # 135
print(num[::2]) # 135
# 8.特殊应用,步长为负数,开始和结束不写,意思全变,一般不用管,只有一种使用场景
#反转(逆置)字符串字符串[::-1]
print(num[::-1]) # 654321
2. 查找方法find
语法:字符串.find(sub_ str, start, end)
作用:在字符串中查找是否存在sub_ str这样的字符串,sub_ str: 要查找的小的字符串
start
:开始位置,从哪个下标位置开始查找,一般不写,默认是0
end
:结束位置,查找到哪个下标结束,一般不写,默认是len()
返回(代码执行之后会得到什么,如果有返回,就可以使用变量保存):
1.如果在字符串中找到了sub_ str,返回sub_ str第一次出现的
正数下标(sub_ str中第一个字符在大字符串中的下标)
2.如果没有找到,返回-1
str = 'hello world and other and'
res = str.find('and')
print(res) # 12
# 在字符串中查找第二个and出现的下标,从第一次出现的后一位开始找
res1 = str.find('and',res + 1)
print(res1) # 22
#在字符串中查找第三个and出现的下标,从第二次出现的后一位开始找
res2 = str.find('and',res1 + 1)
print(res2) # -1
3. 替换方法replace
字符串.replace(old_ str, new_ str, count)
:将字符串中old_str替换为new_str
old_str: 被替换的内容
new_str: 替换为的内容
count: 替换的次数,一般不写,默认是全部替换
str = 'good good study'# 1.将str中所有good改为GOOD
res = str.replace('good','GOOD')
print(res) # GOOD GOOD study
# 2.将str中第一个good改为GOOD
res1 = str.replace('good','GOOD',1)
print(res1) # GOOD good study
4. 拆分 split
语法:字符串.split(sep, maxsplit)
将字符串按照sep进行分割(拆分)
sep,字符串按照什么进行拆分,默认是空白字符(空格,换行\n,tab键\t)
max_ split, 分割次数,一 般不写,全部分割
返回:将一个字符串拆分为多个,存到列表中
注意:如果sep不写,想要指定分割次数则需要按照如下方式使用字符串. split (maxsplit=n) n是次数
str = 'one and two and three and other'# 1.将str中按照 and 字符进行拆分
res = str.split('and')
print(res) # ['one ', ' two ', ' three ', ' other']
# 2.将str中按照 and 字符进行拆分,拆分1次
res1 = str.split('and',1)
print(res1) # ['one ', ' two and three and other']# 3.将str中按照 空格 进行拆分
res2 = str.split()
print(res2) # ['one', 'and', 'two', 'and', 'three', 'and', 'other']
# 将str中按照 空格 进行拆分一次
res2 = str.split(maxsplit=1)
print(res2) # ['one', 'and two and three and other']
5. 字符串拼接 join
语法:字符串.join(列表)
括号中的内容主要是列表,可以是其他容器
作用:将字符串插入到列表中每相邻的两个数据之间,组成一个新的字符串
列表中的数据使用使用逗号隔开的
注意点:列表中的数据必须都是字符串,否则会报错
list = ['good','dood','study']
# 1.将list中按照 空格 进行拼接
res = ' '.join(list)
print(res) # good dood study# 2.将list中按照 and 进行拼接
res1 = ' and '.join(list)
print(res1) # good and dood and study
2. 列表
1. 下标和切片
列表支持下标和切片操作,使用方法和字符串中的使用方法一致
区别:列表的切片得到的是列表
list1 = ['小明',18,1.71,True]
#获取第一个数据,名字
print(list1[0])
#获取最后一个数据
print(list1[-1])#第一第二个数据
print(list1[0:2]) # ['小明',18]
#列表页支持len()求长度的,求数据元素个数
print(1en(list1)) # 4
2. index()查找列表中数据下标的方法
在字符串中使用的 find 方法查找下标的,不存在返回的是-1.
在列表中没有find 方法,想要查找数据的下标,使用的index() 方法
列表.index(数据,start, end)
使用和 find方法一样,同时在字符串中也有index 方法
区别:返回,index() 方法,找到返回第一次出现的下标,没有找到代码直接报错
list = [1,2,4,8,2,5]
# 找出数字 2 出现的下标
res = list.index(2)
print(res) # 1
3. 判断数据是否存在
判断容器中某个数据是否存在可以使用in关键字
数据in容器,如果存在返回True ,如果不存在,返回False
list = [1,2,4,8,2,5]# 找出数字 3 出现的下标
if 3 in list:print(list.index(3))
else:print('list不存在数字 3')
4. 统计出现的次数
统计出现的次数,使用的是count() 方法
列表.count(数据)
返回数据出现的次数
list = [1,2,4,8,2,5]# 找出数字 2 出现的次数
if 2 in list:print(list.count(2)) # 2
else:print('list不存在数字 2')
5. append尾部添加数据的方法
列表.append(数据)
将数据添加到列表的尾部
返回:返回的None(关键字,空),一般就不再使用变量来保存返回的内容
想要查看添加后的列表,需要打印的是列表
list = []# 向列表中添加数据
list.append('apple')
print(list) # ['apple']
6. insert指定下标位置添加数据
列表.insert(下标,数据)
在指定的下标位置添加数据,如果指定的下标位置本来有数据,原数据会后移
返回:返回的None(关键字,空),- -般就不再使用变量来保存返回的内容
想要查看添加后的列表,需要打印的是列表
list = ['apple']# 向列表下标位置为 1 中添加数据
list.insert(1,'orange')
print(list) # ['apple','orange']
# 再次向列表下标位置为 1 中添加数据(位置会全部后移)
list.insert(1,'pear')
print(list) # ['apple', 'pear', 'orange']
7. extend列表合并
列表1.extend(列表2)
将列表 2中的所有数据逐个添加的列表1的尾部
返回:返回的None(关键字,空),一-般就不再使用变量来保存返回的内容想要查看添加后的列表,需要打印的是列表
list = ['apple', 'pear', 'orange']list1 = ['computer','tv']
# 把列表的内容分别放进去
list1.extend(list)
print(list1) # ['computer', 'tv', 'apple', 'pear', 'orange']# 把列表的内容整体放进去
list1.append(list)
print(list1) # ['computer', 'tv', 'apple', 'pear', 'orange', ['apple', 'pear', 'orange']]
8. 修改操作
想要修改列中的指定下标位置的数据,使用的语法是:
列表[下标] =数据
注意:字符串中字符不能使用下标修改
my_list=[1,3,5,7]# 1.想要将下标为1的数据修改为22
my_list[1]=22
print(my_list) # [1, 22, 5, 7]
#修改最后一个位置的数据,改为' hello'
my_list[-1]='hello'
print(my_list) # [1, 22, 5, 'hello']# 2,如果指定的下标不存在,会报错的
my_list[10]=10 #代码会报错
9. 删除操作
在列表中删除中间的数据,那么后面的数据会向前移动。
- 根据下标删除
列表. pop(下标)
删除指定下标位置对应的数据
1.下标不写,默认删除最后一个数据(常用)
2.书写存在的下标,删除对应下标位置的数据
返回:返回的删除的数据 - 根据数据值删除
列表.remove (数据值)
根据数据值删除
返回: None
注意:如果要删除的数据不存在,会报错 - 清空数据(一般不用)
列表.clear()
my_list=[1,3,5,7,9,2,4,6,8,0]# 1.删除最后一个位置的数据
num = my_list.pop()
print(my_list,num) # [1, 3, 5, 7, 9, 2, 4, 6, 8] 0
# 2.删除下标为 1 的数据
my_list.pop(1)
print(my_list) # [1, 5, 7, 9, 2, 4, 6, 8]# 3.删除数据为7的数据
my_list.remove(7) # 注意,如果列表中有多个7,只能删除第一个
print(my_list) # [1, 5, 9, 2, 4, 6, 8]
# 再次 删除数据为7的数据(报错)
my_list.remove(7)
print(my_list) # 报错# 清空
my_list.clear()
print(my_list) # []
10.列表的反转(倒置)
字符串
中反转倒置:字符串[::-1]
列表
中反转和倒置:
1.列表[::-1
] 使用切片的方法,会得到一个新列表,原列表不会发生改变
2.列表.reverse()
直接修改原列表,返回None
my_list=[1,3,5,7,9]#使用切片的方法反转,会得到一个新列表
res = my_list[::-1]
print(my_list) # [1, 3, 5, 7, 9]
print(res) # [9, 7, 5, 3, 1]#使用 reverse 方法,直接修改原列表
my_list.reverse()
print(my_list) # [9, 7, 5, 3, 1]
11.列表的复制
将列表中的数据复制一份,给到一个新的列表
使用场景:有一个列表,需要修改操作列表中的数据,修改之后,
需要和原数据进行对比,即原数据不能改
- 使用切片:
变量=列表[:]
- 使用copy 方法:
变量=列表.copy()
my_list=[1,3,5]# 1. 切片
new_list = my_list[:]
print(my_list,new_list) # [1, 3, 5] [1, 3, 5]
# 改其中一个列表内容不会影响另一个列表
my_list[0] = 'hello'
print(my_list,new_list) # ['hello', 3, 5] [1, 3, 5]# 2. copy()
newList = my_list.copy()
print(my_list,newList) # [1, 3, 5] [1, 3, 5]
# 改其中一个列表内容不会影响另一个列表
my_list[-1] = 'other'
print(my_list,newList) # [1, 3, 'other'] [1, 3, 5]# 3. 这是同一个列表,只是多了一个名字
newList1 = my_list
print(my_list,newList1) # [1, 3, 5] [1, 3, 5]
# 改其中一个列表内容会影响另一个列表
my_list[0] = 'momo'
print(my_list,newList1) # ['momo', 3, 5] ['momo', 3, 5]
12.列表的排序
列表的排序,一般来说都是对数字进行排序的:
列表. sort()
按照升序排序,从小到大
列表.sort( reverse=True )
降序排序,从大到小
my_list=[3,7,5]# 1. 升序排序
my_list.sort()
print(my_list) # [3, 5, 7]# 2. 降序排序
my_list.sort(reverse=True)
print(my_list) # [7, 5, 3]
13.列表去重
列表去重:列表中存在多个数据,需求,去除列表中重复的数据.
- 方式1:
遍历原列表中的数据判断在新列表中是否存在,如果存在,不管,如果不存在放
入新的列表中
遍历: for循环实现
判断是否存在:可以使用in
存入数据: append()
my_list = [1,3,3,1,2,2,3,5]new_list = []
for i in my_list:if i not in new_list:new_list.append(i)print(new_list) # [1,3,2,5]
- 方法2:
在Python 中还有一种数据类型(容器) , 称为是集合(set
)
特点:集合中不能有重复的数据(如果有重复的数据会自动去重)
可以使用集合的特点对列表去重
1.使用set()
类型转换将列表转换为集合类型
2.再使用list()
类型转换将集合转换为列表
缺点:不能保证数据在原列表中出现的顺序(一般来说,也不考虑这件事)
my_list = [1,2,3,1,2,2,3,5]
list = list(set(my_list))
print(list)
3. 元组
元组: tuple, 元组的特点和列表非常相似
1.元组中可以存放任意类型的数据
2.元组中可以存放任意多个数据
区别:
1.元组中的数据内容不能改变。列表中的可以改变的
2.元组使用(),列表使用[]
应用:在函数的传参或者返回值中使用,保证数据不会被修改
定义
1.使用类实例化的方式
2.直接使用()方式
由于元组中的数据不能修改,所以只有查看的方法:
- 在元组中也可以使用下标和切片获取数据
- 在元组中存在 index 方法
- 在元组中存在 count 方法
- 在元组中可以使用 in 操作 以上方法的使用和列表中一样的
# 直接使用()定义
my_tuple4 = (1, "小王",3.14, False)
print(my_tup1e4)
# 特殊点,定义只有一个数据的元组时,数据后边必须有一个逗号
my_tuple5 = (1,)
print(my_tup1e5)print(my_tup1e4[1]) # 小王
4. 字典
1.字典dict,字典中的数据是由键( key )值( value)对组成的(键表示数据的名字,值就是具体的数据)
2.在字典中一组键值对是一个数据,多个键值对之间使用逗号隔开
变量= {key: value, key:value, ...}
3.一个字典中的键是唯-的,不能重复的,值可以是任意数据
4.字典中的键一般都是字符串,可以是数字,不能是列表
# 直接使用{}定义
my_dirt= {"name":"小明","age": 18,"height":1.71,"like":['跑步','看书']}print(my_dirt)
print(len(my_dirt)) # 4
1. 增加和修改操作
语法: 字典[键] = 数据值
1.如果键已经存在,就是修改数据值
2.如果键不存在,就是添加数据(即添加键值对)
my_dirt= {"name":"小明","age": 18,"height":1.71,"like":['跑步','看书']}print(my_dirt)
# 1.添加性别信息sex ,只能添加在最后面
my_dirt['sex'] = '男'
print(my_dirt)
# 2.修改年龄为19
my_dirt['age'] = 19
print(my_dirt)
# 3.添加一个爱好,学习-->本质是向列表中添加一个数据
my_dirt['like'].append('健身')
print(my_dirt)
2. 删除指定键值对
del 字典[键]
字典.pop(键)
键必须书写
清空: 字典.clear()
my_dirt= {"name":"小明","age": 18,"height":1.71,"like":['跑步','看书']}# 1.删除身高信息
del my_dirt['height']
print(my_dirt)my_dirt.pop('name')
print(my_dirt)# 清空键值对
my_dirt.clear()
print(my_dirt)
3. 根据键获取对应的值
字典中没有下标的概念,想要获取数据值,要使用key(键)来获取
- 使用
字典[键]
1.如果键存在返回键对应的数据值,
2.如果键不存在,会报错 - 使用
字典.get(键,数据值)
1.数据值一般不写,默认是None
返回:
1.如果键存在返回键对应的数据值
2.如果键不存在,返回的是括号中书写的数据值(None)
一般建议使用get 方法
my_dirt= {"name":"小明","age": 18,"height":1.71,"like":['跑步','看书']}#
print(my_dirt['age']) # 18
print(my_dirt.get('age')) # 18print(my_dirt['gender']) # 报错
print(my_dirt.get('gender')) # None
4. 字典了遍历
- 对字典的键进行遍历
for 变量 in 字典:print(变量) # 变量就是字典的key,键for 变量 in 字典.keys(): # 字典.keys()可以获取字典中所有的键print(变量)my_dirt= {"name":"小明","age": 18,"height":1.71}
for k in my_dirt:print(k)for k in my_dirt.keys():print(k)
- 对字典的值进行遍历
for 变量 in 字典.values(): # 字典.values()可以获取字典中所有的值print(变量)my_dirt= {"name":"小明","age": 18,"height":1.71}
for v in my_dirt.values():print(v)
- 对字典的键值对进行遍历
#变量1就是键,变量2就是键对应的值
for 变量1,变量2 in 字典.items(): # 字典.items()获取键值对print(变量1,变量2)my_dirt= {"name":"小明","age": 18,"height":1.71}
for k,v in my_dirt.items():print(k,v)
容器部分总结
# 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关键字在容器中都可以使用,注意,在字典中判断的是字典的键是否存在
六、函数
函数,就是把具有独立功能的代码块组织为一个小模块,在需要的时候调用,将多行代码写在一块,起个名字,在需要这多行代码的时候,可以直接使用这个名字来代替。
函数好处:减少代码的冗余(重复的代码不用多写),提高程序的编写效率
def函数名():函数中的代码函数中的代码
# 1. def是关键字,用来定义函数的 define的缩写
# 2.函数名需要遵守标识符的规则
# 3.处于def缩进中的代码,称为函数体
# 4.函数定义的时候,函数体中的代码不会执行,在调用的时候才会执行# 函数的调用
函数名()
# 1.函数调用的时候会执行函数体中代码
# 2.函数调用的代码,要写在函数体外边
1. 函数基本使用
def say_hello():print('hello1')print('hello2')print('hello3')# 调用
say_hello()
say_hello()
2. 函数传参
形参和实参的使用。
# num1和num2 是函数定义时候的参数,起到占位的作用,没有具体的数据值,称为形式参数,简称形参
def my_fun(num1,num2):num = num1 + num2 # 在什么时候定义参数,函数中使用的数据会会变化的时候,就可以定义为参数print(num)# 在函数调用的时候,括号中的数据会传递给形参,是具体的数据值,称为实际参数,简称实参
my_fun(1,10) # 11
my_fun(200,200) # 400
3. 数据类型的改变
数据类型: int float bool str list tuple dict set
可变不可变是指:数据所在的内存是否允许修改,允许修改就是可变类型,不允许修改就是不可变类型(不使用=,变量引用的数据中的内容是否会变化,会变化是可变的,不会变化是不可变的)
可变类型:列表list,字典dict,集合set
不可变类型:int float bool str tuple
1.只有 =,可以改变引用
2.可变类型做参数,在函数内部,如果不使用=直接修改形参的引用,对形参进行的数据修改会同步到实参中
def func(list):list.append(10)my_list = [1,6]
func(my_list)
print(my_list) # [1,6,10]# list= my_list #此时两个变量的引用是相同的
def func1(list):list = [2,9] # list变量的引用发生了改变,my_list的引用没有改变,数据不会变my_list = [1,6]
func1(my_list)
print(my_list) # [1,6]
4. 变量值的交换
重点掌握,Python 特有
a,b = b,a
print(a, b)
原理:组包和拆包
组包(pack):将多个数据值使用逗号连接,组成元组
拆包(unpack):将容器中的数据值使用多个变量分别保存的过程
注意:变量的个数和容器中数据的个数要保持一致
5. 局部变量和全局变量
- 局部变量
局部变量:在函数内部(函数的缩进中)定义的变量,称为是局部变量
特点:
1.局部变量只能在当前函数内部使用,不能在其他函数和函数外部使用
2.在不同函数中,可以定义名字相同的局部变量,两者之间没有影响
3.生存周期(生命周期,作用范围)–>在哪能用
在函数被调用的时候,局部变量被创建,函数调用结束,局部变量的值被销毁(删除),不能使用
所以函数中的局部变量的值如果想要在函数外部使用, 需要使用return 关键字,将这个值进
行返回 - 全局变量
定义位置:在函数外部定义的变量,称为是全局变量
特点:
1.可以在任何函数中读取(获取)全局变量的值
2.如何在函数中存在和全局变量名字相同的局部变量,在函数中使用的是局部变量的值(就近)
3.在函数内部想要修改全局变量的引用,需要添加global 关键字,对变量进行声明为全局变量
4.生命周期
代码执行的时候被创建,代码执行结束,被销毁(删除)
g_num = 100
def func3():global g_num # 这个函数中使用的g_num 都是全局变量g_num = 30 #修改了全局变量print(f'func3中{g_num}')
func3()
6. 函数返回多个数据值
函数中想要返回一个数据值,使用return
关键字
将多个数据值组成容器进行返回,一般是元组(组包)
def num(n1,n2):num1 = n1 + n2num2 = n1 - n2return num1,num2
# 1.结果返回一个元组
res = num(20,10)
print(res,res[0],res[1]) # (30, 10) 30 10# 2.拆包
a,b = num(30,10)
print(a,b) # 40 20
7. 函数的传参
def func(a,b,c):print(f'a:{a},b:{b},c:{c}')# 位置传参
func(1,28,'l')
# 关键宇传参
func(a=1,c=20,b=9)
# 混合使用,关键字必须放在最后
func(1,'k',c=20)
缺省参数
1.定义方式
在函数定义的时候,给形参一个默认的数据值,这个形参就变为缺省参数,注意,缺省参数的书写要放在普通参数的后边
2.特点(好处)
缺省参数,在函数调用的时候,可以传递实参值,也可以不传递实参值
如果传参,使用的就是传递的实参值,如果不传参,使用的就是默认值
def func(name,age='秘密'):print(f'name:{name},age:{age}')func('mario')
不定长参数
当我们在书写函数的时候,不确定参数的具体个数时,可以使用不定长参数。
- 不定长位置参数(不定长元组参数)
1.书写,在普通参数的前边,加上一个*,这个参 数就变为不定长位置参数
2.特点,这个形参可以接收任意多个位置传参的数据
3.数据类型,形参的类型是元组
4.注意,不定长位置参数要写在普通的参数的后面
5.一般写法,不定长位置参数的名字为args, 即(*args ) - 不定长关键字参数(不定长字典参数)
1.书写,在普通参数的前边,加上两个*,这个参 数就变为不定长关键字参数
2.特点,这个形参可以接收任意多个关键字传参的数据
3.数据类型,形参的类型是字典
4.注意,不定长关键字参数,要写在所有参数的最后边
5.一般写法,不定长关键字参数的名字为kwargs, 即(**kwargs), - 完整的参数顺序
def 函数名(普通函数,*args, 缺省参数,**kwargs):pass
# 一般在使用的时候,使用1-2种,按照这个顺序挑选书写即可
def func(*args,**kwargs):print(args)print(kwargs)func(1,2,3) # (1, 2, 3) {}
func(a=1,b=2,c=4) # () {'a': 1, 'b': 2, 'c': 4}
func(1,2,a=1,b=2) # (1, 2) {'a': 1, 'b': 2}# 使用定义好的字典和列表中的数据,如何传参的问题
my_list = [1, 2, 3, 4]
my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
func(*my_list)
func(**my_dict)func(my_list) # 报错
8. 匿名函数 lambda
匿名函数
:就是使用lambda
关键字定义的函数
标准函数
:一般称为使用def
关键字定义的函数
匿名函数只能书写一行代码
匿名函数的返回值不需要return,一行代码(表达式)的结果就是返回值
语法:lambda 参数:一行代码
匿名函数一般不需要我们主动的调用,一般作为函数的参数使用的|
numa = lambda a,b:print(a+b)
numa(1,10) # 11
参数只是一个占位的作用,定义的时候没有具体的数据值,形参的值是在调用的时候进行传递,此时,形参才有数据值形参的类型就是由实参来决定的,在函数定义的时候,参数只是一个符号,写什么都可以,想让其是字典类型,只需要保证实参是字典即可
# 1.定义一个匿名函数可以求两个数的乘积()
func = lambda a,b: a*b
print(func(10,10)) # 100# 2.定义一个匿名函数,参数为字典,返回字典中键为age的值
# 这里实参是字典即可
func1 = lambda x: x.get('age')
print(func1({'name':"aa",'age':19})) # 19
字典排序
列表的排序,默认是对列表中的数据进行比大小的,可以对数字类型和字符串进行比大小,但是对于字典来说,就不知道该怎么比大小,此时,我们需要使用sort 函数中的key这个参数,来指定字典比大小的方法,key这个参数,需要传递一个函数, 一般是匿名函数,字典的排序,其实要指定根据字典的什么键进行排序,我们只需要使用匿名函数返回字典的这个键对应的值即可
列表.sort(key=Lambda x: x[ '键'])
user_list = [{'name':'a','age':18},{'name':'b','age':13},{'name':'c','age':28}]
#根据年龄排序
user_list.sort( key=lambda x:x['age'] )
print(user_list) # 按年龄升序排user_list.sort( key=lambda x:x['age'],reverse=True )
print(user_list) # 按年龄降序排
七、面向对象
步骤:
- 定义类,在定义类之前先设计类
先定义简单的类,不包含属性,在python 中定义类需要使用关键字class
方法: 方法的本质是在类中定义的函数,只不过,第一个参数是self
class类名:
# 在缩进中书写的内容, 都是类中的代码def方法名(self): # 就是一个方法pass
- 创建对象,使用第一步定义的类创建对象
创建对象是使用类名()进行创建,即
类名() 创建一个对象,这个对象在后续不能使用
创建的对象想要在后续的代码中继续使用,需要使用一个变量,将这 个对象保存起来
变量=类名()
这个变量中保存的是对象的地址,一般可以成为这个变量为对象
一个类可以创建多个对象,只要出现类名()就是创建一个对象,每个对象的地址是不一样的 - 通过对象调用方法
对象.方法名()
self是一个形参,不需要手动传递实参值,python解释器会自动将调用该方法的对象作为实参值进行传递 self就是对象自己
1. 封装
- 添加属性:
对象.属性名=属性值
类内部添加:
在内部方法中,self是对象,self.属性名=属性值
在类中添加属性一般写作__init__
方法中
类外部添加:
对象.属性名=属性值
一般不使用 - 获取属性:
对象.属性名
类内部:
在内部方法中,self是对象,self.属性名
类外部:
对象.属性名
一般很少使用
# 定义类
class Cat:def eat(self):print(f'{self.name} 爱吃鱼,今年{self.age}岁')# 创建对象
blue_cat = Cat()
# 添加属性
blue_cat.name = '小蓝猫'
blue_cat.age = 2
# 调用方法
blue_cat.eat()black_cat = Cat()
black_cat.name = '小黑猫'
black_cat.age = 4
black_cat.eat()
1. 魔法方法
python中有一类方法,以两个下划线开头,两个下划线结尾,并且在满足某个条件的情况下,会自动调用,这类方法称为魔法方法
学习:
1.什么情况下自动调用
2.有什么用,用在哪
3.书写的注意事项
__init__方法
- 什么情况下自动调用
创建对象之后会自动调用- 有什么用,用在哪
1.给对象添加属性的 (初始化方法,构造方法)
2.某些代码,在每次创建对象之后,都要执行,就可以将这行代码写在init__ 方法- 书写的注意事项
1.不要写错了
2.如果init方法中,存在出了self 之外的参数,在创建对象的时候必须传参
class Cat:def __init__(self,name,age):self.name = nameself.age = agedef show_info(self):print(f'小猫名字是:{self.name},年龄是{self.age}')# 创建对象
blue_cat = Cat('蓝猫',3)
blue_cat.show_info()
str
- 什么情况下自动调用
使用print(对象)打印对象的时候会自动调用- 有什么用,用在哪
在这个方法中一般书写对象的属性信息的,即打印对象的时候想要查看什么信息,在这个方法中进行定义的
如果类中没有定义__str__
方法,print(对象), 默认输出对象的引用地址- 书写的注意事项
这个方法必须返回一个字符串
def __init__(self,name,age):self.name = nameself.age = age# def show_info(self):# print(f'小猫名字是:{self.name},年龄是{self.age}')# 此方法必须返回一个字符串,只要是字符串就行def __str__(self):return f'小猫名字是:{self.name},年龄是{self.age}'# 创建对象
blue_cat = Cat('蓝猫',3)
print(blue_cat)
del
init_方法, 创建对象之后,会自动调用(构造方法)
__del__
方法,对象被删除销毁时,自动调用的(处理残留) (析构方法)
class Cat:def __init__(self,name,age):self.name = nameself.age = agedef __del__(self):print(f'{self.name}被删除了')# 创建对象
blue_cat = Cat('蓝猫',3)
print(blue_cat)del blue_cat # 删除销毁对象
print('end')
2. 案例
# 1.小明体重 75.0公斤
# 2.小明每次跑步会减肥 0.5 公斤
# 3.小明每次吃东西体重增加 1公斤
class Person:def __init__(self,name,weight):self.name = nameself.weight = weightdef __str__(self):return f'姓名:{self.name},体重 {self.weight}kg'def run(self):print(f'{self.name}跑步5公里,体重减少了')self.weight -= 0.5def eat(self):print(f'{self.name}吃一顿美食,体重增加了')self.weight += 1xm = Person('小明',75.0)
print(xm)
xm.run()
print(xm)
房子添加家具
class House:def __init__(self,name,area):self.name = nameself.total_area = areaself.free_area = areaself.item_list = []def __str__(self):return f'户型:{self.name},总面积:{self.total_area}平米,\剩余面积:{self.free_area},家具名称列表:{self.item_list}'def add_item(self,item): # item 表示家具的对象if self.total_area > item.area:self.item_list.append(item.name)self.free_area -= item.areaprint(f'{item.name}添加成功')else:print('房子剩余面积不足') class HouseItem:def __init__(self,name,area):self.name = nameself.area = areadef __str__(self):return f'家具名{self.name},占地面积{self.area}'# 创建家具类
bed = HouseItem('席梦思',4)
chest = HouseItem('衣柜',2)
table = HouseItem('餐桌',1.5)
print(bed)
print(chest)
print(table)# 创建房子类
house = House('三室一厅',150)
print(house)
# 添加床
house.add_item(bed)
print(house)
3. 私有和公有权限
- 公有权限:
直接书写的方法和属性,都是公有的
公有的方法和属性,可以在任意地方访问和使用- 私有权限
在类内部,属性名或者方法名前边加上两个下划线
,这个属性或者方法就变为私有
私有的方法和属性,只能在当前类的内部使用- 什么时候定义私有
1.某个属性或者方法,不想在类外部被访问和使用,就将其定义为私有即可
2.测试中,一般不怎么使用,直接公有即可
3.开发中,会根据需求文档,确定什么作为私有- 如果想要在类外部操作私有属性,方法是,在类内部定义共有的方法,我们通过这个方法去操作
class Person:def __init__(self,name,age):self.name = name# 私有的本质,是Python 解释器执行代码,发现属性名或者方法名前有两个_,会将这个名字重命名#会在这个名字的前边加上_类名前缀, 即 self.__age ===> self._Person_ageself.__age = age # 年龄,将其定义为私有属性,属性名前加上两个_def __str__(self): # 在类内部可以访问私有属性的return f'姓名:{self.name},年龄 {self.__age}岁' xm = Person('小明',25)
print(xm)#在类外部直接访问age属性
print(xm.__age) # 会报错,在类外部不能直接使用私有属性
#直接修改age属性
xm.__age = 20 # 这个不是修改私有属性,是添加了一个公有的属性__age
print(xm) # 姓名:小明,年龄 25岁
2. 继承
1.继承描述的是类与类之间的关系
2.继承的好处:减少代码的冗余(相同的代码不需要多次重复书写),可以直接使用!
语法:
class A: #没有写父类,但也有父类,object,object 类是Python中最顶级(原始)的类pass
class B(A): #类B,继承类Apass
术语:
- A类,称为是父类(基类)
- B类,称为是子类(派生类)
单继承: 一个类只继承一个父类,称为单继承
继承之后的特点:
子类(B)继承父类(A)之后,子类的对象可以直接使用父类中定义的公有属性和方法
结论 python中
对象.方法()
调用方法
1.现在自己的类中的去找有没有这个方法如果有,直接调用
2.如果没有去父类中查找,如果有,直接调用
3.如果没有,去父类的父类中查找,如果有直接调用
4.如果object 类中有,直接调用,如果没有,代码报错
class Animal:def eat(self):print('eat!!!')
class Dog(Animal):def wan(self):print('wang...')
class Quan(Dog):passdog = Dog()
dog.wan() # 调用自己类中方法
dog.eat() # 调用父类中的方法x = Quan()
x.eat() # 可以调用父类的父类中的方法
x.wan() # 调用父类Dog类的方法
1. 重写
重写: 在子类中定义了和父类中名字相同的方法,就是重写
重写的原因: 父类中的方法,不能满足子类对象的需求,所以重写
重写之后的特点: 调用子类字节的方法,不再调用父类中的方法
重写的方式:
1.覆盖(父类中功能完全抛弃,不要,重写书写)
2.扩展(父类中功能还调用,只是添加一些新的功能) ( 使用较多)
- 覆盖
直接在子类中定义和父类中名字相同的方法
直接在方法中书写新的代码
class Dog(Animal):def bark(self):print('wang...')
class Quan(Dog):# quan 类bark 方法不再是wang...,改为 aoaoao...def bark(self):print('aoaoao...')x = Quan()
x.bark()
- 扩展
直接在子类中定义和父类中名字相同的方法
在合适的地方调用父类中方法super().方法()
书写添加的新功能
class Dog:def bark(self):print('wang...')print('wang...')class Quan(Dog):# quan 类bark 方法不再是wang...,# 改为 先aoaoao... 再wang...def bark(self):print('aoaoao...')# 调用父类中的代码super().bark()print('aoao~~~')x = Quan()
x.bark()
3. 多态
1.是一种写代码,调用的一-种技巧
2.同一个方法,传入不同的对象,执行得到不同的结果,这种现象称为是多态
3.多态可以增加代码的灵活度
哪个对象调用方法,就去自己的类中去查找这个方法,找不到去父类中找
4. 类方法和静态方法
- 实例方法
在类中直接定义的方法就是实例方法
如果在方法中需要使用实例属性(即需要
使用self
), 则这个方法必须定义为实例方法
class Demo:def func(self):
#参数一般写作 self,表示的是实例对象pass
- 类方法(会用)
在方法名字的上方书写@classmethod
装饰器(使用@classmethod 装饰的方法)
1.前提,方法中不需要使用实例属性(即self)
2.用到了类属性,可以将这个方法定义为类方法,(也可以定义为实例方法)
class Demo:@classmethoddef func(cls): # 参数一般写作cls,表示的是类对象(即类名) classpass
- 静态方法(基本不用)
在方法名字的上方书写@staticmethod
装饰器(使用@staticmethod装饰的方法)
1.前提,方法中不需要使用实例属性(即self)
2.也不使用类属性,可以将这个方法定义为静态方法
class Demo:@staticmethoddef func(): # 一般没有参数pass
例:
class Game:top_score = 0 # 类属性def __init__(self,name): # 实例方法self.name = name# 静态方法@staticmethoddef show_help():print('这是游戏的帮助信息')# 类方法@classmethoddef show_top_score(cls):print(f'游戏最高分为:{Game.top_score}')
5. 补充
哈希(hash) :是一个算法,可以对数据产生一 个唯一的值(指纹)
is可以用来判断两个对象是不是同一个对象,即两个对象的引|用是否相同
a is b == > id(a) == id(b)
面试中可能会问: is 和 ==的区别?
== 只判断数据值是否相同,is 判断引用是否相同
八、文件
计算机的文件,就是存储在某种长期储存设备上的一段数据
作用:将数据长期保存下来,在需要的时候使用
1.计算机只认识二进制(0 1)
2.文件中存储的数据都是以二进制(0 1)的形式去存储的
可以根据文件中的二进制内容,能否使用记事本软件将其转换为文字,将文件分为两种:文本文件和二进制文件:
- 文本文件
能够使用记事本软件打开(能够使用记事本转换为文字)
txt,md, py html, css, js,json - 二进制文件
不能使用记事本软件打开的
exe, mp3,mp4, jpg, png
1. 文件的操作
- 打开文件
打开文件:将文件从磁盘(硬盘)中读取到内存中
语法:open(file,mode='r',,encoding-None)
参数file:是要打开的文件,类型是字符串,文件的路径可以是相对路径,也可以是绝对路径(从根目录开始书写的路径) ,建议使用相对路径(相对于当前代码文件所在的路径,./ …/ )
参数mode: 默认参数(缺省参数),表示的是打开文件的方式
r:read 只读打开
w:write 只写打开
a:append 追加打开,在文件的末尾写入内容
参数encoding: 编码方式,(文字和二进制如何进行转换的)
gbk:将一个汉字转换为2个字节二进制
utf-8: 常用,将一个汉字转换为3个字节的二进制
返回值:返回的是文件对象,后续对文件的操作,都需要这个对象 - 读或者写文件
写文件:
向文件中写入指定的内容
前提:文件的打开方式是w或者a
文件对象. write(‘写入文件的内容’)
返回值:写入文件的字符数,一般不关注
读文件:
将文件中的内容读取出来
前提:文件的打开方式需要是r - 关闭文件
关闭文件:将文件占用的资源进行清理,同时会保存文件,文件关闭之后,这个文件对象就不能使用了
文件对象. close()
# 1. 打开文件
f = open('a.txt','w',encoding='utf-8')# 2. 写文件
f.write('hello python\n')
f.write('hello test')# 3. 关闭文件
f.close()
1. 使用with open 打开文件(推荐)
with open()
打开文件的好处:不用自己去书写关闭文件的代码,会自动进行关闭
with open(file, mode, encoding='utf-8') as 变量:
# 在缩进中去读取或者写入文件
# 缩进中的代码执行结束,出缩进之后,文件会自动关闭
# 1. 打开文件
with open('a.txt','a',encoding='utf-8') as f:f.write('\n我是追加内容~~')# a方式打开文件,文件不存在会创建文件,文件存在,在文件的末尾写入内容
2. 按行读取文件内容
按行读取文件:一次读取一行内容
文件对象.readline()
# 读取所有文件
# 方法一
with open('a.txt',encoding='utf-8') as f:print(f.readline()) # 一行一行读取print(f.readline())# 方法二
with open('a.txt',encoding='utf-8') as f:for i in f:print(i,end='')# 方法三
with open('a.txt',encoding='utf-8') as f:while True:buf = f.readline()if len(buf) == 0:breakelse:print(buf,end='')
2. json文件的处理
json文件也是一个文本文件,就可以直接使用read() 和write()方法去操作文件,只是使用这两个方法,不方便,所以对json文件有自己独特的读取和写入的方法。
常用在在做测试的时候,将测试数据定义为json文件格式,使用代码读取json文件,即读取测试数据,进行传参(参数化)
json的介绍
json基于文本,独立于语言的轻量级的数据交换格式
1.基于文本,是一个文本文件,不能包含图片,音视频等
2.独立于语言,不是某个语言特有的,每种编程语言都可以使用的
3.轻量级,相同的数据,和其他格式相比,占用的大小比较小
4.数据交换格式,后端程序员给前端的数据(json,html,xml)
1. json文件的语法
- json文件的后缀是
.json
- json 中主要数据类型为对象({ }类似Python 中字典)和数组([ ],类似Python中的列表),对象和数组可以互相嵌套
- 一个json文件是一个对象或者数组(即json文件的最外层要么是一个{},要么是一个数组[])
- json中的对象是由键值对组成的,每个数据之间使用
逗号隔开
,但是最后一个数据后边不要写逗号 - json 中的字符串必须使用
双引号
- json中的其他数据类型
数字类型----> int float
string字符串—>str
布尔类型true, false ----> True, False
null ----> None
2. json 文件的书写
{"name":"mario","age":22,"gender":"female","like":["听歌","健身","跑步","看书"],"address":{"country":"中国","city":"武汉"}
}
3. json 文件的读取
1.导包 import json
2.读打开文件
3.读文件:json.load(文件对象)
返回的是字典(文件中是对象)或者列表(文件中是数组)
import jsonwith open('info.json',encoding='utf-8') as f:res = json.load(f) # 读取文件# print(type(res)) # <class 'dict'>print(res)print(res['name'])print(res['address']['city'])
json读取多个文件:
# json文件
[{"name":"mario","age":22,"gender":"female","like":["听歌","健身","跑步","看书"],"address":{"country":"中国","city":"武汉"}},{"name":"大鹏","age":19,"gender":"male","like":["健身","打游戏","看电影"],"address":{"country":"中国","city":"广州"}}
]
import jsonwith open('info.json',encoding='utf-8') as f:res_list = json.load(f) # 读取文件for info in res_list:print(info['name'],info['age'],info['address']['city'])
案例
某网站的测试数据如下data.json, 需求,提取json文件中的用户名,密码和预期结果,
组成格式: [(),(),()] (自动化参数化需要的数据格式)
# json文件
[{"desc": "正确的用户名密码","username": "admin","password": "123456","expect": "登录成功"},{"desc": "错误的用户名","username": "root" ,"password": "123456","expect": "登录失败"},{"desc": "错误的密码","username": " admin","password": "123123" ,"expect": "登录失败"}
]
import jsondef read_data():with open('info.json',encoding='utf-8') as f:data = json.load(f)# print(data)new_list = []for i in data:# print((i['desc'],i['username'],i['password'],i['expect']))new_list.append((i['desc'],i['username'],i['password'],i['expect']))# print(new_list)return new_list
4. json 文件的写入
文件对象. write(字符串)不能直接将 Python的列表和字典作为参数传递
想要将Python 中的数据类型存为json 文件,需要使用json 提供的方法,不再使用write
步骤:
1.导包 import json
2.写(w)方式打开文件
3.写入json. dump(Python中的数据类型,文件对象)
import jsonmy_list = [('admin', '123456', '登录成功'), ('root', '123456', '登录失败'), ('admin', '123123', '登录失败')]
with open('info1.json','w',encoding='utf-8') as f :# 显示中文,不以ASCII码显示;缩进显示json.dump(my_list,f,ensure_ascii=False,indent=3)
九、异常
程序在运行时,如果Python 解释器遇到到一个错误,会停止程序的执行,并且提示一些错误信息,这就是异常
程序停止执行并且提示错误信息这个动作,抛出异常(raise
关键字)
捕获异常:程序遇到异常,默认动作是终止代码程序的执行,遇见异常之后,可以使用异常捕获,让程序代码继续运行,不会终止运行(重点)
1. 异常的捕获(重点)
基本语法
try:书写可能发生异常的代码
except: # 任何类型的异常都能捕获发生了异常执行的代码try:书写可能发生异常的代码
except 异常类型: # 只能捕获指定类型的异常,如果不是这个异常,还是会报错发生了异常执行的代码
try:num = input('请输入数字')num = int(num)print(num)
except:print('请输入正确的数字')print('后续代码不会被阻断,继续执行...')
捕获多个指定类型的异常:
try:num = input('请输入数字')num = int(num)print(num)a = 100 / num # 100 / 0 ,除数不能为0print(f'a:{a}')
except ValueError:print('发生了异常,请输入正确的数字')
except ZeroDivisionError:print('除数不能为0')
2. 捕获异常的完整版本
完整版本中的内容,不是说每- -次 都要全部书写,根据自己的需要,去选择其中的进行使用
完整写法:
try:可能发生异常的代码
except 异常类型1:发生异常类型1执行的代码
# Exception 是常见异常类的父类,这里书写Exception,可以捕获常见的所有异常,
# as变量,这个变量是一个异常类的对象,print(变量)可以打印异常信息
except Exception as 变量:发生其他类型的异常,执行的代码
else:没有发生异常会执行的代码
finally: 不管有没有发生异常,都会执行的代码
常用写法:
try:可能发生异常的代码
except Exception as e:发生异常执行的代码
3. 异常的传递(了解)
异常传递是Python 中已经实现好了,我们不需要操作,我们知道异常会进行传递.
异常传递:在函数嵌套调用的过程中,被调用的函数,发生了异常,如果没有捕获,会将这个异常向外层传递,… 如果传到最外层还没有捕获,才报错
def func1():num = 10 / 0print(num)def func2():func1()print(1111)func2()
十、模块和包
模块和包一个用法。
1. 模块
1.Python 源代码文件就是一个模块
2.模块中定义的变量函数类,都可以让别人使用,同样,可以使用别人定义的(好处:别人定义好的不需要我们再次书写,直接使用即可)
3.想要使用别人的模块中的内容工具(变量,类,函数),必须先导入模块才可以
4.我们自己写的代码,想要作为模块使用,代码的名字需要满足标识符的规则(由数字,字母下划线组成,不能以数字开头)
方式一:
import 模块名
#使用模块中的内容
模块名.工具名#举例
import random
import json
random.randint(a, b)
json.load()
json.dump()
方式二:
from 模块名 import 工具名
#使用
工具名 # 如果是函数和类需要加括号#举例
from random import randint
from json import load, dump
randint(a, b)
load()
dump()
对于导入的模块和工具可以使用
as
关键字给其起别名
注意
:如果起别名,原来的名字就不能用了只能使用别名
1. 模块的查找顺序
在导入模块的时候会先在当前目录中找模块,如果找到,就直接使用;
如果没有找到回去系统的目录中进行查找,找到,直接使用没有找到,报错
注意点:定义代码文件的时候,你的代码名字不能和你要导入的模块名字相同
十一、unitTest 框架
概念:UnitTest是Python自带的一个单元测试框架,用它来做单元测试。
自带的框架:不需要单外安装,只要安装了Python, 就可以使用
第三方框架:想要使用需要先安装后使用( pytest):selenium,appium,requests
单元测试框架:主要用来做单元测试,一般单元测试是开发做的.
对于测试来说,unittest框架的作用是自动化脚本(用例代码)执行框架(使用unittest 框架来管理运行多个测试用例的)
为什么使用UnitTest框架?
1.能够组织多个用例去执行
2.提供丰富的断言方法(让程序代码代替人工自动的判断预期结果和实际结果是否相符)
3.能够生成测试报告
1. UnitTest核心要素(unitest的5大组成)
- TestCase(最核心的模块)
TestCase (测试用例),注意这个测试用例是unittest 框架的组成部分,不是手工和自动化中我们所说的用例(Test Case)
主要作用:每个TestCase(测试用例)都是一个代码文件,在这个代码 文件中来书写 真正的用例代码 - TestSuite
TestSuite(测试套件),用来管理组装(打包)多个TestCase (测试用例)的 - TestRunner
TestRunner(测试执行,测试运行),用来执行TestSuite(测试套件) - TestLoader
TestLoader(测试加载),功能是对TestSuite(测试套件)功能的补充,
管理组装(打包)多个TestCase(测试用例)的 - Fixture
Fixture(测试夹具),书写在TestCase( 测试用例)代码中,是一个代码结构,可以在每个方法执行前后都会执行的内容
举例:
登录的测试用例,每个用例中重复的代码就可以写在Fixture 代码结构中,只写一遍,但每次用例方法的执行,都会执行Fixture 中的代码
1.打开浏览器
2.输入网址
TestCase(测试用例)
1.是一个代码文件,在代码文件中来书写真正的用例代码
2.代码文件的名字必须按照标识符的规则来书写(可以将代码的作用在文件的开头使用注释说明)
步骤
1.导包(unittest)
2.自定义测试类
3.在测试类中书写测试方法
4.执行用例
# 1.导包
import unittest# 2.自定义测试类,需要继承unittest 模块中的TestCase类即可
class TestDemo1(unittest.TestCase):# 3.书写测试方法,即用例代码。目前没有真正的用例代码,使用 print代替# 书写要求,测试方法必须以test_开头(本质是以test开头)def test_method1(self):print('这是测试1的代码')def test_method2(self):print('这是测试2的代码')# 4,执行用例(方法)
# 4.1将光标放在类名的后边运行,会执行类中的所有的测试方法
# 4.2将光标放在方法名的后边运行,只执行当前的方法
TestSuite(测试套件) & TestRunner(测试执行)
TestSuite(测试套件):管理打包组装TestCase( 测试用例)文件的
TestRunner (测试执行):执行TestSuite(套件)
步骤
1.导包( unittest)
2.实例化(创建对象)套件对象
3.使用套件对象添加用例方法
4.实例化运行对象
TestSuite(测试套件):是用来管理多个TestCase(测试用例)的,
先创建多个TestCase( 测试用例)文件
# 1.导包
import unittestfrom testDemo1 import TestDemo1
from testDemo2 import TestDemo2# 2.实例化(创建对象)套件对象,
suit = unittest.TestSuite()# 3.使用套件对象添加用例方法
# 方式一: 套件对象.addTest(测试类名('方法名')) 建议测试类名和方法名直接去复制,不要手写
suit.addTest(TestDemo1('test_method1'))
suit.addTest(TestDemo1('test_method2'))
suit.addTest(TestDemo2('test_method1'))
suit.addTest(TestDemo2('test_method2'))# 4.实例化运行对象
runner = unittest.TextTestRunner()
# 5.使用运行对象去执行套件对象
# 运行对象.run (套件对象)
runner.run(suit)
# 1.导包
import unittestfrom testDemo1 import TestDemo1
from testDemo2 import TestDemo2# 2.实例化(创建对象)套件对象,
suit = unittest.TestSuite()# 3.使用套件对象添加用例方法
# 方式二: 将一个测试类中的所有方法进行添加
# 套件对象.addTest(unittest.makeSuite(测试类名))
suit.addTest(unittest.makeSuite(TestDemo1))
suit.addTest(unittest.makeSuite(TestDemo2))# 4.实例化运行对象
runner = unittest.TextTestRunner()
# 5.使用运行对象去执行套件对象
# 运行对象.run (套件对象)
runner.run(suit)
登录测试案例
源代码(不能修改):
def login(username,password):if username == 'admin' and password == '123456':return '登录成功' else:return '登录失败'
测试用例:
import unittest
from testDemo1 import loginclass TestLogin(unittest.TestCase):def test_log1(self):if login('admin','123456') == '登录成功':print('success!')else:print('Error!')def test_log2(self):if login('root','123456') == '登录失败':print('success!')else:print('Error!')def test_log3(self):if login('admin','123123') == '登录失败':print('success!')else:print('Error!')
套件和执行的代码:
import unittest
from testCase import TestLoginsuit = unittest.TestSuite()
suit.addTest(unittest.makeSuite(TestLogin))runner = unittest.TextTestRunner()
runner.run(suit)
TestLoader(测试加载)
TestLoader ( 测试加载),作用和TestSuite 的作用是-样的,对TestSuite 功能的补充,用来组装测试用例的
比如:如果TestCase 的代码文件有很多,(10 ,20,30 )
使用步骤
1.导包
2.实例化测试加载对象并添加用例 —> 得到的是suite对象
3.实例化运行对象
4.运行对象执行套件对象
unittest.TestLoader().discover('用例所在的路径','用例的代码文件名')
代码实现
在一个项目中TestCase( 测试用例)的代码,一般放在一个单独的目录(case)
# 1. 导包
import unittest# 2.实例化加载对象并添加用例
# 2.1用例所在的路径,建议使用相对路径,用例的代码文件名可以使用*(任意多个任意字符)通配符
suit = unittest.TestLoader().discover('./case','test*.py')
# 2.2也可以使用默认的加载对象并加载用例
suit = unittest.defaultTestLoader.discover('case','test*.py')# 3,实例化运行对象
unittest.TextTestRunner().run(suit)
Fixture(测试夹具)
Fixture(测试夹具)是一种代码结构
在某些特定的情况下会自动执行
- 方法级别[掌握]
在每个测试方法(用例代码)执行前后都会自动调用的结构
#方法执行之前
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
登录案例
# 1. 导包
import unittestclass TestLogin(unittest.TestCase):# 每个测试方法执行之前都会先调用的方法def setUp(self):print('2.输入网址...') # "每个测试方法执行之后都会调用的方法def teatDown(self):print('4.关闭当前网址页面...') # 定义测试类之前调用的方法@classmethoddef setUpClass(cls):print('1.打开浏览器')# 定义测试类之后调用的方法@classmethoddef tearDownClass(cls):print('5.关闭浏览器')# 测试方法def test_1(self):print('3.输入正确用户名密码验证码,点击登录1')def test_2(self):print('3.输入错误用户名密码验证码,点击登录2')
2. 断言
让程序代替人工自动的判断预期结果和实际结果是否相符.
断言的结果有两种:
True, 用例通过
False,代码抛出异常,用例不通过
在unittest 中使用断言,都需要通过self.断言
方法来试验
- assertEqual
self.assertEqual(预期结果,实际结果)
判断预期结果和实际结果是否相等
1.如果相等,用例通过
2.如果不相等,用例不通过,抛出异常 - assertIn
self.assertIn(预期结果,实际结果)
判断预期结果是否包含在实际结果中
1.包含,用例通过
2.不包含,用例不通过,抛出异常
assertIn('admin', 'admin') # 包含
assertIn('admin','adminnnnnnn') # 包含
assertIn('admin', 'aaaadminnnnn') # 包含
assertIn('admin', 'addddmin') # 不包含
登录案例
源代码:
def login(username,password):if username == 'admin' and password == '123456':return '登录成功' else:return '登录失败'
断言测试:
import unittest
from testDemo1 import loginclass TestLogin(unittest.TestCase):def test_log1(self):self.assertEqual('登录成功',login('admin','123456')) def test_log2(self):self.assertEqual('登录失败',login('root','123456'))def test_log3(self):self.assertEqual('登录失败',login('admin','123123'))# assertIn:包含”失败“也可以def test_log3(self):self.assertIn('失败',login('admin','123123'))
3. 参数化
参数化在测试方法中,使用变量来代替具体的测试数据,然后使用传参的方法将测试数据传递给方法的变量
好处:相似的代码不需要多次书写
工作中场景:
1.测试数据一-般放在json文件中
2.使用代码读取json文件,提取我们想要的数据—> [(), ()] or [[],[]]
安装插件
unittest框架本身是不支持参数化,想要使用参数化,需要安装插件来完成
联网安装(在cmd 窗口安装或者)
pip install parameterized
pip是Python 中包(插件)的管理工具,使用这个工具下载安装插件
# 1. 导包
import unittest
from parameterized import parameterized
from testDemo1 import login# 组织测试数据[(), (), ()] or [[], [], []]
data = [('admin','123456', ' 登录成功'),('root', '123456', '登录失败'),('admin','123123', '登录失败')
]# 2.定义测试类
class TestLogin(unittest.TestCase):# 3.书写测试方法(用到的测试数据使用变量代替)@parameterized.expand(data)def test_login(self,except,username,password):self.assertEqual(except,login(username,password)) # 4.组织测试数据并传参(装饰器@)
实际数据放在单独的 json文件:
# 1. 导包
import unittest
import json
from parameterized import parameterized
from testDemo1 import login # 测试的源代码# 组织测试数据[(), (), ()] or [[], [], []]
def build_data():with open('data.json',encoding='utf-8') as f:res = json.load(f)data = []for i in res:data.append(i['username'],i['password'],i['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.组织测试数据并传参(装饰器@)
4. 跳过
对于一些未完成的或者不满足测试条件的测试函数和测试类,不想执行,可以使用跳过使用方法,装饰器完成
代码书写在TestCase 文件
import unittest
#直接将测试函数标记成跳过
@unittest.skip( '跳过额原因' )
#根据条件判断测试函数是否跳过,判断条件成立,跳过
@unittest.skipIf(判断条件,' 跳过原因')
import unittestverson = 3.0 # 版本号class TestDemo(unittest.TestCase):@unittest.skip('此代码未完善,跳过测试!')def test1(self):print('测试方法1')@unittest.skipIf(verson >= 3.0,'版本号大于3.0不用测!')def test2(self):print('测试方法2')
5. 测试报告
自带的测试报告:
只有单独运行TestCase 的代码,才会生成测试报告
第三方测试报告 HTMLTestRunner
HTMLTestRunner是一个第三方的类库,用来执行测试用例并生成HTML格式的测试报告
网上有多种不同的实现版本,用法都类似,只是生成的HTML报告样式有差别
注意:下载的文件要与Python的版本兼容(有些版本只支持Python2.x)
# 1.获取第三方的测试运行类模块,将其放在代码的目录中
# 2.导包unittest
import unittest
from HTMLTestRunner import HTMLTestRunner# 3.使用套件对象,加载对象去添加用例方法
suite = unittest.defaultTestLoader.discover('.','demo.py')# 4.实例化第三方的运行对象并运行套件对象
# HTML TestRunner() 参数可选如下:
# stream=sys.stdout, 必填,测试报告的文件对象(open),注意点,要使用wb打开
# verbosity=1, 可选,报告的详细程度,默认1简略,2详细
# title=None,可选,测试报告的标题
# description=None 可选,描述信息,Python 的版本,pycharm 版本# file = 'report.htmL' # 报告的后缀是 .htmL
file = 'report.html'
with open(file,'wb') as f:# runner = HTMLTestRunner(f) # 运行对象runner = HTMLTestRunner(f,2,'测试报告','python 3.6.6') # 运行对象# .运行对象执行套件,要写在with的缩进中runner.run(suite)
中文的报告:
import unittest
from HTMLTestRunnerCN import HTMLTestReportCN
#组装用例方法
suite = unittest . defaultTestLoader .discover('.', '*pa1.py')
#实例化运行对象
with open( 'report_ cn.htm1' ,'wb') as f:
runner = HTMLTestReportCN(f )
runner . run(suite)