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等 调用时,使用模块名.函数名()

新建一个moduleTest.py,输入

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个,从低到高分别是:

  1. DEBUG
  2. INFO
  3. WARNING
  4. ERROR
  5. 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}')