1.编译型和解释型
编译器软件:将书写的代码转换成一个二进制文件,优点是执行效率高,缺点是代码存在编码错误的时候,就不能产生中间文件。如:c.
解释型软件:在代码执行的时候,将代码转换未二进制,边执行边转换(解释),优点是代码从上到下执行,后续代码的错误不会影响前面代码的执行。如js,python,php等
2 注释
注释是对代码解释说明的文字,不会执行,可以增强代码可读性
单行注释:#,快捷键ctrl /(可以先选中多行,再按快捷键,会给每行加上或取消注释)
多行注释:三对双引号或者三对单引号
3 代码中的波浪线
红色:代码的错误,必须处理,代码才能继续执行(代码没有写完也可能有红色波浪线)
灰色:不会影响代码的正常执行(如PEP8要求注释以# + 空格开始,如果打上#但是忘记加上空格,就会提示灰色波浪线。其中PEP8是python代码的书写规范,如果不按规范书写,就会给灰色波浪线。我们可以在书写完全部代码后,按下快捷键ctrl + alt +L 来按照PEP8自动化格式代码)
绿色:不会影响代码的正常执行。常出现在引号中,认为你书写的内容部属一个单词。
4 变量
作用:是用来存储数据的(在程序代码中出现的数据,想要保存下来使用,就必须使用变量
变量注意事项:必须先定义后使用
定义变量:变量名=变量值
使用变量:定义变量之后,直接使用变量名就可以了
起名规范(标识符规则):必须由字母数字和下划线构成,并且不能以数字开头,不能使用python中的关键字(python自带的已经使用的标识符,具有特殊作用),区分大小写
建议性命名:驼峰命令法(大驼峰如MyNameIs和小驼峰myNameIs),下划线连接法(每个单词之间使用下划线连接)
5 运行代码的方式
第一种方式是在命令行窗口(cmd打开),输入[python 要执行的python文件的路径(文件格式为.py)]
第二种方式是先进入到存储要运行的Python文件的位置,然后右击运行命令行,输入【python python文件名】
第三种方式是使用可视化工具直接run
6 数据类型
- 数字类型
- 整形int:就是整数,不带小数的数
- 浮点数float:就是小数
- 布尔类型bool:只有两个值True和False(注意大小写)
- 复数如3+4i
- 非数字类型
- 字符串str:使用引号引起来的就是字符串
- 列表list: 如[1,2,3]
- 元组tuple:如(1,2,3,4)
- 字典dict:如{‘name':'Cai'}
type(变量):可以获取变量的数据类型,如果要输出则使用print(tyoe(变量))
7 输入
input():获取用户使用键盘录入的内容
常常使用的形式是:变量=input('提示信息’)
代码从上到下执行,遇到input函数之后,会暂停执行,等待用户的输入,如果不输入会一直等待。在输入过程中,遇到回车表示本次输入结束 。会自动将输入的内容转换成字符型(通过type(变量)查看类型为[class 'str'])保存到左边的变量中。
8 类型转换
语句:变量=要转换为的类型(原数据)
注意:数据类型转换,不会改变原来数据的 类型,会生成一个新的数据类型)
int()将其他类型转换为int类型
可以将float类型的数字转换为整型
可以将 整数型的字符串转换为 整型
float() 将其他类型转换为 浮点型
可以将int类型转换为浮点型
可以将数字类型的字符串(整数类型和小数类型)转换为浮点型
str()将其他类型转换为字符串类型
任何其他类型都可以使用str()转换为字符串类型
9 格式化输出
print()可以使用逗号输出多个内容
%d,%f,%s分别是整数小数字符串类型占位
例1:输出“我的名字是xx,年龄是xxx,身高是xxx"
print('我的名字是%s,年龄是%d,身高是%f) % (name,age,height))
例2:从例1的实际输出可以看出,%f默认保留小数位为6位,要是想保留2为小数
print('我的名字是%s,年龄是%d,身高是%2f) % (name,age,height));
例3:保留一位小数
print('我的名字是%s,年龄是%d,身高是%1f) % (name,age,height))
例4:将1输出为000001
print('我的学号是%06d' % num) #%0nd将n换成具体数字后,就表示整数一共几位
例5:使用%
print('我的成绩是前10%%‘)
10 f 字符串格式化
注意:要想使用此方法,python版本需要>=3.6才可
使用:在字符串前加上小f或者大F,占位符号变更为{},
例子:(\n表示换行)
print( f’我的名字是{name},\n我的年龄是{age:},\n我的身高是{height:3f},我的学号是{stu_num:06d}我的成绩在前{num}%')
11 字符串.format()格式化字符串
使用{}占位,
语法: ‘ {},{},{},....’.format(变量1,变量2,变量3....)
12 快捷键
撤销ctrl+z
删除一行ctrl+x
复制粘贴一行:ctrl+d
快速在代码下方新建一行:shift+enter
13 运算符
算数运算符:+,-,*,\ (得到的是浮点类型), // 求商,% 取余 ,** 幂运算
比较运算符:>,< ,>=,<=,==,
逻辑运算符:and(第一个条件为false的时候不再继续判断),not,or(第一个条件为true的时候不再继续判断)
赋值运算符:=将等号右边的值保存到等号左边的变量中
复合运算符:+=,-=,/=,*=
14 if...elif...else
语法结构:
if 判断条件:
书写条件成立(真)执行的代码
elif 判定条件1:
elif 判定条件2:
elif 判定条件n:
else :
书写条件不成立(假)执行的代码
if是一个关键字,和后续判断条件之间需要一个空格
判断条件后边需要一个冒号,else也需要
冒号之后回车,代码需要缩进,在pycharm中会自动缩进,一般是四个空格,或者一个tab键
if代码块的代码,要么都执行,要不都不执行
只有if不成立了,才会去判断elif
age=input('你的年龄是')
if int(age)>18:
print('可以进去网吧‘)
else
print(’不能进去网吧‘)
name=input('你的名字是')
if name=='admin':
print('欢迎admin')
pwd=input('你的密码是')
if name=='admin' and pwd=='123':
print(f'欢迎{name}登入’)
else :
print('错误‘)
猜拳游戏:
import random
player=input('请出拳头1,剪刀2,布3)
computer=random.randint(1,3)
if player==1 and computer==2 or player==12 and computer==3 or player==3 and computer==1:
print(玩家胜利)
elif player ==computer:
print(电脑获胜)
else:
print(打平了)
15 debug
主要作用:查看代码的执行步骤
在pycharm中,代码和行号之间点击,出现小红点即打断点,再次点击小红点会取消断点
断点的位置,一般来说会在代码的第一行(在程序运行的时候,想要在什么地方停下来)
注意点:可能会出现的bug(pychrm软件的问题):代码中只有一个断点的时候不能debug调试查看代码执行过程,解决方案是在代码其他任意地方多加一个断点
16 while循环
循环就是让指定代码重复的执行
在程序开发中一共有三种流程方式:顺序,分支,循环
语法:
while 判断条件:
循环语句
死循环:一般由写代码的人不小心造成的bug,代码会一直运行下去
无限循环:写代码的人故意无限制的去执行,代码会一直不停的运行下去。常用场景是书写循环的时候不确定循环要执行多少次,所以一般会在循环当中添加一个if判断,然后使用break来终止循环。
17 for循环
语法:
for 变量名 in 容器:
重复执行的代码
容器可以是:字符串str,列表list,元组tuple,字典dict
18 range函数
range()是python自带的函数,作用是可以生成【0,n)之间的整数,不包含n,一共循环n次。
想让for循环几次n就写多少
range(n,m)是range的变形,作用是获取n到m之间的整数,不包含m。
19 字符串
使用单引号,双引号,三引号定义
字符串本身含有双引号,则在定义的时候不能使用双引号;字符串本身含有单引号,则在定义的时候不能使用单引号。若实在想使用,则使用转义字符\,但如在字符串前面添上r' ',则表示是原生字符串,不对转义字符进行转义
下标:从左到右从0开始,从右到左-1开始
长度:len(字符串名)
19.1 字符串切片
切片:字符串[start:end:step],start是开始的下标,end是结束位置的下标(不能取到),例如[1:5:2]就是1 3 。
切片会得到一个字符串,既可以获取字符串中多个字符。
str1='abcdefg'
print(str1[0:3:1])#abc
print(str1[0:3])#abc,如果步长为1可以不写,最后一个冒号可以不写
print(str1[:3])#abc如果开始位置为0,可以不写,但是冒号必须有
print(str1[4:7])#efg
print(str1[-3:7])#efg
print(str1[4:7])#efg
print(str1[4:])#efg如果最后一个字符也要取,可以不写,但是冒号一定要有
print(str1[:])#如果取全部字符,可以不写,但是冒号一定要有
注意有种特殊使用:步长为负数,开始和结束不写,表示倒置字符串
print(str1[: :-1]
19.2 find查找字符串
语法:字符串.find(sub_str,start,end)
sub_str : 要查找的小的字符串
start:开始位置,从哪个下标开始找,一般不写,默认是0
end:结束位置,查找哪个下标结束,一般不写默认是len()
如果找到了则返回sub_str第一次出现的正数下标,如果没找到就返回-1
str1='and it and cai and python'
在字符串中查找'and'
num=str1.find('and')
print(num)
在字符串中查找第二个and出现的下标,从第一个之后开始找
num1=str1.find('and',num+1)
print(num1)
在字符串中查找第三个and出现的下标,从第二个之后开始找
num2=str1.find('and',num1+1)
print(num2)
19.3 replace替换字符串
字符串.replace(oldstr,newstr,count),表示将字符串oldstr替换为newstr,进行count次,如果count不写默认全部替换。
19.4 split字符串的拆分
字符串.split(sep,max-split)表示将字符串按照sep进行分割。
其中sep表示字符串按照什么分割,默认是空白字符(空格,换行,tab键),max-split是分割次数,一般不写,全部分割。
返回结果是列表
如果sep不写想要指定分割次数,则使用字符串.split(max_split=n),n是次数。
19.5 字符串拼接
字符串.join(列表)是将字符串插入到列表中每相邻的两个数据之间,列表中的数据使用逗号隔开,
括号里的内容主要是列表也可以是其他容器,列表的数据都必须是字符串,否则会报错。
20 列表(定义,添加,查询,修改,排序)
列表在其他语言中叫数组
定义语法:
法1:数组名=[数据之间用英文逗号隔开]
法2:数组名=list()
类型转换:
list1=list('hello')转换字符串会将字符串中的每个字符作为一个数据存入列表
print(type(list1),list1)
下标规则和切片操作与字符串使用方法一样,区别是列表的切片得到的是列表
添加:列表.append(数据)
查询:列表.index(数据),列表.count(数据)
修改:列表[下标]=数据,注意字符串中的字符不能使用下标修改,如果指定的下标不存在代码会报错。
排序:列表.sort()表示从小到大排序,列表.sort(reverse=True)表示从大到小排序
20.1 查找列表中数据下标的方法
在字符串中使用find方法查找下标 不存在返回-1,而在列表中使用index()方法
列表.index(数据,start,end)使用和find方法一样。
同时在字符串中也有index方法,区别的地方在于返回第一次出现的下标,如果找不到直接报错。
20.2 in用于判断是否存在
判断容器中某个数据是否存在可以使用in关键字
语法:数据 in 容器,如果存在则返回True,不存在则返回False
20.3 count()查找找统计出现的次数
· 语法:列表.count(数据),返回数据出现的次数
20.4 添加数据
20.4.1尾部添加(最常用)
语法:列表.append(数据),将数据添加到列表的尾部
返回:返回的None(关键字,空),一般就不再使用 变量 来保存返回的内容,想要查看添加后的列表,需要打印的是列表
20.4.2 指定下标位置添加
语法:列表.insert(下标,数据),在指定的下标位置添加数据,如果指定的下标位置本来有数据,原数据会后移
返回:返回的None(关键字,空),一般就不再使用 变量 来保存返回的内容,想要查看添加后的列表,需要打印的是列表
20.4.3列表合并
语法:列表1.extend(列表2),将列表2中所有数据逐个添加到列表1的尾部
返回: 返回的None(关键字,空),一般就不再使用 变量 来保存返回的内容,想要查看添加后的列表,需要打印的是列表
20.5 列表删除
在列表中删除中间的数据,那么后面的数据会向前移动
20.5.1 根据下标删除
语法:列表.pop(下标),下标不写,默认删除最后一个数据
返回的是删除的数据
20.5.2 根据数据值删除
语法:列表.remove(数据值),根据数据值删除数据
返回:None
注意,删除的数据不存在会报错
20.5.3 清空数据(一般不用)
语法:列表.clear
20.6 列表反置
字符串中反转倒置是:字符串[ : :-1]
列表中反转和倒置:
1.列表[ : :-1]:使用切片的方法,会得到一个新列表,原列表不会发生改变
2.列表.reverse() 直接修改原列表,返回None
20.7 列表的复制
使用场景:有一个列表,需要修改操作列表中的数据,修改之后,需要和原来的数据进行对比,即原来的数据不能改
语法1:使用切片:变量=列表[ : ]
语法2:使用copy:变量=列表.copy()
20.8 列表嵌套
person_info=[['zhangshan','18','功能测试'],['lisi','20','自动化测试']]
print(person_info) #['zhangshan','18','功能测试'],['lisi','20','自动化测试']
print(len(person_info) ) #2
print(person_info[0]) # ['zhangshan','18','功能测试']
print(person_info[0][0]) #'zhangshan'
print(person_info[0][0][0]) #'z'
21 元组
元组tuple的特点和列表非常相似:元组可以存放任意类型的数据,元组中可以存放任意多个数据;区别在于元组中的数据内容不能改变,列表中的数据可以改变,元组使用(),列表使用[]
元组运用:在函数的传参或者返回值中使用,保证数据不会被修改
定义:使用 类实例化 或者 直接使用()方式
1.类实例化的方式
1.1 定义空元组(不会使用)
tuple1=tuple()
print(type(tuple1),tuple1) #<class 'tuple'> ()
1.2类型转换
tuple2=tuple([1,2,3])
print(tuple2)
转换字符串
tuple3=tuple('hello')
print(tuple3)
2.直接使用()定义
tuple4=(1,'小王',3.14,False)
print(tuple4)
3.特殊点,定义只有一个数据的元组时,数据后边必须有一个逗号
tuple5=(1,)
print(tuple5)
常用方法:由于在元组中的数据不能修改,所以只有查看的方法
1.在元组中也可以使用切片获取数据
2.在元组中存在index方法
3.在元组中存在count方法
4.在元组中可以使用in操作
以上方法和列表中一样
22 字典
字典dict,字典中的数据由键值对组成(键表示数据的名字,值就是具体的数据)
定义:变量={key:value, key :value....}
一个字典中的键是唯一的,不能重复的,值可以是任意数据
字典里的键一般都是字符串,可以是数字,不能是列表。
定义:
1.使用类实例化的方法
dict1=dict()
print(type(dict),dict1 )# <class 'dict'> {}
dict()不能转列表和元组,字符串
2.使用{}定义
2.1空字典
dict2={}
peint(type(dict2),dict2) #<class 'dict> {}
2.2非空字典,小明('name') 18('age') 1.71('height') True(is_men)
dict3={'name':小明,'age':18,'height':1.71,'is_men':True}
print(dict3)
print(len(dict3))
增加和修改操作:
语法:字典[键]=数据值
1.如果键已经存在,就是修改数据值
2.如果键不存在,就是添加数据(即添加键值对)
dict1={'name':小明,'age':18,'height':1.71,'is_men':True}
#添加性别信息
dict1['sex']='男'
#修改信息
dict['age']=19
删除:
删除指定键值对:del 字典[键] 或 字典.pop(键)
清空:字典.clear()
查询(根据键获取对应的值):
字典没有下标的概念,想要获取数据值,需要使用key(键)来获取
1.字典[键],如果键存在返回键对应的数据值,如果不存在,会报错
2.字典.get(键,数据值),数据值一般不写,默认是None,如果键存在,返回对应的数据值,如果不存在,返回的是括号书写的数据值
一般建议使用get方法
dict3={'name':小明,'age':18,'height':1.71,'is_men':True}
print(dict3.get('sex',‘保密’)
遍历字典:
1.遍历字典的值
语法:#字典.values可以获取字典中所有的值
for 变量 in 字典.values():
print(变量)
2.遍历字典的键
语法1:
for 变量 in 字典:
print(变量)
语法2:
for 变量 In 字典.keys():
print(变量)
3.遍历字典的键值对
语法:#字典.items()获取键值对
for 变量1,变量2 in 字典.items():
print(变量1,变量2)
23 容器部分总结
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 关键字在任何容器中都能使用,注意,容器中判断是字典的键是否存在
24 列表去重
方法1:
思路 :遍历原来列表中的数据判断是否在新列表中存在,如果不存在,就放进新列表,如果存在则不管
遍历使用for实现
判断是否存在可以使用in
存入数据使用:append
方法2:
思路:使用集合 set,特点是集合中不能使用重复的数据(如果有重复的数据会自动去重),使用set()类型将列表转换为集合类型,再使用list()类型将集合转换为列表
缺点:不能保证数据再原列表中出现的顺序,一般来说,也不考虑这件事
法一:
mylist=[1,2,3,3,2,1,2,3,1]
newlist=[]
for i in mylist:
if i not in newlist:
newlist.append(i)
print(newlist)
法二:
mylist=[1,2,3,3,2,1,2,3,1]
set(mylist)
list(set(mylist)
25 函数
好处:减少代码的冗余,重复的代码不用多写
函数必须先定义后使用:
定义语法:
def 函数名():
函数中的代码
1.def 是关键字,是用来定义函数的,define的缩写
2.函数名需要遵守标识符的规则
3处于def缩进中的代码,称为函数体
4.函数定义的时候,函数体中的打开吗不会执行,在调用的时候才会执行
函数使用:
语法:函数名()
文档注释:
文档注释的本质还是注释,只不过书写的位置和作用比较特殊
书写位置:在函数名下方使用,三队双引号进行的注释
作用:告诉别人这个函数如何使用
查看:在调用的时候,将光标放到函数名上,使用快捷键ctrl + q直接查看,使用ctrl+b转到函数声明中查看
函数参数
def mysum(num1,num2):#num1,num2是函数定义时候的参数,起到占位符的作用,没有具体的数据值,简称 形参
print(num1+num2)
mysum(1,2) #函数调用时括号中的数据会传递给形参,是具体的数据值,称为实际参数,简称 实参,调用时参数类型与顺序和个数,都要与定义的函数一一对应。
完整的参数顺序:
def 函数名(普通函数, *args,缺省参数, **kwargs):
函数返回值return:
return关键字只能在函数中使用
作用:代码执行遇到return,会结束函数的执行
场景:需要使用函数处理过的数据
def 函数名字1():#返回值None
pass #代码中没有return
def 函数名字2():#return后面没有数据,返回值None
return
def 函数名字3():#返回值是xx
return xx
函数返回多个数据值
函数想要返回一个数据值,使用return关键字
将多个数据值组成容器进行返回,一般是元组(组包)
def cal(a,b):
num1=a+b
num2=a-b
return num1,num2
方法一:
result=cal(10,5)
print(result,result[0],result[1]) #输出(15,5) 15 5
方法二:直接拆包
x,y=cal(10,5)
print(x,y)
函数传参:
包括位置传参和关键字传参,还有 混合使用
位置传参:在函数调用的时候,按照形参的顺序,将实参值传递给形参
关键字传参:在函数调用的时候,指定数据值给到哪个形参
混合使用:关键字传参必须写在位置传参的后面,不要给一个形参指定多个实参
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=2)
缺省参数:
缺省参数,默认参数
1.在函数定义的时候给形参一个默认的数据值,这个形参就变为缺省参数,注意缺省参数的书写要放在普通参数的后面
2.好处:缺省参数在函数调用的时候,可以传递实数值也可以不传递实数值
多参传递[可变参数/不定长参数]:
1.不定长位置参数(不定长元组参数)
在普通参数的前边,加上一个 * ,这个参数就变为不定长参数,这个形参就可以接收任意多个传参的数据,其数据类型是 元组 ,一般写法 * args,其中args表示不定长位置参数的名字
2.不定长关键字参数(不定长字典参数)
一般是在普通参数的前边加上两个 * (即 ** ),这个参数就变为不定长关键字参数,这个形参就可以接收任意多个传参的数据,其数据类型是 字典,注意不定长关键字参数要写在所有参数的最后边,一般写法 **kwargs (kwargs表示不定长关键字参数的名字
def func(*args,**kwargs):
print(type(args),args) #print默认会有换行效果
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) #混合传参,前三个数据给了args,后三个给了kwargs)
匿名函数:
使用lambda关键字定义的函数称之为匿名函数(使用def关键字定义的函数是 标准函数),匿名函数一行只能书写一行代码, 匿名函数的返回值不需要return,一行代码(表达式)的结果就是返回值,也不需要我们主动调用,一般作为函数的参数使用
语法:lambda 参数:一行代码
- 分类:
- 无参无返回值
- 无参有返回值
- 有参无返回值
- 有参有返回值
1.无参无返回值:
def func1():
print('hello')
等价于 lambda : print ('hello')
调用匿名函数:
func11=lambda : print ('hello')
func11()
不要对匿名函数起名字,要不然就直接使用def就成了
2.无参有返回值
def func2():
return 10
lambda : 10
3. 有参无返回值
def func3(a,b):
print(a)
等价于:lambda a,b :print(a)
4.有参有返回值
def func4(a,b):
return a+b
lambda a,b :a+b
练习:
1.求两个数的积:lambda a,b :a*b
2.定义一个匿名函数,其参数(参数只是一个占位的作用,定义的时候没有具体的数值,形参的类型是由实参决定的)为字典,返回字典中键为age的值
lambda x:x.get('age')或lambda x:x['age']
应用:
匿名函数作为函数的参数,列表中的字典排序
userlist=[
{'name':'zhangsan','age':18},
{'name:'lisi','age':19'},
{'name:'wangwu':,'age':17}
]
#userlist.sort()会报错,因为列表的排序默认是对列表中的数据进行比较大小,而且仅仅可以对 数字类型和字符串类型 进行比大小,对于字典来说,我们需要使用sort函数中key这个参数,来指定字典比较大小的方法,key这个参数需要传递一个函数,一般是匿名函数,字典的排序其实是要指定字典的什么进行排序
userlist.sort(key=lambda x:x['age'])
userlist.sort(key=lambda x:x['age'],reverse=True)
#说明:userlist.sort(key=lambda x:x['age'])这个匿名函数中的参数是 列表中的数据,在sort函数内部,会调用Key这个函数,从列表中获取函数的返回值,对返回值进行比较大小操作
26 变量进阶
变量的引用:
1.在定义变量的时候 变量=数据值,python解释器会在内存中开辟两块空间
2,变量和数据都有自己的空间
3,日常简单理解,将数据保存到变量的内中中,本质是将数据的地址保存到变量对应的内存中
4,变量中存储数据地址的行为就是引用(变量引用了数据的地址,简单来说就是变量中存储数据),存储的地址称为引用地址
5,可以使用id()来获取变量中的引用地址(即数据的地址),如果两个变量的id()获取的引用地址一样,即代表着两个变量引用了同一个数据,是同一个数据
6.只有赋值运算符=,可以改变变量的引用(等号左边数据的引用)
7,python中数据的传递,都是传递的引用
a=1 #将数据 1 的地址 存到a对应的内存中
print('a',id(a))
b = a#将 变量 a 的引用保存到变量 b
print('b',id(b))
a=10 #将数据 10 的地址 存到a对应的内存中,即 a 的引用变了
print('a',id(a))
print('b',id(b) #b还是 数据 1 的内存地址
27 可变类型和不可变类型
数据类型:int float bool str list tuple set dic
可变不可变是指:数据所在的内村是否允许被修改,允许修改就是可变类型,不允许修改就是不可变类型(不使用=,变量引用的数据中的内容是否会变化,会变化是可变的,不会变化是不可变的)
可变类型:列表 list,字典 dict,集合 set
列表.append(),字典.pop(键)
不可变类型:int float bool str tuple
mylist=[1,2,3]
mylist1=[1,2,3]
print('mylist',id(mylist),id(mylist1))
print('mylist1',id(mylist1))
mylist[1]=10
print(mylist)
print('mylist',id(mylist),id(mylist[1]))
mytuple=(1,2,[3,4])#元组中存储1的地址,2的地址 和 列表的地址
print(mytuple,id(mytuple[-1])
mytuple[-1][0]=10 #修改的是列表中下标为0 的位置的引用地址,列表的地址没变,元组的内容没有变化
print(mytuple,id(mytuple[-1])
#只是把引用地址里面的数字给改变了,但是地址还是没有变
28 组包和拆包
组包(pack):将多个数据值用逗号连接,组成元组
拆包(unpack):将容器中的数据值使用多个变量分别保存的过程,注意:变量的个数和容器中数据的个数要保持一致
a=10
b=20
c=b,a #组包
print(type(c),c) #输出<class 'tuple'> (10,20)
a,b=c #拆包
print(a,b) #输出 10 20
x,y,z=[1,2,3]
print(x,y,z) #输出为 1 2 3
赋值运算符都是先执行等号右边的代码,执行的结果,保存到等号左边的变量
函数中的拆包:
def mysum(*args,**kwargs):
for i in args:
num+=i
for j in kwargs.values():
num +=j
print(num)
#需求,mylist=[1,2,3,4],字典mydict={'a':1,'b':2,'c':3,'d':4}
#将字典和列表中的数据使用mysum函数进行求和,该如何传参的问题
mysum(1,2,3,4)
mysum(a=1,b=2,c=3,d=4)
#想要将列表中的数据,分别作为位置参数,进行传参,需要对列表进行拆包操作
mylist=[1,2,3,4]
mysum(* mylist)
#想要将列表中的数据,分别作为关键字参数,进行传参,需要对字典进行拆包操作
mylist=[1,2,3,4]
mydict={'a':1,'b':2,'c':3,'d':4}
mysum(* * mydict)
29 局部变量和全局变量
局部变量:在函数内部(函数的缩进中)定义的变量,称之为局部变量
- 特点
- 局部变量只能在当前函数内部使用,不能在其他函数和函数外部使用,
- 在不同函数中可以定义名字相同的局部变量,两者之间没有影响
- 生存周期(生命周期,作用范围):在函数被调用的时候,局部变量被创建,函数调用结束,局部变量被销毁(删除),不能使用
- 所以函数中的局部变量的值,如果想在函数外使用,则需使用关键字"return",将这个值返回
全局变量:在函数外部定义的变量,称之为额全局变量
- 特点
- 可以在任何函数中读取(获取)全局变量的值
- 如何在函数中存在和全局变量名字相同的局部变量,在函数中使用的是 局部变量的值(就近)
- 在函数内部想修改全局变量的引用,需要添加 global 关键字,对变量进行声明为全局变量
- 生命周期:在代码执行的时候被创建,代码执行结束被销毁
30 print()函数
end='\n'表示每一个print函数结束,都会打印的内容 (结束符),默认是换行,若想修改使用如print(1,end=' ') print(2)print(3,end=' * ')
sep=' '表示多个位置参数之间的间隔,修改如下:print(1,2,3,4,5,6,sep='__') print(1,2,3,sep= ' * '
31 面向对象
面向对象是一个编程思想(写代码的套路) ,编程思想包括 面向过程 和 面向对象
在程序代码中 , 对象 由 类 创建
类是抽象的概念,对 多个特征和行为相同或者相似的事物的统称,泛指
对象是具体存在的一个事物,特指
类的组成:
类名:满足大驼峰命名法,即每个单词的首字母大写
属性:事物的特征,一般文字中的名词
方法:事物的行为,一般是动词
步骤:
1,定义类
先定义简单的类,不包含属性,使用关键字class
方法:方法的本质是在class中定义的函数,只不过第一个参数是self
2.创建对象
使用 类名() 进行创建
常用语法:变量=类名() ,这个变量保存的是对象的地址,一般可以称为这个变量为对象
3.调用方法
语法:对象.方法名()
class Cat:
def eat(self):
print('eat fish')
def drink(self):
print('drink water')
blueCat=Cat()
blueCat.eat()
blueCat.drink()
blackCat=Cat()
blackCat.eat()
blackCat.drink()
self的说明:
从函数语法上来说.self是形参,就可以是任意的变量名,只不过问你习惯性将这个形参协作self
self是普通的形参,但是在调用的时候没有传递实参值,原因是python解释器在执行代码的时候,自动将调用这个方法的对象传递给self,
属性:
1.添加属性:
分为 外部添加 和 类内部添加,
语法:对象.属性名=属性值
1.1 内部添加
在内部方法中,self是对象
self.属性名=属性值
在类中添加属性一般写做 _init_方法中
1.2类外部添加
对象.属性名=属性值 #一般不使用
2.获取属性
语法:对象.属性名
2.1内部获取
在内部,self是对象
self.属性名
2.2 外部获取
对象.属性名
魔法方法:
在python中有一类方法,以两个下划线结尾,并且在满足某个条件的情况下,会自动调用,这里方法称为魔法方法
1._init_方法
创建对象之后自动调用,用于给对象添加属性(初始化方法,构造方法)
class Cat:
def _init_(self):
self.name='blueCat'
self.age=2
def show(self):
print({self.name},{self.age})
cat1=Cat()
cat1.show()
2,_str_方法
使用print(对象)打印对象的时候会自动调用,适用于想要打印对象的时候想要查看什么信息,在这个方法里面定义,需注意,这个方法必须返回一个字符串
class Cat:
def _init_(self):
self.name='blueCat'
self.age=2
def _str_(self):
return "1"
def show(self):
print({self.name},{self.age})
cat1=Cat()
cat1.show()
3,_del_方法
对象对销毁之后自动调用
class Cat:
def _init_(self):
self.name='blueCat'
self.age=2
def _str_(self):
return "1"
def _str_(self):
print('没了')
def show(self):
print({self.name},{self.age})
cat1=Cat()
cat1.show()
cat2.Cat()
print('代码运行结束')
4.__dict__
为魔法属性
可以将对象具有的属性组成字典返回
使用:对象名.__dict__
实例1:
小明体重70KG,跑步廋0.5KG,吃东西胖1KG
class Person:
def _init_(self,name,weight):
self.name=name
self.weight=weight
def _str_(self):
return f"姓名{self.name},"体重"{self.weight}"
def run(self):
print(f'{self.name}廋了')
self.weight-=0.5
def eat(self):
print('f{name}胖了')
self+=1
xm=Person(小明,75)
print(xm)
xm.run()
xm.eat()
实例2:
需求是某web项目登入页面包括:用户名,密码,验证码,登录按钮和登录的方法,书写代码实现上述功能,登录方法使用print输出即可
class LoginPage:
def _init_(self,username,password,code):
self.username=username
self.password=password
self.code=code
self.btc='登录'
def login(self)
print(f'输入用户名{self.username}')
print(f'输入密码{self.password}')
print(f'输入验证码{self.code}')
print(f'点击按钮{self.btn}')
login=LoginPage('admin','123456','8888')
login.login()
私有和公有:
访问控制分为两种权限,公有和私有
公有权限表示在任意地方可以访问和使用
私有权限表示只能在当前类的内部使用
某个属性或者方法,不行在类外部被访问和使用,就将其定义为私有即可
测试中,一般不怎么使用的直接公有即可
开发中会根据需求文档,确定什么作为私有
如果想要在类外操作私有属性,一般是在类内部定义公有的方法,我们通过这个方法去操作私有属性
class Person:
def _init_(self,name,age):
self.name=name #公有
self._age=age#私有,私有的本质是python解释权执行代码,发现属性名或者方法名前有两个_,会将这个名字重命名,会在这个名字的前面加上_类名前缀,如self.__age变成 self._Peerson__age,如果想在类外打印,可以使用print(xm._person__age),平常时不要用
def _str_(self):
return f'{self.name},age:{age}'
xm=Person('xiaoming',,18')
print(xm)
print(xm._age)
print(xm.name)
面向对象的三大特性:
封装,继承.多态
继承的语法:class 类名(父类名)
父类又称之为基类,子类又称之为派生类
继承之后的特点:子类继承父类之后,子类的对象可以直接使用父类中定义的公有属性和方法
python中对象.方法()调用方法,如果自己的类中有就用本身的,如果没有就去父类找,全没有就报错
重写:在子类中定义和父类名字相同的方法
重写的原因:父类中的方法,不能满足子类对象的需求,所以重写
重写之后的特点:调用子类自己的方法,不再调用父类的方法
重写分为覆盖和拓展(保留父类中的功能)
覆盖:直接在子类中定义要覆盖的父类方法就可以
拓展:在子类定义的父类方法中的适宜位置调用super().方法()
多态:不同的子类对象 调用相同的父类方法,产生不同的执行结果;是调用方法的技巧,不会影响类的内部设计
class Person:
def work(self):
print('人需要工作')
class Coder(Person):
def work(self):
print('开发人员-->工作是写代码')
class Tester(Person):
def work(self):
print('测试人员-->工作是测试项目')
class Company:
def show_work(worker):
worker.work()
c=Company()
xw=Coder()
xh=Tester()
c.show_work(xw)
c.show_work(xh)
实例对象:
通过 类名() 创建的对象,我们称之为实例对象,简称实例
创建对象的过程称之为实例化
每个实例对象都有自己的内存空间,在自己的内存空间中保存自己的属性(实例属性)
类对象:
类对象 就是类,或者可以认为是类名
类对象就是 python 解释器在执行的过程中创建的
类对象的作用:使用类对象创建实例,类对象有且只有一份自己的内存空间,可以保存一些信息
实例属性:
在init方法中使用self.属性名=属性值 定义,在方法中使用self.属性名 来获取(调用)
类属性:
在类内部,方法外面直接定义的变量就是类属性,通过 类对象.属性名=属性值 或者 类名.属性名=属性值 来定义,使用 类对象.属性名 或 类名.属性名 获取
使用技巧:找多个对象,来判断这个值是不是一样的,如果都是一样的,同时变化,则一般定义为 类属性,否则就定义为 实例属性
练习:
定义一个dog类,定义一个类属性count,用来记录该类创建类几个对象,实例属性name
class Dog:
count=0 #定义类属性
def __init__(self,name)
self.name=name #实例属性
Dog.count++ # 因为每创建一个对象,都需调用一遍__init__
print(Dog.count)
dog1=Dog('xh')
print(Dog.count)
dog2=Dog #不是创建对象,个数不变
print(Dog.count)
dog3=dog1 #不是创建对象,个数不变
print(Dog.count)
dog4=Dog('xx')
print(dog1.count)
print(dog4.count)
方法的划分:
方法,使用def关键字定义在类中的函数就是方法
实例方法:
在类中直接定义的方法就是实例方法
如果在方法中需要使用实例属性(即需要使用self),则这个方法必须定义为 实例方法\
调用: 对象.方法名() #不需要给self传参
class Demo:
def func(self):
类方法:
在方法的名字上方书写@classmethod装饰器(使用 @classmethod装饰的方法)
使用前提是方法中不需要使用 实例属性(即self),用到类属性,可以将这个方法定义为类方法(也可以定义为实例方法)
调用 : 类名.方法名() #不需要给cls传参,python解释器自动传递 与 实例.方法名() #不需要给cls传参,python解释器自动传递
class Demo:
@classmethod
def func(cls):#参数一般写作cls,表示的是类对象(即类名)class
静态方法:
在方法的名字上方书写@staticmethod装饰器(使用 @staticmethod装饰的方法)
使用前提是方法中不需要使用 实例属性(即self),也不用到类属性,可以将这个方法定义为静态方法
调用:类名.方法名 或 实例.方法名
class Demo:
@staticmethod
def func():#参数一般不写
补充:
哈希(hash):是一个算法,可以对数据产生一个唯一的值(类似于指纹)
is 可以判断两个对象是不是同一个对象,即 两个对象的引用是否相同
a is b==>id(a)==id(b)
==值用于判断数据值是否相等,is判断引用是否相等
32 文件
作用:将数据长期保存下来,在需要的时候使用
文件中存储的数据都是以2进制的形式存储
可以根据 "文件中的二进制内容,能否使用记事本软件将其转换为文字 " 将文件分为 文本文件 和二进制文件 两种
文本文件能使用记事本打开(能用记事本转换为文字,如txt,md,py,html,css,js,json),二进制则不能 (如 exe,mp3,mp4,jpg,png)
文件操作的步骤:1.打开文件(将文件从磁盘/硬盘 ) 中读取到内存中 2.读或者写文件 3.关闭文件
打开文件:
语法:open(file,mode='r',encoding=None)
file是要打开的文件,类型是字符串,文件的路径可以是绝对路径或者相对路径,建议使用相对路径;mode默认参数(缺省参数),表示的是打开文件的方式,r 表示只读打开,w表示打开写,a表示追加打开即在文件的末尾写入内容;参数encoding表示编码方式,表述文件和二进制如何进行转换
返回值返回的是 文件对象,后续对文件的操作,都需要这个文件
写文件:
向文件写入指定内容
前提:文件的打开方式是a或者w
语法:文件对象.write('写入的内容')
返回值是写入文件的字符数,一般不关注
读文件:
将文件中的内容读取出来
前提:文件的打开方式需要是r
语法:文件对象.read(n),参数n表示读取多少个字符,一般不写,表示读取全部内容
返回值:读取到的文件内容,类型是字符串
关闭文件:
将文件占用的资源进行清理,同时会保存文件,文件关闭之后,这个文件对象就不能使用
语法:文件对象.close()
1.写文件
f=open('a.txt','w',encoding='utf-8')#文件不存在就会直接创建文件,文件存在就会覆盖原文件
f.write('好好学习')
f.close()
open('a.txt','w',encoding='utf-8')
f.write('学习')
f.close()
open('a.txt','w',encoding='utf-8')
f.write('好好学习\n')
f.write('学习')
f.close()
2.读文件
f=open('a.txt','r',encoding='utf-8') #r方式打开,如果文件不存在就会报错
buf=f.read()
print(buf)
f.close()
使用with open 打开文件
with open()打开文件的好处:不用自己书写关闭文件的代码,会自动关闭
语法:with open(file,mode,encoding='utf-8') as 变量:
#缩进去读或者写文件
#缩进中的代码执行结束,出缩进之后,文件会自动关闭
with open(file,a,encoding='utf-8') as f:
f.write('好好学习')
#使用a,如果文件不存在,就新建,存在就在末尾追加新内容
按行读取文件:
with open(file,encoding='utf-8') as f:#没有写code的话,默认传递参数a
buf=f.readline()
print(buf)
print(f.readline) #会读取第二行的内容
print(f.readline) #会读取第三行的内容
读取所有行:
with open(file,encoding='utf-8') as f:
for i in f:
print(i)
json文件:
json文件也是一个文本文件,就可以直接使用read() 和write()方法去操作文件,只是说那个这两个方法不方便,所以对json文件有自己独特的读取和写入方法
常用在做测试的时候,将测试数据定义为json文件格式,使用代码读取json文件,即读取测试数据,进行传参(参数化)
json基于文本(是一个文本文件,不能包含图片视频等),独立于语言(不是某个语言特有的,每种编程语言都可以使用)的轻量级(与其他格式相比,占用的大小比较小)的数据交换格式 (后端程序员给的数据,比如json,html,xml)
json文件的后缀是.json
json中主要的数据类型为对象({}类似python字典)和数组([类似于python中的列表),对象和 数组可以相互嵌套
一个json文件是一个对象或者数组(即json的最外层要么是一个{},要么是一个数组[]
json中的对象是由键值对组成,每个数据直接使用逗号隔开,但是一个数据后边不要写逗号
json中的字符串必须使用双引号
json的书写:
{
“name”:“小康”,
“age”:true,
“like”:[
“听歌”,
“游戏”,
“睡觉”
],
“adrress”:{
“country”:“中国”,
“city”:“上海”
}
}
读取json文件
导包import json,读打开文件,读文件json.load(文件对象)
返回的是字典(文件中是对象)或者列表(文件中是数组)
import json
with open('info.json',encoding='utf-8') as f:
result=json.load(f)
print(type(result))
print(result.get('name'))
print(result.get('address').get('city')
)
json的写入
文件对象.write(字符串)不能直接将python的列表和字典 作为参数传递
想要将python中的数据存为json文件,需要使用json提供的方法,不再使用write
步骤:1导包 import json,2写方式打开文件3写入json.dump(python中的数据类型,文件对象)
import json
mylist=[('admin','123456','登录成功'),('root','123456','登录失败')]
with open('info.json','w',encoding='utf-8') as f:
json.dump(mylist,f,ensure_ascii=Falsep,indent=4)
json.dump(mylist,f,ensure_ascii=Falsep,indent=2)
33 异常
程序运行时,如果python解释器遇到一个错误,会停止程序的运行,并且提示一些错误信息,这就是异常
程序停止执行并且提示错误信息这个动作,抛出异常(raise关键字)
捕获异常:程序遇到异常,默认动作是终止代码程序的执行,遇到异常之后,可以使用异常捕获,让程序代码继续执行,不会终止运行
语法:
try :
书写可能发生异常的代码
excep 异常类型1:(只能捕获指定类型的异常,如果不是这个异常,还是会报错)
发生了异常执行的代码
excep 异常类型n:
发生了异常执行的代码
示例:
try :
num=input('请输入数字')
num=int(num)
print(num)
except ValueError:
print('请输入正确数字')
print('其他代码继续执行。。。')
异常捕获的完整格式:
try :
书写可能发生异常的代码
excep 异常类型1:
发生了异常执行的代码
excep Exception as 变量:
发生了异常执行的代码
else:
没有发生异常会执行的代码
finally:
不管有没有发生异常,都会执行的代码
异常传递:
在函数嵌套调用过程中,被调用的函数发生异常,如果没有捕获这个异常,就会向外层传递,如果传递到最外层还没捕获,才报错
34 模块和包
python源代码就是一个模块
模块中定义好的变量 函数 类 ,都可以让别人使用,同样可以使用别人定义的(好处:别人定义好的不需要我们再次书写,直接使用即可)
想要使用别人的模块泽东内容工具(变量 类 函数),就必须导入模块 才可以
我们自己写的代码,想要作为模块使用,代码的名字需要满足标识符的规则(由数字,字母中)
导入语法1:import 模块名 模块名.工具名
导入语法2:from 模块名 import 工具名
导入语法3:from 模块名 import *表示将模块中所有内容都导入
对于导入的模块都可以使用 as关键字给其起别名,但一旦起别名了,原来的名字就不能用了,只能使用别名
模块的查找顺序:
在导入模块的时候,会先在当前目录查找模块,如果找到就直接使用,如果没找到就回去系统的目录中进行查找,找到则直接使用,没找到就报错
需注意,定义代码文件的时候,我们的代码名字不能和我们要导入的模块名字相同
_name_的作用
每个代码文件都是一个模块,在导入模块的时候,会执行模块中的代码
_name_变量是python解释器自动维护的变量,如果代码是直接运行,值是“_main_“,如果代码是被导入执行,值是 模块名 (指代码文件名)
在python中,包是一个目录,只不过在这个目录存在一个文件 init.py,将功能相近或者相似的代码放在一起
在python中使用的时候,不需要区分是包还是模块,使用方法是一样的
import 包名或者alt➕回车
35 unittest
框架:为解决一类事情的功能集合
unittest框架是python自带的一个单元测试框架,用它来做单元测试
自带的框架:不需要单独安装,只需安装了python就可以使用
第三方框架:想要使用,需要先安装后使用pytest
单元测试框架,主要用来做单元测试,一般单元测试是开发做的,对于测试来说,unittest框架的作用是 自动化脚本(用例执行)执行框架,使用unittest框架来 管理 运行 多个测试用例的
使用unittset框架的原因:
能够组织多个用例去执行
提供丰富的断言方法(让程序代码代替人工自动的判断预期结果和实际结果是否相符)
能够生成测试报告
unittest核心要素(unittest的组成):
testCase(测试用例),注意这个测试用例是unittest框架组成部分,不是手工和自动化中我们所说的用例(test case),主要作用是每个testcase都是一个代码文件,这个代码文件中,来书写真正的测试用例
TestSuite(测试套件),用来管理 组装(打包)多个TestCase
TestRunner(测试执行),用来执行TestSuite
TestLoader(测试加载),用来TestSuite的功能补充,管理 组装(打包)多个TestCase的
Fixtrue(测试夹具),书写在TestCase代码中,是一个代码结构,可以在每个方法执行前后都执行的内容,每个用例重复的代码可以写在Fixture代码结构中,只写一遍,但每次用例方法的执行,都会执行Fixture中的代码
TestCase测试用例的书写
是一个代码文件,在代码文件中来书写真正的用例代码
代码文件的名字必须按照标识符的规则来书写(可以将代码的作用在文件开头进行标注)
步骤:
1.导包(unittest)
2.自定义测试类,需要继承unittest模块中的TestCase即可
3.在测试类中书写测试方法,即用例代码(目前没有真正的用例代码,使用print代替),书写要求是测试方法必须以test_开头(本质是以test开头))
4.执行用例,将光标放在类名后边运行,会执行类中所有的测试方法,光标放在方法名后边运行,会执行方法中所有的测试方法,
import unittest
class TestDemo(unittest.TestCase):
def test_method1(self):
print('测试方法1')
def test_method2(self):
print('测试方法2')
代码书写常见的错误:
1.代码文件命名不规范
比如代码文件名字以数字开头;代码文件名字中有空格;代码文件名字有中文;有特殊的符号(数字字母下划线以外的字符)
2.代码运行没有结果
右键运行没有unittests for提示,出现的问题
解决方案一:首先新建代码文件,将原来的代码复制进去新文件
解决方案二:删除已有的运行方式(点击右上角倒三角,然后点击 edit configurations,接着点击弹窗左上角的减号)
3.没有找到用例
测试方法中不是以test_开头或者单词写错了
TestSuilte和TestRunner的书写
步骤:
1.导包(unittest
2.实例化(创建对象)套件对象)
3.使用套件对象添加实例方法,建议测试类名和方法名直接去复制,不要手写
4.实例化运行对象
5.使用运行对象去执行套件对象
假设我们写了两个测试类TestDemo1和TestDemo2,每个类中都有两个测试方法test_method1和test_method2
方法一
import unittest
suite=unittest.TestSuite()
suite.addTest(TestDemo1('test_method1))
suite.addTest(TestDemo1('test_method2))
suite.addTest(TestDemo2('test_method1))
suite.addTest(TestDemo2('test_method2))
runner=unittest.TextTestRunner()
runner.run(suite)
方法二:将一个类中所有方法添加
import unittest
suite=unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestDemo1))
suite.addTest(unittest.makeSuite(TestDemo2))
runner=unittest.TextTestRunner()
runner.run(suite)
查看结果的方法:
结果的 . 表示一个用例通过(如果四个用例通过就四个 . ,以此类推),F表示用例不通过,E表示用例代码有问题
TestLoader使用
步骤:
1.导包(unittest
2.实例化测试加载对象并添加用例(得到的是suite对象)
3.实例化运行对象
4.使用运行对象去执行套件对象
TestLoader里的代码变成下面这样也要认得出来
# 导包
import unittest# 实例化加载对象并添加用例
# unittest.TestLoader().discover('用例所在路径','用例的代码文件名')
# 用例所在路径建议使用相对路径,用例的代码文件名可以使用 *(任意多个字符) 通配符
# suite = unittest.TestLoader().discover('./', 'TestA*.py')
suite = unittest.defaultTestLoader.discover('./', 'TestA*.py')
# 实例化运行对象
runner = unittest.TextTestRunner()
# 执行
runner.run(suite)
Fixture:
Fixture是一个概述,对一个测试用例环境的初始化和销毁就是一个Fixture
Fixture控制级别:方法级别,类级别,模块级别
方法级别:在每个测试方法(用例代码)执行前后都会自动调用的结构
类级别:在每个测试类中所有方法执行前后,都会自动调用的结构(在整个类中 执行之前执行之后各一次,类级别的fixture 是一个类方法
模块级别:在每个代码文件执行前后执行的代码结构
方法级别和类级别 的前后方法 ,不需要同时出现,按需自行选择使用
#方法级别
# 方法执行之前
def setup(self):# 每个测试方法之前执行pass# 用例代码放在这边def teardown(self):# 每个测试方法之后都会执行pass
#类级别
#类中所有方法之前
@classmethod
def setupClass(cls):pass#类中所有方法之后
@classmethod
def teardownClass(cls):pass
#模块级别
# 模块级别需要写在类的外边直接定义函数即可
# 代码文件之前
def setupModule():pass
# 代码文件之后
def teardownModule():pass
案例:
1,打开浏览器(整个测试过程中就打开一次浏览器) 类级别
2,输入网址(每个测试方法都需要一次) 方法级别
3,输入用户名和密码验证码点击登录 (不同的测试数据) 测试方法
4,关闭当前页面(每个测试方法都需要一次) 方法级别
5,关闭浏览器(整个测试过程就关闭一次浏览器) 类级别
----
1,打开浏览器(整个测试过程中就打开一次浏览器) 类级别
2,输入网址(每个测试方法都需要一次) 方法级别
3,输入用户名和密码验证码点击登录 (不同的测试数据) 测试方法
4,关闭当前页面(每个测试方法都需要一次) 方法级别
2,输入网址(每个测试方法都需要一次) 方法级别
3,输入用户名和密码验证码点击登录 (不同的测试数据) 测试方法
4,关闭当前页面(每个测试方法都需要一次) 方法级别
2,输入网址(每个测试方法都需要一次) 方法级别
3,输入用户名和密码验证码点击登录 (不同的测试数据) 测试方法
4,关闭当前页面(每个测试方法都需要一次) 方法级别
5,关闭浏览器(整个测试过程就关闭一次浏览器) 类级别
import unittestclass TestLogin(unittest.TestCase):def setUp(self):# "每个测试方法执行之前都会先调用的方法"print('输入网址...')def tearDown(self) -> None:# "每个测试方法执行之后都会先调用的方法"print('关闭当前页面...')@classmethoddef setUpClass(cls) -> None:print('1.打开浏览器')@classmethoddef tearDownClass(cls) -> None:print('5.关闭浏览器')def test_1(self):print('输入正确的用户名密码验证码,点击登录1')def test_2(self):print('输入正确的用户名密码验证码,点击登录2')
36 断言
让程序代替人工自动的判断预期结果和实际结果是否相符
断言的结果有两种:true(表示用例通过),False(代码抛出异常,用例不通过)
常用断言语法 解释
assertEqual(预期结果a, 实际结果b) 判断a==b
assertNotEqual(a, b) 判断a!=b
assertTrue(x) bool(x) is True
assertFalse(x) bool(x) is False
assertIs(a, b) a is b
assertIsNot(a, b) a is not b
assertIsNone(x) x is None
assertIsNotNone(x) x is not None
assertIn(预期结果a,实际结果 b) a in b预期结果是否包含在实际结果中
assertNotIn(a, b) a not in b
assertIsInstance(a, b) isinstance(a, b)
assertNotIsInstance(a, b) not isinstance(a, b)
例子:
asserIn('admin','admin') #包含
asserIn('admin','adminnnnnn') #包含
asserIn('admin','aaaaaaadmin') #包含
asserIn('admin','aaaaadmimnnnnn') #包含
asserIn('admin','addddmin') #不包含
37 参数化
在测试方法中,使用 变量 开替代具体的测试数据,然后使用传参的方法将测试数据传递给方法的变量
好处:相似的代码不需要多次书写
工作中的场景:测试数据一般放在json文件中,使用代码读取json文件,提取我们想要的数据
unittest 框架本身不支持参数化,但是可以通过安装unittest拓展插件parameterized来实现
安装语句:pip install parameterized
验证:pip list可以查看到parameterized
参数化代码:
1.导包
2.定义测试类
3.书写测试方法(用到的测试数据使用变量替代)
4.组织测试数据
import unittest
import Add(要测试的自己写的类,里面有个自己写的方法add)
data[
(2,3,5),(1,2,3),(8,9,17)
]
class Test(unittest.TestCase):
@parameterized.expand(data)
def testAdd(self,num1,num2,except)
self.assertEqual( except,Add.add(num1,num2))
如果数据在data.json文件里,代码可以变更为
import unittest
import Add(要测试的自己写的类,里面有个自己写的方法add)
def build_data():
with open('data.json'),encoding='utf-8') as f:
result=json,load(f)
data=[]
for i in result:
data.appned(i.get('num1'),i.get('num2'))
return data
class Test(unittest.TestCase):
@parameterized.expand(data)
def testAdd(self,num1,num2,except)
self.assertEqual( except,Add.add(num1,num2))
常见错误
1.no such file for directory :'xxxxx'
查看是否文件名写错了
2.'NoneType' object is not iterable数据是空的
跳过:
对于一些未完成或者不满足测试条件的测试函数和测试类,可以执行跳过
使用方式:@unittest.skip('跳过原因')可以直接将测试函数标记为跳过;@unittest.skipIf(condition,reason)可以根据条件判断测试函数是否跳过 ;注意上述两种方法要写在TestCase里
38 测试报告
自带的测试报告:只有单独运行TestCase的代码,才会生成测试报告
生成第三方的测试报告:HTMLTestRunner是一个第三方库,用来执行测试用例并生成HTML格式的测试报告,需注意,下载的python文件要与python兼容(有的版本只支持python2.x)
1.获取第三方的 测试运行类模块,将其放在代码的目录中
2.导包unittest
import unittest
from HTMLTestRunner import HTMLTestRunner
3.使用 套件对象,加载对象 去添加用例方法
suite = unittest.defaultTestLoader.discover('.',Add.py')
4.实例化 第三方的运行对象 并运行 套件对象
#HTMLTestRunner()
#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') #运行对象
#运行对象执行套件.要写在with的缩进中
runner.run(suite)
中文化测试报告:
import unittest
from HTMLTestRunneCNr import HTMLTestReportCN
suite = unittest.defaultTestLoader.discover('.',Add.py')
with open('report.html','wb') as f:
runner =HTMLTestReportCN(f) #运行对象
runner.run(suite)
1.组织用例文件(TestCase里边),书写参数化,书写断言.书写Fixture,书写 跳过,如果单个测试文件,直接运行,得到测试报告,如果多个测试文件,需要组装运行生成测试报告
2.使用 套件对象组装,加载对象组装
3.运行对象 运行
3.1运行对象=第三方的运行类(文件对象(打开文件需要使用wb方式))
3.2运行对象.run(套件对象)