01-字符串+列表与元组
字符串的概念
字符串是 Python 中最常用的数据类型。我们可以使用引号来创建字符串。
str1='Hello' #单引号的字符串
str2="Hello" #双引号的字符串
str3='''Hello''' #三引号的字符串
字符串中本身有单引号时,外面用双引号
str1="It's OK"
字符串中本身有双引号时,外面用单引号
str2='He said:"Are you ok?"'
三引号
三引号,可以用三个单引号''' ''',也可以用三个双引号""" """
在换行比较多的情况下,可以用三引号,这样就不需要手动输入换行符
字符串中既有单引号,也有双引号的场合,用三引号
三引号也可以用于函数或方法的注释
str3='''独坐幽篁里
弹琴复长啸
深林人不知
明月来相照'''
print(str3)
def fun1():
'''
:return:
'''
字符串中的转义符
# \n 换行符 \t 制表符
filepath='D:\note1.txt'
print(filepath) #这样打印,filepath中的\n进行了转义
#方案一 在\前面再加一个\,后面的\不进行转义
filepath='D:\\note1.txt'
#方案二 在字符串外面加一个r,字符串中的所有转义符均不进行转义
filepath=r'D:\note1.txt'
#方案三 表示路径时,可以用/代替\
filepath='D:/note1.txt'
字符串的拼接
print('1'+'6') #1和6拼接,打印16
print('1'+6) #字符串与数字拼接,报错
print('1'*6) #表示将字符串打印6次
a=5
b='6'
print(a+int(b)) #int(),将对象转为整数型,float(),将对象转为浮点型,str()将对象转为字符串型
字符串的下标
#下标以 0 为开始值,-1 为从末尾的开始位置。
str6='abcdefg'
print(str6[5]) #取得第5位的值,f
print(str6[-2]) #取得倒数第二位的值,f
str6[0]='q' #字符串是不可变对象,不可以通过下标修改某个位置的值
字符串的切片
[起始值:终止值:步长] 包含起始值,不包含终止值 步长默认为1
print(str6[0:3]) #abc
print(str6[-7:-4]) #abc
print(str6[:-4]) #起始值不写,表示从头开始取值
#步长为正数时,从左向右取值,步长为负数时,从右向左取值
print(str6[2::-1]) #终止值不写,表示取到后面所有的值
print(str6[:]) #全部取值,注意切片是一个新的对象,不影响原对象的值
print(str6[::2]) #aceg
切片是一个新对象,不影响原对象
str9='aabbccddee'
str9_new=str9[0:2]
print(str9)
print(str9_new)
字符串翻转
print("-----------------字符串翻转---------------------")
# 切片
s = "Hello, World!"
reversed_s = s[::-1]
print(reversed_s) # 输出 "!dlroW ,olleH"
# json和reversed
s2 = "Hello, World!"
reversed_s2 = ''.join(reversed(s2))
print(reversed_s2) # 输出 "!dlroW ,olleH"
#循环
s3 = "Hello, World!"
reversed_s3 = ''
for x in s3:
reversed_s3 = x + reversed_s3
print(reversed_s3) # 输出 "!dlroW ,olleH"
列表与元组
列表的概念
列表是Python以及其他语言中最常用到的数据结构之一。Python中使用中括号[]来表示列表
列表可以存放任意类型的对象
list1=[1,'abc',[10,20],(10,20),{'A':'apple'}]
列表是可变对象
list2=[10,20,30,40,50]
list2[0]=198
新增元素
append()方法,添加元素到列表末尾
list2.append(60)
insert()方法,添加元素到指定位置
list2.insert(1,60)
extend()方法,列表的拼接
list2_1=[100,200]
list2_2=[300,400]
list2_1.extend(list2_2)
print(list2_1)
删除元素
pop()方法,默认删除列表末尾的元素,也可以指定位置进行删除
list3=[100,200,300,400,500,500]
list3.pop(0)
print(list3)
remove()方法,根据值进行删除
list3.remove(500)
print(list3)
del的方式进行删除
del list3[2]
print(list3)
列表的切片
列表的切片,也是一个新的对象,不影响原列表的值
list6=[11,22,33,44,55,66]
print(list6[0:3])
print(list6[-6:-3])
print(list6[-4::-1])
元组
元组与列表类似,都可以使用下标与切片,但是元组是不可变对象,不能进行增删改
tuple1=(11,22,33,44,55,66)
tuple2=(10,) #当元组中只有一个值时,加个逗号
print(type(tuple2))
如果元组中有子列表,子列表的值可以修改
tuple3=(10,20,30,40,50,[1,2])
tuple3[5][0]=99
print(tuple3)
02-布尔表达式+条件判断
布尔表达式
布尔表达式有true(真)和false(假)两个取值。
在python中,=表示赋值,==表示判断恒等
print(100==100) #判断等式左侧和右侧是否相等
字符串比较时,根据ASCII码进行判断 a=97 A=65
print('a'=='A')
print('a'>='A') #True
字符串的比较,只比较第一位
print('aA'=='Aa') #False
True和False可以参与算术运算,True相当于1,False相当于0
print(True+True+True+True+True)
in,not in
list1=[10,20,[80,90,100]]
print(10 in list1) #True
print(80 in list1) #False
and,or
print(2>1 and 1>2) #一假为假,全真为真
print(2>1 or 1>2) #一真为真,全假为假
not,and,or组合条件 优先级not>and>or
print(2>1 and 1>2 or 3>2 and not False)
print(2>1 and 1>2 and not 1 or 3>2) #not 1相当于not True,not 0相当于not False
在python中,!=表示不等于
print('a'!='A')
isinstance() 判断某个对象是否属于某个类,返回值为布尔型
print(isinstance(100.1,float))
浅拷贝与深拷贝
赋值(多了个名字而已)
list2=[1,2,3,4,5,6,[7,8]]
list2_new=list2 #赋值,对列表赋值时,相当于起了一个别名,两者指向的是同一个对象
list2[0]=96
print(list2,id(list2))
print(list2_new,id(list2_new))
浅拷贝(内存里是)
import copy
list2_new=copy.copy(list2) #浅拷贝,生成了一个新的对象,子列表仍然是同一个对象
list2[0]=96 #修改list2的值,不会影响list2_new
list2[-1][0]=1998 #修改list2的子列表的值,list2_new的值也会变化
print(list2,id(list2),id(list2[-1]))
print(list2_new,id(list2_new),id(list2_new[-1]))
切片,等价于浅拷贝
list2_new=list2[:] #相当于copy.copy(list2)
list2[0]=96
list2[-1][0]=1998
print(list2,id(list2),id(list2[-1]))
print(list2_new,id(list2_new),id(list2_new[-1]))
深拷贝
list2_new=copy.deepcopy(list2) #深拷贝,列表与子列表都是新的对象
list2[-1][0]=1998 #修改list2的子列表的值,不会影响list2_new
print(list2,id(list2),id(list2[-1]))
print(list2_new,id(list2_new),id(list2_new[-1]))
分支语句
缩进
python对于缩进是有比较严格的要求的,不需要缩进的地方不能缩进,需要缩进的地方必须缩进 python对于缩进几个空格没有强制性要求,可以1个,也可以多个,一般默认为4个空格
if 10>9: #如果if后面的布尔表达式为真,则执行下面的语句
print('Hello')
写一个程序,用户输入一个分数,如果大于等于90分,则打印"优秀",如果大于等于80分,则打印"不错",如果大于等于60分,则打印"及格",否则打印不及格
score=input('请输入一个数字: ') #input()读取用户的输入,返回值是str型
if score.isdigit(): #判断对象是否是由纯数字组成
score=int(score) #int()将对象转为整数型
if score>=90:
print('优秀')
elif score>=80:
print('良好')
elif score>=60:
print('及格')
else: #如果以上条件都不满足,则执行else中的语句
print('不及格')
复合条件语句
如果一个人的年龄大于60岁,并且为男性,我们称他为老先生
age=69
gender='male'
if age>60 and gender=='male':
print('老先生')
或者
if age>60:
if gender=='male':
print('老先生')
03-函数+对象的方法
函数
函数是一段封装的代码,在有需要的时候进行调用
def fun1(): #定义函数
print('Hello')
print(fun1()) #调用函数
函数的返回值
def fun2():
return 'Hello'
print(fun2())
函数的形参与实参
def sumdata(a,b): #a,b形式参数,简称形参
return a+b
print(sumdata(1,2)) #实际参数,简称实参
print(sumdata(1)) #实参的数量与形参的数量不相等,则报错
函数的缺省值
def sumdata2(a=100,b=80):
return a+b
print(sumdata2()) #用户不输入实参,则使用缺省值
print(sumdata2(1,2)) #用户输入了实参,则使用用户输入的值
print(sumdata2(1)) #用户输入了a的值,那么就是1+80=81
print(sumdata2(b=1)) #指定输入b的值,那么就是100+1=101
print(sumdata2(3,6)) #简略写法
print(sumdata2(a=3,b=6)) #完整写法
print(sumdata2(3,b=6)) #先简略写法,后完整写法
print(sumdata2(a=3,6)) #先完整写法,后简略写法,这种写法会报错
函数中可以有多个return
写一个函数,返回某数的绝对值
def absolute_value(n):
if n>=0:
return n
return 'Hello' #上一行的return语句执行完之后就退出了函数,之后的语句是不可达语句
else:
return -n
print(absolute_value(6))
函数可以return多个值,当有多个值时,以元组形式返回
def sumdata3(a,b):
return a+b,a-b,a*b,a**b
print(sumdata3(3,6))
列表是一个对象,所以返回时,直接返回列表,不需要以元组形式返回
def sumdata3(a,b):
return [a+b,a-b,a*b,a**b] #列表是一个对象,所以返回时,直接返回列表,不需要以元组形式返回
print(sumdata3(3,6))
print()函数可以传任意个参数
sep=’ ’ 间隔符的默认值为1个空格 end=‘\n’ 结束符的默认值为一个换行符
print(1,2,3,4,5,6,7,8,9,10,sep='/',end='') #内置函数
*args可变长度参数,允许用户传任意个参数
def fun6(a,*args):
return a,*args #这么写,可以少一层元组,这种写法称之为解包.这种写法在低版本的python中会报错
print(fun6(1,2,3,4,5,6))
低版本的python的写法
def fun6(a,*args):
return (a,*args) #低版本的python,这么写
print(fun6(1,2,3,4,5,6))
不解包的写法
def fun6(a,*args):
return a,args #这么写,会多一层元组
print(fun6(1,2,3,4,5,6))
#关键字参数 **kwargs
允许用户输入任意个参数,必须是x=y的格式,返回值是字典格式
def fun9(a,**kwargs):
return a,kwargs
print(fun9(1,A='apple',B='book'))
对象的方法
方法就是写在类当中的函数
index()方法 返回某个或某些字符在字符串中的下标,默认从第0位开始查找,也可以从指定的位置开始查找
str1='hytrevrwce'
print(str1.index('h')) #返回某个或某些字符在字符串中的下标,默认从第0位开始查找,也可以从指定的参数位置开始查找
print(str1.index('h',3)) #找不到时,抛异常
print(str1.find('h',3)) #找不到时返回-1
strip()方法 去掉字符串前后的空格,或者其他指定字符
str2=' nht br gvfr bnth b g '
print(str2.strip())
str2='********************nht br gvfr bnth b g****************'
print(str2.strip('*'))
replace(参数1,参数2) 参数1需要替换的字符,参数2 替换后的字符,replace的返回值是字符串,是一个新的字符串对象
print(str2.replace(' ',''))
str3='**** * * *** **abcde** ***'
print(str3.replace('*','').replace(' ',''))
startswith() 判断字符串是否以某个或某些字符开头
#根据身份证号码判断是否是南京的身份证
id_card='32010419990809098X'
if id_card.startswith('3201'):
print('南京的身份证')
endswith() 判断字符串是否以某个或某些字符结尾
#判断身份证最后一位是否是X
if id_card.endswith('X'):
print('最后一位是X')
split() 切割字符串,它有一个参数,以参数作为分割符,将字符串切割为多个值,split()返回值是列表
str9='abcdecfgc'
print(str9.split('c'))
写一个号段筛选程序,需求如下:
用户从控制台输入一个手机号,判断出运营商(移动(假设号段是130-150)、
联通(假设是151-170)、电信(假设是171-199)),如果用户输入的位数不对,提示用户位数有误;
如果用户输入非数字,提示有非法字符
input1=input('请输入一个手机号')
if not input1.isdigit(): #判断用户输入的是否不是数字,如果不是数字,则提示用户输入的不正确
print('您输入的不是数字')
else:
if len(input1)!=11: #判断手机号的位数是否是11位
print('位数不正确')
else:
num1=int(input1[0:3]) #取得手机号的前三位,并转为int型
if 130<=num1<=150:
print('移动手机号')
elif 151<=num1<=170:
print('联通手机号')
elif 171<=num1<=190:
print('电信手机号')
else:
print('您输入的手机号不属于任何运营商')
04-格式化字符串+循环语句与注释
格式化字符串
格式化字符,类似于字符串的拼接,比普通的拼接方式更加简便
a=6
b=9
print(str(a)+'+'+str(b)+'='+str(a+b)) #普通的拼接方式打印6+9=15
print('%d+%d=%d'%(a,b,a+b)) #格式化字符串的方式
格式化字符串方案一
%s字符串 %d整数 %f浮点数
info1='我是%s,你是%s,他是%s,今年是%d年.'%('天乐','青云','德华',2021)
print(info1)
前面的占位符比后面的参数多,则报错
info1='我是%s,你是%s,他是%s,今年是%d年.'%('天乐','青云','德华')
print(info1)
前面的占位符比后面的参数少,也报错
info1='我是%s,你是%s,他是%s.'%('天乐','青云','德华',2021)
print(info1)
前面是%d,后面是str型,报错
info1='你是%d'%('天乐')
print(info1)
前面是%s,后面是数字,不报错
info1='你是%s'%(100)
print(info1)
补齐 %ns n是任意整数,表示补齐到n位,不足n位用空格补齐,默认右对齐
info1='我是%5s,你是%5s,他是%5s,今年是%5d年.'%('天乐','青云','德华',2021)
print(info1)
如果字符串本身就超过了n位,显示全部字符
info1='我是%5s,你是%5s,他是%5s,今年是%5d年.'%('真正的高手名字不会很长','青云','德华',2021)
print(info1)
方案一中,对于数字,可以在左侧补0
info1='我是%5s,你是%5s,他是%5s,今年是%010d年.'%('天乐','青云','德华',2021)
print(info1)
左对齐 %-ns
info1='我是%-5s,你是%-5s,他是%-5s,今年是%-10d年.'%('天乐','青云','德华',2021)
print(info1)
%f浮点型,默认保留6位小数
number1='您输入的数字是%f'%(3.6)
print(number1)
保留两位小数
number1='您输入的数字是%.2f'%(3.6)
print(number1)
补齐到10位,保留两位小数
number1='您输入的数字是%10.2f'%(3.6)
print(number1)
格式化字符串方案二
str1='My name is {},Your name is {},age is {}'.format('Clark','Ralf',21)
print(str1)
前面的参数比后面的参数多,报错
str1='My name is {},Your name is {},age is {}'.format('Clark','Ralf')
print(str1)
前面的参数比后面的参数少,不报错
str1='My name is {},Your name is {}'.format('Clark','Ralf',21)
print(str1)
补齐 {:n} n是任意整数 不足n位时补齐到n位,字符串默认左对齐,� 2000 �字默认右对齐
str1='My name is {:10},Your name is {:10},age is {:10}'.format('Clark','Ralf',21)
print(str1)
补0
str1='My name is {:10},Your name is {:10},age is {:010}'.format('Clark','Ralf',21)
print(str1)
改变对齐方式 >右对齐 <左对齐 ^居中对齐
str1='My name is {:>10},Your name is {:<10},age is {:<10}'.format('Clark','Ralf',21)
print(str1)
{}里面没有写数字时,是顺序取值法,写了数字时,是下标取值法
str1='My name is {},Your name is {},age is {}'.format('Clark','Ralf',21)
print(str1)
顺序取值法与下标取值法不能混用,否则报错
str1='My name is {1},Your name is {0},age is {}'.format('Clark','Ralf',21)
print(str1)
在python3.6之后的版本中,可以使用更简便的写法
name1='天乐'
name2='青云'
str2=f'My name is {name1},Your name is {name2}'
print(str2)
循环
一组被重复执行的语句称之为循环
while循环,从1打印到10
i=1
while i<=10:
print(i)
i += 1 # i每次自增长1
for循环,1打印到10
for i in range(1,11): #range(起始值,终止值,步长) 包含起始值,不包含终止值,步长的缺省值为1
print(i)
如果有明确的循环次数,建议用for循环,如果循环次数不确定,建议用while循环,两者可以互相替换
打印100以内的奇数
for i in range(1,100,2):
print(i)
for循环的起始值省略时,默认为0
for i in range(10):
print(i)
遍历列表
方式一,用下标的方式进行遍历
list1=['火','炎','焱','燚']
for i in range(len(list1)):
print(list1[i])
方式二,直接遍历
for one in list1:
print(one)
break语句与continue语句
break 停止循环
for i in range(1,11):
if i==5:
break
print('Hello') #break与continue后的语句是不可达语句
else:
print(i)
continue 跳出当次循环
for i in range(1,11):
if i==5:
continue
print('Hello') #break与continue后的语句是不可达语句
else:
print(i)
循环语句中也可以带一个else语句,当循环成功执行完毕时,会执行一次else中的语句
for i in range(1,11):
if i==5:
pass #占位符
else:
print(i)
else: #如果循环中执行了break语句则else中的语句不执行,其他情况下执行
print('循环执行完毕')
写一个倒计时程序
import time # 加载time模块
for i in range(10, 0, -1):
print(f'\r倒计时{i}秒', end='') # \r让光标回到行首 # 低版本的python中,可能不会自动刷新,要加一句
flush = True
print(f'\r倒计时{i}秒', end='', flush=True)
time.sleep(1) # 让程序等待1秒 else: print('\r倒计时结束')
05-文件的读写+字典
文件的读写
读取一个文件 open(参数1,参数2) 参数1,路径 参数2,读写的模式r/w/a,参数2的缺省值是r
r读取 w写入 a追加写入
filepath='D:/note9.txt'
file1=open(filepath)
print(file1.read()) #读取文件内容
print(file1.readline()) #读取一行的内容
print(file1.readlines()) #读取文件内容,返回值是列表,每一行就是一个元素,有换行符
print(file1.read().splitlines()) #读取文件内容,返回值是列表,每样就是一个元素
file1.close() #关闭文件
如果遇到乱码问题,首先检查文件的编码,与pycharm保持一致. pycharm的编码设置 settings→editor→file 2000 encodings,选择正确的编码
文件的写入
filepath2='D:/note99.txt'
file2=open(filepath2,'w')
file2.write('微微风簇浪')
file2.close()
filepath2='D:/note99.txt'
file2=open(filepath2,'a')
file2.write('散作满河星')
file2.close()
r+ 可以同时读写,如果文件不存在,则报错,写入时是覆盖写入
w+ 可以同时读写,如果文件不存在,则新建文件,写入时是清空写入
a+ 可以同时读写,如果文件不存在,则新建文件,写入时是追加写入
filepath2='D:/note99.txt'
file2=open(filepath2,'w+')
file2.write('春风得意马蹄疾,一日看尽长安花')
file2.seek(0) #让光标回到行首,seek(n)表示偏移n位,英文1个字节,汉字占两个字节
print(file2.read())
file2.close()
with open(),用法与open()一样,并且它可以同时处理多个文件,也不需要写close()方法
filepath='D:/210530.txt'
filepath2='D:/210530_2.txt'
with open(filepath) as file1,open(filepath2) as file2:
print(file1.read())
print(file2.read())
将100以内的自然数写入文件
with open('D:/210628_100以内的自然数.txt','w+') as file1:
for i in range(1,101):
if i==100:
file1.write(str(i))
else:
file1.write(str(i)+',') #write方法里必须写str类型的参数
字典
字典是非常常用的一种数据结构,它与json格式的数据非常相似,核心就是以键值对的形式存储数据,关于Python中的字典做如下四点说明:
1.构造字典对象需要用大括号表示 {},每个字典元素都是以键值对的形式存在,并且键值对之间用英文状态下的’‘:’'隔开
2.键在字典中是唯一的,不能有重复,对于字符型的键需要用引号引起来。值可以是单个值,也可以是多个值构成的列表,元组或字典
3.字典不再是序列,无法通过位置索引完成元素值的获取,只能通过键索引实现。
4.字典是可变对象
字典是无序的
dict1={'A':'apple','B':'book'}
dict2={'B':'book','A':'apple'}
print(dict1==dict2)
列表是有序的
list1=[10,20]
list2=[20,10]
print(list1==list2) #列表是有序的
字典的键可以存放不可变对象,不可以存放可变对象 字典的值可以存放任意对象 字典属于可变对象,可以进行增删改
字典的键是唯一的
dict6={'A':'apple','A':'ace'} #保存的是{'A':'ace'}
print(dict6)
字典的新增与修改的语句是一样的,如果字典内已经有同名的键,则修改,如果没有,则新增
dict9={'A':'apple'}
dict9['hyntehwrtgrf34nthbg']='3j5hg45umryjbtrghmryjbg' #字典中没有对应的键,所以新增
dict9['A']='ace' #字典中有对应的键,所以进行修改
print(dict9)
update()方法,可以添加或修改多个键值对
dict9.update({'C':'cake','D':'duck','E':'earth'})
print(dict9)
del 删除字典中的键值对
del dict9['E']
print(dict9)
清空字典中的键值对
dict10 = {'A': 'apple'}
print(id(dict10))
dict10.clear() # 这种方式,内存地址不变
print(id(dict10))
dict10 = {} # 这种方式,内存地址发生了变化,相当于重新定义了一个字典
print(id(dict10))
遍历字典中的键值对
dict11={'老虎':'WOW!!','羊':'咩~~','狗':'汪汪汪'}
for k,v in dict11.items():
print(k,v)
遍历键
for k in dict11.keys():
print(k)
遍历值
for v in dict11.values():
print(v)
判断某个对象是否在字典中,根据键判断,而不是值
dict100={'ABC':'ABCDE'}
print('ABCDE' in dict100)
合并两个字典
方法1:使用update方法
这是合并字典的一种简单方法。使用update方法可以轻松地将一个字典的键值对添加到另一个字典中。如果两个字典中有相同的键,后者的值将覆盖前者的值。
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
dict1.update(dict2)
print(dict1) # 输出: {'a': 1, 'b': 3, 'c': 4}
方法2:使用操作符
使用操作符可以实现字典的扩展,这同样会覆盖同名键的值。
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
dict1 = {**dict1, **dict2}
print(dict1) # 输出: {'a': 1, 'b': 3, 'c': 4}
方法3:手动合并
如果不想使用内置方法,也可以手动合并字典。这种方法提供了最大的灵活性,例如可以决定是否覆盖同名键。
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
# 创建一个新的字典,合并dict1和dict2
merged_dict = {**dict1, **dict2}
# 或者,如果不想覆盖同名键,可以这样做:
merged_dict = dict1.copy() # 先复制dict1
for key, value in dict2.items():
if key not in merged_dict:
merged_dict[key] = value
print(merged_dict) # 输出: {'a': 1, 'b': 3, 'c': 4}
json模块
#json格式,非常像字典的字符串
str1='''{
"aac003" : "tom",
"tel" : "13959687639",
"crm003" : "1",
"crm004" : "1"
}'''
import json
str1_new=json.loads(str1) #将json格式转为字典
print(type(str1_new))
print(str1_new['tel'])
str2=json.dumps(str1_new) #将字典转为json
print(type(str2))
07-模块与包+yaml文件操作
模块与包
一个.py文件就是一个模块
#存放文件的目录,如果里面有__init__.py文件,称之为包
#存放文件的目录,如果里面没有__init__.py文件,称之为文件夹
#__init__.py文件,当导入某个包时,这个文件里的内容会被执行一次
#无论是包还是文件夹,都可以导入,简称为导入包
import 包/文件夹
导入模块的几种方式
import 模块名
适用于和当前模块在同一个目录内,或者是python标准库:id(),time() / 或第三方库中的文件:selenium,pytest等 调用时,使用模块名.函数名()
def sumdata(a, b): # a,b形式参数,简称形参
return a + b
def sumdata2(a, b, c): # a,b,c形式参数,简称形参
return a + b + c
然后在007importAndYaml输入
import moduleTest
print(moduleTest.sumdata(3, 6))
from 包 import 模块
调用时,使用模块名.函数名(),这样相当于少写funAndObject.
from moduleTest import sumdata
print(sumdata(3, 6))
from 包.模块 import 函数
适用于不和当前模块在同一个目录内,新建一个包docTest,然后在包下重写一个moduleTest2.py
调用时,使用函数名()
from docTest.moduleTest2 import sumdata
print(sumdata(3, 6))
不同的模块中,有同名的函数,可以使用别名进行调用
from moduleTest import sumdata as f1
from moduleTest import sumdata2 as f2
print(f1(3,6))
print(f2(3,6,1))
只在模块内执行的代码
if __name__ == '__main__': #以下代码只在本模块内执行
print('Hello')
读取yaml文件
当前目录下新建一个config.yml的文件,输入
- 10
- 20
- 30
- 40
- 50
import yaml
with open("./config.yml") as file1:
content = yaml.load(file1, Loader=yaml.FullLoader)
print(content) # yaml的书写规范,列表必须要有空格,可以是一个或多个
读取文件中的多段内容
name: dehua
age: 20
--- #多段内容,用---分隔
- 10
- 20
- 30
- 40
- 50
with open("./config.yml",encoding='utf-8') as file2:
content2=yaml.load_all(file2,Loader=yaml.FullLoader)
for one in content2:
print(one)
yaml文件常见格式
列表
- 10
- 20
- 30
- 40
- 50
字典
name: dehua
age: 20
列表中的字典
-
name: tom
age: 21
-
A: apple
字典中的列表
name:
- 10
- 20
- 30
age: 20
字典中的字典
name:
name1: qingyun
多段内容,用—分隔
name: dehua
age: 20
---
-
name: tom
age: 21
-
A: apple
---
name:
- 10
- 20
- 30
age: 20
---
name:
name1: qingyun
变量
&变量名 定义变量
*变量名 使用变量
HOST: &HOST 121.41.14.39
url: *HOST
08-pycharm使用技巧+排序
pycharm使用技巧
#新建文件时,自动填充代码
#settings→editor→file and code templates,选择python script
#${NAME} 文件名
#${DATE} 日期
#自动补齐
# if name == ‘main’: #先输入main,然后按tab键
#自动补齐自定义的段落
#settings→editor→live templates,在右侧点击+号,添加自定义的内容
#完成之后,下方勾选python,表示使用python代码时生效
#修改注释的颜色
#settings→editor→color scheme→python
#选择line comments,可以修改注释的颜色
#取消语法检查
#settings→editor→inspections,选择python,取消勾选pep8的两个选项
#设置pycharm的分屏
#settings→keymap,查询split关键字,找到分屏的图标,设置快捷键
#常见的快捷键
# if name == ‘main’: #先输入main,然后ctrl+J,然后回车
#快速换行 shift+回车
#快速注释 ctrl+/ 按一次进行注释,再按一次取消注释
#快速缩进 tab 按一次缩进一层 取消缩进 shift+tab 按一次取消缩进一层
#切换编码,当遇到乱码问题时,可以通过切换编码解决乱码的问题
#settings→editor→file encodings
#在pycharm中安装第三方库
#settings→project→python interpreter
排序
永久排序 sort() 这个方法没有返回值
list1=[96,28,-1,36,22,75,9,18]
list1.sort()
sort()倒序排序
list1.sort(reverse=True)
临时排序 sorted() 返回值为排序后的列表,是一个新的对象
list3 = sorted(list1)
print(list3)
sorted()倒序排序
list4 = sorted(list1, reverse=True)
print(list4)
翻转列表,不排序
print(list1[::-1])
冒泡算法
5,4,3,2,1 原始数据 n个数,第一轮比较n-1次
4,5,3,2,1 第一次比较,将5和4的位置互换
4,3,5,2,1 第二次比较,将5和3的位置互换
4,3,2,5,1 第三次比较,将5和2的位置互换
4,3,2,1,5 第四次比较,将5和1的位置互换,第一论比较结束,最大的数沉底
第二轮比较,4,3,2,1,5 第二轮比较n-2次
3,4,2,1,5 第一次比较,将4和3的位置互换
3,2,4,1,5 第二次比较,将4和2的位置 1000 互换
3,2,1,4,5 第三笔比较,将4和1的位置互换
第三轮比较 3,2,1,4,5 第三轮比较n-3次
2,3,1,4,5 第一次比较,将3和2的位置互换
2,1,3,4,5 第二次比较,将3和1的位置互换
第四轮比较 2,1,3,4,5 第四轮比较n-4次
1,2,3,4,5 第一次比较,将2和1的位置互换 n个数一共比较了n-1轮
list1=[96,28,-1,36,22,75,9,18]
for i in range(len(list1)-1): #控制比较多少轮
for j in range(len(list1)-1-i): #控制每轮比较多少次
if list1[j]>list1[j+1]: #如果前面的数比后面的数大,则两数互换
print(f'第{j}位和第{j+1}位的顺序不对')
print(f'变化之前-------------------------->{list1}')
list1[j],list1[j+1]=list1[j+1],list1[j]
print(f'变化之后-------------------------->{list1}')
print(f'第{i+1}轮循环结束')
print(list1)
09-面向对象基础+反射与单例模式
面向对象基础
新建一个长方形的类
class Rectangle:
list1=[10,20,30,40,50] #类属性,具有唯一性
def __init__(self,length,width): #初始化方法
self.length=length #将用户传的length转为实例自身的length
self.width=width #将用户传的width转为实例自身的width
self.list2 = [10, 20, 30, 40, 50,60] # 实例属性,不唯一
def permiter(self): #周长方法
return (self.length+self.width)*2
def area(self): #面积方法
return self.length*self.width
rec=Rectangle(5,4) #实例化
print(rec.permiter())
print(rec.area())
print(rec.__dict__) #查看实例的属性
print(rec.list2)
rec1=Rectangle(10,8)
rec2=Rectangle(8,6)
print(id(rec1.list1)==id(rec2.list1)) #所有的实例,共用一个类属性
print(id(rec1.list2)==id(rec2.list2)) #每个实例,使用各自的实例属性
封装
封装是指隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。在Python中,通常通过将属性设置为私有(使用双下划线开头)来实现封装。
class Person:
def __init__(self, name, age):
self.__name = name # 私有属性
self.__age = age # 私有属性
# 对外提供访问私有属性的接口
def get_name(self):
return self.__name
def get_age(self):
return self.__age
# 对外提供设置私有属性的接口
def set_name(self, name):
self.__name = name
def set_age(self, age):
if age > 0:
self.__age = age
在这个例子中,Person 类的 __name 和 __age 属性被设置为私有,外部代码不能直接访问这些属性。要获取或设置这些属性,必须使用 get_name、set_name、get_age 和 set_age 这些公共方法。
继承
继承是一种创建新类的方式,在现有类(父类)的基础上增加新的特性。新类称为子类,它继承了父类的属性和方法
class Student(Person): # Student类继承自Person类
def __init__(self, name, age, student_id):
super().__init__(name, age) # 调用父类的构造函数
self.student_id = student_id
def study(self):
print(f"{self.get_name()} is studying.")
多态
多态是指同一个方法在不同类型的对象上有不同的行为。在Python中,多态是通过继承和方法重写来实现的。
class Animal:
def speak(self):
return "The animal makes a sound."
class Dog(Animal):
def speak(self):
return "The dog barks."
class Cat(Animal):
def speak(self):
return "The cat meows."
# 多态性体现:
def make_sound(animal):
return animal.speak()
dog = Dog()
cat = Cat()
print(make_sound(dog)) # 输出: The dog barks.
print(make_sound(cat)) # 输出: The cat meows.
# 虽然make_sound函数接收的是Animal类型的参数,但由于Dog和Cat都重写了speak方法,
# 因此当传入它们各自的实例时,调用的是各自类中定义的speak方法,这就是多态的体现。
反射
hasattr:在对象里找有没有某个属性或方法,返回值是布尔型
getattr:在对象里找有没有某个属性或方法,返回值是属性或方法本身,可以多写一个参数指定返回值
setattr:在对象里新增或修改属性值
print(hasattr(str,'replace')) #在对象里找有没有某个属性或方法,返回值是布尔型
print(hasattr(Rectangle,'list2')) #类没有list2
print(hasattr(rec,'list2')) #实例有list2
print(getattr(str,'replace')) #在对象里找有没有某个属性或方法,返回值是属性或方法本身
print(getattr(str,'replace123','没有找到对应的属性或方法')) #找不到属性或方法返回指定的值
# setattr 在对象里新增或修改属性值
class Class1:
a=1
def __init__(self):
pass
setattr(Class1,'a',100) #将属性a设置为100
setattr(Class1,'b',200) #新增属性b,并设置为200
print(Class1.a)
print(Class1.b)
反射举例
class Restaurant:
def yuxiangrousi(self):
return '鱼香肉丝'
def gongbaojiding(self):
return '宫爆鸡丁'
def qingjiaotudousi(self):
return '青椒土豆丝'
def shousibaocai(self):
return '手撕包菜'
def kaishuibaicai(self):
return '开水白菜'
while True:
menu=input('请点菜: ')
if hasattr(Restaurant,menu): #hasattr(对象,属性或方法名),判断对象中是否有某个属性或某个方法,返回值是布尔型
print('好的,请厨师开始做菜')
break
else:
print('没有这道菜')
单例模式
一般情况下,类可以生成任意个实例,单例模式只生成一个
class Single:
def __init__(self): # 初始化方法
pass
def __new__(cls, *args, **kwargs): # 构造方法,用于生成实例
if not hasattr(cls, 'obj'): # 判断类当中有没有实例方法,如果没有则新建
cls.obj = object.__new__(cls) # 生成实例对象
return cls.obj # 返回实例
s1=Single()
s2=Single()
print(s1==s2) #因为s1走了object.__new__(cls),新建了一个实例对象,而s2走了return cls.obj 没有新建仍然拿的s1新建的,所以他们两个相等
其实单例模式相当于间接使用了反射
10-面向对象进阶+面向对象高级
面向对象进阶
class Rectangle:
def __init__(self,length,width): #初始化方法
self.length=length #将用户传的length转为实例自身的length
self.width=width #将用户传的width转为实例自身的width
def perimeter(self): #实例方法
return (self.length+self.width)*2
def area(self): #实例方法
return self.length*self.width
@classmethod #装饰器,声明下面的方法是类方法
def features(cls):
print('两边的长相等,两边的宽也相等,长和宽的角度为90度')
@staticmethod #装饰器,声明下面的方法是静态方法
def sumdata(a, b): #静态方法
return a + b
调用实例方法,类方法,静态方法
rec=Rectangle(5,4) #实例化
print(rec.perimeter()) #实例方法可以由实例调用,不可以由类调用
print(rec.area())
Rectangle.features() #类方法可以由类调用,也可以由实例调用
print(rec.sumdata(3,6))
print(Rectangle.sumdata(3,6)) #静态方法既可以由类调用,也可以由实例调用
判断一个对象是方法还是函数,可以用type,返回具体信息,python2都叫方法,python3才区别开,比较直观能看出来区别的是方法都会有一个self参数,函数一般不加
print(type(rec.perimeter)) #返回值是method
print(type(Rectangle.features)) #返回值是method
print(type(Rectangle.sumdata)) #返回值是function
inspect模块
某个对象是否是方法inspect.ismethod(),返回布尔值
某个对象是否是函数inspect.isfunction(),返回布尔值
print(inspect.ismethod(rec.perimeter)) # True
print(inspect.ismethod(rec.features)) # True
print(inspect.ismethod(rec.sumdata)) # False
print(inspect.isfunction(rec.perimeter)) # False
print(inspect.isfunction(rec.features)) # False
print(inspect.isfunction(rec.sumdata)) # True
继承
完全继承,不重写
class Square(Rectangle):
pass
squ=Square(6,6)
print(squ.perimeter())
print(squ.area())
部分继承,重写父类的一些方法
class Square(Rectangle):
def __init__(self,side):
self.length=side
self.width=side
squ=Square(6)
print(squ.perimeter())
print(squ.area())
全部重写,相当于没有继承
class Square(Rectangle):
def __init__(self,side):
self.side=side
def perimeter(self):
return self.side*4
def area(self):
return self.side**2
squ=Square(6)
print(squ.perimeter())
print(squ.area())
继承父类方法的同时,对父类的方法进行扩展
class Square(Rectangle):
def __init__(self,side):
self.length=side
self.width=side
@classmethod
def features(cls):
super().features() #声明继承父类的方法
print('两边的长相等,两边的宽也相等,长和宽的角度为90度,并且是对称的图形')
Square.features()
@property 声明下面的方法是一个属性而不是方法
class Test1:
a=[1,2,3] #类的静态属性,具有唯一性
def __init__(self):
self.b=[4,5,6] #实例的静态属性,不具有唯一性
@property #声明下面的方法作为一个属性而不是方法
def fun1(self):
return 'Hello'
tt1=Test1()
print(tt1.fun1) #加了@property装饰器之后,作为属性进行调用
面向对象高级
#私有属性和私有方法
#私有属性和私有方法不能被子类继承,也不能被直接调用.
#在属性的前面加上__,就变成了私有属性.在方法的前面加上__,就变成了私有方法.
#__只在前面加,如果前后都有__,不是私有方法或私有属性
class Class_test1:
__str1='ABCDE' #私有属性
str2='QQQ'
def __init__(self):
pass
def __method1(self):
print('这是一个私有方法')
def method2(self):
print(self.__str1) #在对外开放的方法里调用私有属性
self.__method1() #在对外开放的方法里调用私有方法
cls1=Class_test1()
print(cls1.__str1) #私有属性不能被直接调用
cls1.__method1() #私有方法不能被直接调用
print(cls1.str2) #非私有属性可以直接调用
cls1.method2()
所有的类都是object的子类,一个类无论是否声明继承object,实际都继承
class Class10:
'''
天子呼来不上船
自称臣是酒中仙
'''
Class10继承了object,所以可以直接使用object里提供的方法
print(Class10.__dict__) #显示类的属性
print(Class10.__doc__) #显示类的注释
print(Class10.__base__) #显示父类的名称
print(Class10.__bases__) #显示所有父类的名称
print(Class10.__name__) #显示类的名称
多继承
class Money1:
def money(self):
print('一个亿')
class Money2:
def money(self):
print('两个亿')
class Man(Money1,Money2): #继承多个父类时,用逗号隔开,多个父类中有同名方法时,按照继承顺序进行继承
pass
man=Man()
man.money()
多态
例1:
class Animal:
pass
class Dog(Animal):
def say(self):
print('汪汪汪')
class Cat(Animal):
def say(self):
print('喵喵喵')
def animal_say(obj):
obj.say()
dog=Dog()
cat=Cat()
animal_say(dog)
例2
class Fanguan:
pass
class Yuxiangrousi(Fanguan):
def caidan(self):
print('鱼香肉丝')
class Gongbaojiding(Fanguan):
def caidan(self):
print('宫保鸡丁')
class Qingjiaotudousi(Fanguan):
def caidan(self):
print('青椒土豆丝')
def fuwuyuan(obj):
obj.caidan()
guke1=Yuxiangrousi()
guke2=Gongbaojiding()
guke3=Qingjiaotudousi()
fuwuyuan(guke2)
写一个猜数字游戏,需求如下:随机生成一个100以内的整数,让用户猜,如果猜对了,提示回答正确,游戏结束 如果猜错了,提示过大或过小,最多允许猜7次
from random import randint
answer=randint(1,100) #在1-100之间生成一个整数,包含边界值
for i in range(7):
input1=input('请输入一个数字: ')
if not input1.isdigit():
print('您输入的不是数字,游戏结束')
break
else:
input1=int(input1) #将用户输入的字符串型数字转为真正的数字
if input1==answer:
print('回答正确,游戏结束')
break
elif input1>answer:
print('数字过大')
else:
print('数字过小')
写一个三角形的类
class Sanjiaoxing:
def __init__(self,a,b,c):
self.a=a
self.b=b
self.c=c
def zhouchang(self):
if self.a+self.b<=self.c or self.a+self.c<=self.b or self.b+self.c<=self.a:
return '无法构成三角形,忽略周长'
else:
return self.a+self.b+self.c
def mianji(self):
if self.a + self.b <= self.c or self.a + self.c <= self.b or self.b + self.c <= self.a:
return '无法构成三角形,忽略面积'
else:
p=(self.a+self.b+self.c)/2
return (p*(p-self.a)*(p-self.b)*(p-self.c))**0.5
sjx=Sanjiaoxing(3,4,5)
print(sjx.zhouchang())
print(sjx.mianji())
思考题
解题思路
1.建立一个老虎的类,老虎的体重是200,有叫的方法,有吃的方法
2.建立一个羊的类,羊的体重是100,有叫的方法,有吃的方法
3.建立一个房间的类
4.将老虎或羊的实例放入房间的实例
5.写游戏相关的代码
①调用叫的方法,如果是老虎就调用老虎的叫的方法,如果是羊就调用羊的叫的方法
②调用吃的方法,如果是老虎就调用老虎的吃的方法,如果是羊就调用羊的吃的方法
③游戏时间的控制
④游戏结束时显示每个房间的动物以及体重
class Tiger:
def __init__(self):
self.name='老虎'
self.weight=200
def eat(self,food):
if food=='meat':
print('喂食正确')
self.weight+=10
elif food=='grass':
print('喂食错误')
self.weight-=10
def roar(self):
print('Wow!!')
self.weight-=5
class Sheep:
def __init__(self):
self.name='羊'
self.weight=100
def eat(self,food):
if food=='grass':
print('喂食正确')
self.weight+=10
elif food=='meat':
print('喂食错误')
self.weight-=10
def roar(self):
print('mie~~')
self.weight-=5
class Room:
def __init__(self,animal):
self.animal=animal
roomlist=[] #定义一个列表,用来存放房间的实例
from random import randint
for i in range(10):
if randint(1,2)==1: #在1和2之间随机取一个整数
animal=Tiger() #实例化一个老虎
else:
animal=Sheep() #实例化一个羊
room=Room(animal) #实例化一个房间
roomlist.append(room) #把房间的实例放入列表
import time
start_time=time.time() #记录游戏开始的时间
while time.time()-start_time<180: #如果游戏时间未超过3分钟,则循环运行游戏
room_number=randint(0,9) #随机选择一个房间
random_room=roomlist[room_number] #选取该房间
load1=input(f'当前访问的是{room_number+1}房间,请问是敲门还是喂食?1表示敲门,2表示喂食')
if load1=='1':
random_room.animal.roar() #调用房间中的动物的叫的方法
elif load1=='2':
food=input('请问喂哪种食物 meat/grass')
if food in ('meat','grass'):
random_room.animal.eat(food) #调用房间中的动物的吃的方法
else:
print('您输入的食物不正确')
else:
print('您的操作不正确,请输入1或2')
else:
print('游戏时间到')
for i in range(len(roomlist)):
print(f'{i+1}号房间的动物是{roomlist[i].animal.name},体重是{roomlist[i].animal.weight}')
11-异常与日志
异常处理
try except语句中,至少要有一个except,也可以有多个.也可以加上一个else语句,一个finally语句.
try:
int1=int(input('请输入一个数字: '))
print(1/int1)
except ZeroDivisionError: #0作为分母的异常
print('0不能作为分母')
except ValueError: #输入的是非数字的异常
print('您输入的不是数字')
except: #如果不指定异常类型,则捕获任何出现的异常
print('程序出现错误')
else: #当程序未捕获到任何异常,会执行else中的语句
print('没有出现异常')
# finally: #无论程序是否出现异常,都会执行
finally:
print('程序执行完毕')
常见的异常
NameError 未定义的变量
IndexError 下标越界
FileNotFoundError 找不到文件异常
所有的异常,都是Exception的子类,或者子类的子类,Exception也有一个父类 BaseException
print(NameError.__base__)
print(IndexError.__base__)
print(LookupError.__base__)
print(FileNotFoundError.__base__)
print(OSError.__base__)
print(Exception.__base__)
手动抛出异常
try:
raise IOError #假装这里有异常
except IOError:
print('程序出现了IO错误')
日志模块
日志等级,默认打印WARNING以上级别,可以设置level改为别的级别
日志等级可以分为5个,从低到高分别是:
- DEBUG
- INFO
- WARNING
- ERROR
- CRITICAL
日志等级说明:
DEBUG:程序调试bug时使用
INFO:程序正常运行时使用
WARNING:程序未按预期运行时使用,但并不是错误,如:用户登录密码错误
ERROR:程序出错误时使用,如:IO操作失败
CRITICAL:特别严重的问题,导致程序不能再继续运行时使用,如:磁盘空间为空,一般很少使 用
默认的是WARNING等级,当在WARNING或WARNING之上等级的才记录日志信息。
日志等级从低到高的顺序是: DEBUG < INFO < WARNING < ERROR < CRITICAL
设置basicConfig里面设置成什么,就在控制台打印该级别以上的日志
import os
from loguru import logger
logger.debug('松勤')
logger.info('松勤')
logger.warning('松勤')
logger.error('松勤')
logger.critical('松勤')
if not os.path.exists('./log'):
os.mkdir('./log')
logfile='./log/log1.log'
logger.add(logfile,rotation='200KB',compression='zip') #rotation拆分日志文件,每个日志200KB,compression压缩日志
logger.remove(handler_id=None) #这句代码表示信息不在控制台显示
for i in range(10000):
logger.info('松勤')
def fun1(a,b):
return a/b
try:
fun1(2,0)
except:
logger.exception('报错')
12-pytest框架入门+allure报告
pytest
pytest是一种自动化测试框架,pytest向下兼容unittest
命名规范:
文件名以test开头,或者test结尾
类以Test开头,且类当中不能有init方法
方法或函数以test_开头
断言必须使用assert
pytest框架使用
import os
import pytest
class Test1:
def test_100(self):
print('******************test100*********************')
assert 1==2 #判断预期结果与实际结果是否一致
def test_200(self):
print('***********************test200**********************')
assert 6==6
if __name__ == '__main__':
pytest.main(['test_pytest1.py','-sv']) #-s表示允许执行print语句 -v表示打印详细信息
动态化参数
import pytest
#不用写很多个测试方法,动态化参数
list1 = [1,2],[2,3],[3,5],[6,8],[9,9]
class Test1:
@pytest.mark.parametrize('expected_result,actual_result',list1)
def test_ce1(self ,expected_result,actual_result):
assert expected_result == actual_result
if __name__ == '__main__' :
pytest.main([__file__,'-sv' ])#-v详细的信息
装饰器
import pytest
@pytest.fixture(scope="module") # 装饰器,声明下面的函数是setup函数,缺省值为function级
# scope可以加入参数scope='class',将级别改为class
# scope可以加入参数scope='module',将级别改为module
# scope='session' 使用这个级别时,将fixture的内容写到conftest.py文件中,目录下的所有文件都使用这个配置
def fun1():
print('测试开始')
yield # 这个关键字之后的代码相当于teardown
print('测试结束')
class Test1:
def test_c01(self,fun1):
assert 1 == 2
def test_c02(self,fun1):
assert 1 ==1
class Test2:
def test_c03(self,fun1):
assert 1 == 2
def test_c04(self,fun1):
assert 1 ==1
if __name__ == '__main__':
pytest.main([__file__, '-sv']) # -s表示允许执行print语句 -v表示打印详细信息
conftest.py
conftest.py:pytest会默认读取conftest.py里面的所有fixture,所有同目录测试文件运行前都会执行conftest.py文件
装饰器如果设置为session的话,在同个目录下新建一个conftest.py输入
import pytest
@pytest.fixture(scope="session",autouse=True)
def fun100():
print("sessionConfTest测试开始")
yield
print("sessionConfTest测试结束")
if __name__ == '__main__':
pytest.main([__file__,"-sv"])
然后运行动态化参数类:
import pytest
#不用写很多个测试方法,动态化参数
list1 = [1,2],[2,3],[3,5],[6,8],[9,9]
class Test1:
@pytest.mark.parametrize('expected_result,actual_result',list1)
def test_ce1(self ,expected_result,actual_result):
assert expected_result == actual_result
if __name__ == '__main__' :
pytest.main([__file__,'-sv' ])#-v详细的信息
会执行conftest.py文件
autouse
autouse=True设置了后,类里面不用再传fun了,自动传
@pytest.fixture(scope="module",autouse=True) # 装饰器,声明下面的函数是setup函数,缺省值为function级
# scope可以加入参数scope='class',将级别改为class
# scope可以加入参数scope='module',将级别改为module
# scope='session' 使用这个级别时,将fixture的内容写到conftest.py文件中,目录下的所有文件都使用这个配置
def fun1():
print('测试开始')
yield # 这个关键字之后的代码相当于teardown
print('测试结束')
class Test1:
def test_c01(self): #没有传fun1
assert 1 == 2
def test_c02(self):
assert 1 ==1
class Test2:
def test_c03(self):
assert 1 == 2
def test_c04(self):
assert 1 ==1
if __name__ == '__main__':
pytest.main([__file__, '-sv']) # -s表示允许执行print语句 -v表示打印详细信息
allure报告
1、下载allure.zip
2、解压allure.zip到一个文件目录 f0a 中
3、将allure报告安装目录\bin所在的路径添加环境变量path中
4、pip install allure-pytest
import pytest
import allure
@allure.epic('项目名称')
@allure.feature('业务模块名称')
class Test100:
@allure.story('接口名称')
@allure.title('用例标题1')
def test_c100(self):
assert 1 == 2
@allure.story('接口名称2')
@allure.title('用例标题2')
def test_c101(self):
assert 1 == 1
if __name__ == '__main__':
pytest.main([__file__, '-sv','--alluredir','./report/report','--clean-alluredir'])
os.system('allure serve ./report/report')
层级和ids
import pytest
import allure
list2=[[1,2],[1,1],[2,2],[1,2]]
@allure.epic('项目名称')
@allure.feature('业务模块名称')
class Test1:
@pytest.mark.parametrize('expected_result,actual_result',list2,ids=("id1","id2","id3","id4")) #ids相当于给list2命名
def test_ce1(self ,expected_result,actual_result):
assert expected_result == actual_result
# class Test100:
# @allure.story('接口名称')
# @allure.title('用例标题1') #相当于给方法命名,和ids用法一致,但allure有层级
# def test_c100(self):
# assert 1 == 2
#
# @allure.story('接口名称2')
# @allure.title('用例标题2')
# def test_c101(self):
# assert 1 == 1
if __name__ == '__main__':
path="../report/report"
#-s表示可以输出打印语句,-v表示打印详细信息,alluredir表示创建输出目录,--clean-alluredir表示清干净上一次的目录
pytest.main([__file__, '-sv','--alluredir',f'{path}','--clean-alluredir'])
#os.system表示打开cmd
os.system(f'allure serve {path}')