Python学习笔记

本文介绍了Python的基础语法,包括变量、数据类型、字符串操作、列表和元组的使用,以及字典和集合的概念。进一步讲解了面向对象编程,包括类的创建、对象的实例化、继承、多态和封装。还探讨了Python中的异常处理、文件操作和JSON操作。此外,简述了unittest测试框架的使用,包括测试用例、参数化测试、测试报告和断言。

python学习

可以用keyword中的kwlist看python中的关键字

eg:print(keyword.kwlist)


命名格式

1.见识知义

2.使用驼峰体

  • 大驼峰:每个单词首字母大写,例如:MyName
  • 小驼峰:第二个单词开始首字母大写,例如:myName

3.使用下划线:每个单词之间使用下划线连接,例如:my_name

代码格式要进行缩进来表示代码块:


if True:
    print("true")
 else:
    print("true")
        

字符串

字符串类型:(字符串是没办法被改变的)

在字符串中单引号 ' 和双引号 " 使用完全相同

r 可以使反斜杠不发生转义,如 r"this is a line with \n"

字符串可以直接用 + 号连接

python中字符串有两种索引方式,从左到右以0开始,从右到左以-1开始。

  • 如 str_a = "abc" 则str_a[0]=a ,str_a[-1]=c

Python 没有单独的字符类型,一个字符就是长度为 1 的字符串。

字符串的截取的语法格式如下:变量[头下标:尾下标:步长]

  • 如str='123456789'
  • print(str) # 输出字符串 print(str[0:-1]) # 输出第一个到倒数第二个的所有字符 print(str[0]) # 输出字符串第一个字符 print(str[2:5]) # 输出从第三个开始到第五个的字符 print(str[2:]) # 输出从第三个开始后的所有字符 print(str[1:5:2]) # 输出从第二个开始到第五个且每隔一个的字符(步长为2) print(str * 2) # 输出字符串两次 print(str + '你好') # 连接字符串

补充

str ="abcdefg"

print(str1[::-1]) #将字符串反转(逆置输出)

- 字符串的查找方法 find


用法:
字符串.find(sub_str,start,end)
作用:在字符串中查找是否存在sub_str 这样的字符串
sub_str:要查找的小的字符串
start:开始位置,从哪个下标位置开始查找,一般不写,默认为0
end:结束位置,查找到哪个下标结束,一般不写,默认是len()
返回(代码执行之后会得到什么,如果有返回,就可以使用变量保存)
1.如果在字符串中找到了sub_str ,返回sub_str 第一次出现的下标(sub_str 中第一个字符在大字符串中的下标)
2.如果没找到,返回-1

- 字符串的查找



字符串.replace(old_str,new_str,count) #将字符串中的old_str 替换为new_str
old_str:被替换的内容
new_str:替换为的内容
count:统计数据出现的次数
返回:替换之后的完成的字符串,注意:原来字符串没有发生改变

- 字符串的拆分 split



字符串.split(sep,max_split) #字符串按照sep 进行分割(拆分)
sep,字符串按照什么进行拆分,默认是空白字符(空格,换行\n,tab键\t)
max_split 分割次数,一般不写,全部分割
返回:将一个字符串拆分为多个,存到列表中
注意:如果seq不写,想要指定分割次数,则需要按照如下方式使用字符串.split(max_split=1) #n是次数

- 字符串的链接join



字符串.join(列表) #括号中的内容主要是列表,可以是其他内容
#作用:将字符串插入到列表中每相邻的两个数据之间,组成一个新的字符串
列表中的数据使用,用逗号隔开
注意点:列表中的数据必须都是字符串,否则会报错

- 字符串的比大小



字符比大小,是比较字符对应的 ASCII 码值
A<Z < a<z
ord(字符) #获取字符对应ascii的值
chr(ASCII的值)#获取对应的字符
字符串比大小:
对应下标位置字符的大小,直到比出大小,如果全部比完了,还没有比出大小,就是相等

数字类型有:

  • int,通常被称为是整型或整数,是正或负整数,不带小数点。Python3 整型是没有限制大小的,可以当作 Long 类型使用,所以 Python3 没有 Python2 的 Long 类型。布尔(bool)是整型的子类型。
  • bool(布尔类型)
  • float(浮点数),浮点型由整数部分与小数部分组成,浮点型也可以使用科学计数法表示(2.5e2 = 2.5 x 102 = 250)
  • complex(复数),复数由实数部分和虚数部分构成,可以用a + bj,或者complex(a,b)表示, 复数的实部a和虚部b都是浮点型。

数值的运算



5+4 #加法
9
4.3 - 2 # 减法
2.3
3 * 7  # 乘法
21
2 / 4  # 除法,得到一个浮点数!!!
0.5
2 // 4 # 除法,得到一个整数
0
17 % 3 # 取余
2
2 ** 5 # 乘方
32
>>> 7.0//2  #向下取整
3.0

容器:

列表

List(列表类型)(List列表是可变的可以用append,pop进行添加)

  • 列表是写在方括号 [ ]之间、用逗号分隔开的元素列表。
  • 和字符串一样,列表同样可以被索引和截取,列表被截取后返回一个包含所需元素的新列表。

正在上传…重新上传取消

列表的定义



列表 list 是使用最多的一种容器(数据类型)
列表中可以存取多个数据,每个数据之间使用逗号隔开
列表中可以存放任意类型的数据
1.1定义空列表
变量 = list()
1.2 类型转换 list(容器) 讲其他的容器转换为列表
#转换字符串会将字符串中的每一个字符作为一个数据存入到列表中

列表的查询



在字符串中使用find方法查找下标的,不存在返回-1,
在列表中没有find方法,想要查找数据的下标,使用的是index()方法
列表.index(数据,strat,end) 使用和find方法一样,同时字符串中也有index方法
区别:返回,index()方法,找到返回第一次出现的下标,没有找到代码直接报错

添加数据的方法

尾部添加



列表.append(数据) #在数据添加到列表的尾部

指定下标位置添加



列表.insert(下标,数据) #在指定的下标位置添加数据,如果指定的下标位置本来就数据,原数据返回

列表合并



列表1.extend(列表2) #讲列表2中的所有数据逐个添加到列表1的尾部

修改操作



想要修改列中指定下标位置的数据,使用的语法是:
列表[下标] = 数据
#字符串不能修改

删除数据



在列表中删除中间的数据,那么后面的数据会向前移动

根据下标删除



列表.pop(下标) #删除指定下标位置对应的数据
1.下标不写,默认删除最后一个数据(常用)
2.书写存在的下标,删除对应下标位置的数据
返回:返回的删除的数据

根据数据值删除



列表.remove(数据值) #根据数据值删除
返回:none
注意:如果要删除的数据不存在,会报错

清空数据(一般不用)

列表.clear()

列表的反转(倒置)

字符串中 反转倒置:字符串[::-1]
1.在列表当中 反转和倒置 列表[::-1]  #使用切片的方法,会得到一个新列表,原列表不会发生改变
2.列表.reverse() #直接改变原列表 返回none
如果直接用 参数 = 另一个list3
则其中一个修改的话,另一个也会跟着修改

list1 =my_list[::-1]
print("my_list:",my_list)
print("list1:",list1)

#使用reverse 方法,直接改变原列表
my_list.reverse()
print("my_list",my_list)

列表的复制

将列表中的数据复制一份,给到一个新的列表
#使用场景:有一个列表,需要去修改操作列表中的数据,同时还要备份列表中的数据,修改之后,需要和原数据进行对比,即原数据不能改

1.使用切片
变量=列表[:] #开始到结尾
2.使用copy方法
变量 = 列表.copy()

列表推导式

列表推导式:快速的生成列表

变量名 = [生成数据的规则 for 变量 in xxx] #循环每执行一次,在列表中添加一个数据

列表的排序

列表的排序,一般来说都是对数字进行排序的

列表.sort() #按照升序排序,从小到大的排序

列表.sort(reverse=True) #降序排序,从大到小

列表嵌套

列表可以多层嵌套

不论多少层都要可以使用下标进行访问

person_info = [["张三","18","功能测试"],["李四","20","自动化测试"]]

列表的加法

对于列表来说,+=的本质是extend操作
def func(list1):
    list1 + =[1,2]
    
my_list = ['a','b']
func(my_list)
print(my_list) 

最后输出为['a','b',1,2]

Tuple(元组)

  • 元组(tuple)与列表类似,不同之处在于元组的元素不能修改。元组写在小括号 () 里,元素之间用逗号隔开。
  • 元组中的元素类型也可以不相同:
  • 元组中的数据内容不能改变,列表中的可以改变
  • 元组使用( ),列表 使用[ ]
  • 应用:在函数的传参或者返回值中使用,保证数据不会被改变

定义

1.使用 类实例化的方式
2.直接使用()方式
3.特殊点,定义只有一个数据的元组时,数据后边必须有逗号
如my_tuple =(1,)

常用的方法

由于元组的数据不能修改,所以只能查看的方法

1.在元组中也可以使用,下标和切片获取数据
2.在元组中存在index()方法,查找下标,如果不存在,会报错
3.在元组中存在count()方法,统计数据出现的次数
4.在元组中可以使用in 操作,判断数据是否存在
5.len()统计个数
以上方法的使用,和列表中一样的

正在上传…重新上传取消

Set(集合)

定义

  • 集合(set)是由一个或数个形态各异的大小整体组成的,构成集合的事物或对象称作元素或是成员。
  • 基本功能是进行成员关系测试和删除重复元素。
  • 可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典

正在上传…重新上传取消

Dictionary(字典)

  • 字典(dictionary)是Python中另一个非常有用的内置数据类型。
  • 列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取。
  • 字典是一种映射类型,字典用 { } 标识,它是一个无序的 键(key) : 值(value) 的集合。
  • 键(key)必须使用不可变类型。
  • 在同一个字典中,键(key)必须是唯一的。

正在上传…重新上传取消

1.1字典的作用

  • 实际业务很复杂,需要用到不同类型的数据
  • 不同类型数据在保存时应当加以区分
  • 字典不仅可以保存多个数据,同时还能给不同数据"起名字"

1.2字典的定义

  1. 基本结构:字典名 = {}
  2. 大括号内结构为: 键名 :键值 [俗称键值对]
  3. 多个键值对之间使用逗号隔开

字典

1.字典dict,字典中的数据是由键(key)值(value)对组成的(键表示数据的名字),值就是具体的数据
2.在字典中一组键值对是一个数据,多个键值之间使用 逗号隔开
变量 = {key:value,key:value,...}
3.一个字典中的键是唯一的,不能重复的,值可以是任意数据
4.字典中的键 一般都是 字符串,可以是数字,不能是列表

定义

# 1.使用 类实例化的方法
my_dict =dict()
print(type(my_dict),my_dict)

#非空字典,小明('name') 18('age') 1.71('height')True(is_men)  抽烟 喝酒 烫头('like')
my_dict2={'name':"小明","age":18,"height":1.71,"is_men":True,"like":["抽烟","喝酒","烫头"]}
print(my_dict2)
print(len(my_dict2))

my_dict2['sex'] = '男'
print(my_dict2)

#2.修改年龄为19
my_dict2['age']=19
print(my_dict2)

#3.添加一个爱好,学习--> 本质是向列表中添加一个数据
my_dict2['like'].append('学习')

查询 - 根据键获取对应的值

字典中没有下标的概念,想要获取数据值,要使用key(键)来获取

使用 字典[键]

  • 如果键存在,返回键对应的数据值
  • 如果键不存在,会报错

使用 字典.get(键) 推荐使用

  • 字典.get(键,数据值)
  • 1.数据值一般不写,默认为none
  • 返回:
  • 1.如果键存在,返回键对应的数据值
  • 2.如果键不存在,会报错
my_dic ={'name':'小明','age':19,'like':['抽烟','喝酒','烫头','学习']}
print(my_dic['name'])
print(my_dic.get('name'))
print(my_dic.get('name','保密')) #还是返回小明

print(my_dic.get('sex'))
print(my_dic.get('sex','保密'))

print(my_dic['like'][1])
print(my_dic.get('like')[1])

字典的遍历

对 字典的键 进行遍历

for 变量 in 字典:
	print(变量) #字典就是字典的key ,键
for 变量 in 字典.key(): #字典.key() 可以获取字典中所有的键
	print(变量)

对 字典的值 进行遍历

for 变量 in 字典.value(): #字典.values() 可以获取字典中所有的值
	print(变量)

对 字典的键值对 进行遍历

# 变量1 就是 键,变量2 就是键对应的值
for 变量1,变量2 in 字典
for 变量1,变量2 in 字典.items(): #字典.item() 获取键值对
    print(变量1,变量2)

    

字典的删除

- del 字典[key]
- 字典.clear()
-字典.pop(key)

容器部分 总结

#1.字符串,列表,元组 支持加法运算
str1 ='hello' +'world' # 'hello world'
list=[1,2] +[3,4] #[1,2,3,4]
tuple1 =(1,2) +(3,4) #(1,2,3,4)

#2.字符串 列表 元组 支持 乘一个数
'hello' * 3 #==> 'hello hello hello'
[1,2]*3 #==>[1,2,1,2,1,2]
(1,2)*3 #==>(1,2,1,2,1,2)

#3.len() 在容器中 都可以使用

#4. in 关键字在容器中都可以使用,注意,在字典中判断的是字典的键是否存在


函数

概念

函数,就是把 具有独立功能的代码块 组织为一个小模块,在需要的时候 调用

函数:通俗理解,将多行代码写在一块,起个名字,在需要这多行代码的时候,可以直接使用这个名字来替代

函数的好处:减少代码的冗余(重复的代码不用多写),提高程序的编写效率

函数定义

1.多行代码放在一块,起名字的过程,称为函数定义
2.函数必须先定义后调用
  • 语法

    def 函数名():
    	函数中的代码
    	函数中的代码
    #1.def是关键字,用来定义函数的 define的缩写
    #2.函数名需要遵循标识符的规则
    #3.处于def缩进中的代码,称为函数体
    #4.函数定义的时候,函数体中的代码不会执行,在调用的时候执行
    
  • 函数定义小技巧:

  • 在前期,书写不熟练的时候,
    1.可以先不管函数,先把功能写出来,
    2.给多行代码起名字
    3.选中多行代码,使用tab 键进行缩进  
    

函数调用

1.使用多行代码的时候,成为函数调用

  • 语法

  • 函数名()
    #1.函数调用的时候会执行函数体中的代码
    #2.函数调用的代码,要写在函数体外边
    

函数的嵌套调用

在一个函数定义调用另一个函数

1.函数定义不会执行函数体中的代码
2.函数调用会执行函数中的代码
3.函数体中代码结束会回到函数被调用的地方继续向下执行

函数的返回值

函数的返回值,可以理解为是 整个函数整体执行的结果是什么
什么上班需要书写返回值:函数中得到的数据在后续的代码中还要使用,这个时候就应该将这个数据作为返回值返回,以供后续使用

print()
input()
type()
len()

在函数中想要将一个数据作为返回值 返回,需要使用return 关键字(只能在函数中使用)
作用:
1.将数据值作为返回值返回
2.函数代码执行遇到return,结束函数执行

输入语句

获取用户使用键盘录入的内容

使用的函数 input()

变量 = input("提示的信息")

变量为字符串类型

1.代码从上到下执行,遇到input函数,会暂停执行,等待用户输入

输出语句

输出使用的函数是 print()函数,作用,将程序中的数据或者结果打印到控制台(屏幕)

pirnt('hello world')
name ='小明'
print(name)
print(name,age) #可以使用逗号输出多个内容

格式化输出

在字符串中指定的位置,输出变量中存储的值

1.在需要使用变量的地方,使用特殊符号占位

2.使用变量填充占位的数据

%格式化输出占位符号

  • %d 占位,填充 整形数据 digit
  • %f 占位,填充 浮点型数据 float
  • %s 占位,填充 字符串类型 string
name ="Sum"
age =18
height =171.1

print("我的名字是%s 年龄是%d 身高是%.2f" %(name,age,height))
# 小数默认显示6位,如果想要指定显示小数点后几位,%.nf ,n需要换成具体的整数数字,即保留小数的位置

#补充
stu_num =1
print("我的学号为%d" % stu_num)
# %0nd n需要换成具体的整数数字,表示整数一共占几位
print("我的学号是%06d" %stu_num)

字符串.format()

字符串.fomat() 可以再任意版本中使用
1.在需要使用 变量的地方使用 {}占位
2."{} ,{},...".format(变量,变量,...)
eg:print("我的名字是{},年龄是{},身高是{}m,学号是{},本次考试的及格率为{}%").foemat(name,age,height,stu_id,pasr)

花括号的使用 f-string

f"{变量}" F"{变量}"

name ="Sum"
age =18
height =171.1
print(f"我的名字是{name} 年龄是{age} 身高是{height}")

快捷键(小操作)

添加引号括号:可以直接选中要添加引号或者括号的内容,书写即可
删除一行:ctrl x
复制粘贴一行:ctrl d
新建一行,在代码下面,新建一行: shift 回车
快速注释 选中并且按 ctrl + /

type函数的使用

type(变量) 可以获取变量的数据类型

文档注释

文档注释的本质,还是注释,只不过书写的位置和作用比较特殊
1.书写的位置,在函数名的下方使用,三队双引号进行注释
2.作用:告诉别人这个函数如何使用
3.查看,在调用的时候,将光标放在函数名上,使用快捷键 Ctrl q

函数进阶

返回值 - 函数返回多个数据值

函数中想要返回一个数据值,使用 return 关键字

将多个数据值组成容器进行返回,一般是元组(组包)

def calc(a,b)
	num = a + b
    num1 = a - b
    return num,num1
#写法一
result =calc(10,5)
print(result,result[0],result[1])
#直接拆包
x,y =calc(20,10)
print(x,y)
    
    

函数的参数

形参的不同书写方法

函数的传参方式

位置传参
 - 在函数调用的时候,按照形参的顺序,将实参值传递到形参
关键字传参
 - 在函数调用的时候,指定数据值给到那个参数

缺省参数

缺省参数,默认参数
列表.pop() #不写参数,删除最后一个
列表.sort(reverse = True)

1.定义方式
在函数定义的时候,给形参一个默认的数值,这个形参就变成缺省参数,注意缺省参数的书写放在普通参数的后面
2.特点(好处)
缺省参数,在函数调用的时候,可以传递实参值,也可以不传递实参值
如果传参,使用的就是传递的实参值,如果不传参,使用的就是默认值

def show_info(name,sex='保密')
	print(name,sex)

show_info('小王')
show_info('小王','男')

多值参数[可变参数/不定长参数]

print(1)
print(1,2,3)
print(1,2,3,4)

print函数 sep=' '每个位置参数之间的间隔 end='\n' print所有参数输出之后,会再次输出end
end = ' '连接下一句输出语句
当我们在书写函数的时候,不确定参数的具体个数的时候,可以使用不定长参数
*args是元组 **kwargs是字典
def 函数名(普通参数,*args,缺省参数,**kwargs)
			pass



def func(*args,**kwargs):
    print(type(args),args)
    print(type(kwargs),kwargs)
    print('_'*30)

func()
func(1,2,3) #位置传参,数据都给了args
func(a=1,b=2,c=3)#关键字传参,数据都给了kwargs

匿名函数

匿名函数:就是使用 lamda 关键字定义的函数
一般称为 def 关键字定义的函数为,标准函数

匿名函数只能书写一行代码
匿名函数的返回值不需要 return,一行代码(表达式)的结果就是返回值
语法:
lambda 参数:一行代码
  • 语法

  • lamba 参数:一行代码
    #匿名函数一般不需要我们主动去调用,一般作为函数的参数使用的
    
    func11 =lambda a,b:a*b
    print(func11(1,2))
    
  • 匿名函数作为函数的参数 - 列表中的字典排序

    user_list = [{"name":"zhangsan","age":18},{"name":"lisi","age":19},{"name":"wangwu","age":17}]
    
    列表排序(列表中的数字):
    列表.sort()
    列表.sort(reverse =True)
    列表中的内容都是字典,想要排序
    列表.sort(key=lambda x:x['键'])
    
    
    

类型转换

根据代码的需要,将一种数据类型转换成另一种数据类型(将input输入得到的数字转换为整型)

如 变量 = int(变量) 还有float(), str()

循环语句

for语句

for循环可以遍历容器中的数据(
    遍历:从容器中把数据一个一个拿出来
    容器:可以简单理解为盒子,盒子中可以存放很多的数据(字符串 str ,列表 list ,元组 tuple ,字典 dict))
for 循环 也可以称为for遍历

语法:
for 变量名 in 容器
	重复执行的代码
#1.for 和 in 都是关键字
#2.容器中有多少个数据,循环会执行多少次(0 个数据 ,执行0次)
#3.每次循环,会讲容器中数据取出来一个保存到in 关键字前面的变量中

for i in range(101):   #只能执行到100 跟索引一样遵循左闭右开
    print(i)

for i in range(2,101,2): #从2到100 间隔为2取数
    print(i)
 
#if语句
#补充not in
if i not in range(2):
    print(i)
    
a = "Hello"
b = "Python"
 
print("a + b 输出结果:", a + b)
print("a * 2 输出结果:", a * 2)
print("a[1] 输出结果:", a[1])
print("a[1:4] 输出结果:", a[1:4])
 
if( "H" in a) :
    print("H 在变量 a 中")
else :
    print("H 不在变量 a 中")
 
if( "M" not in a) :
    print("M 不在变量 a 中")
else :
    print("M 在变量 a 中")
      
    
 my_str ="hello"
for i in my_str:
    print("!!!!")

break 和 continue

break 和 continue 是python中的两个关键字,只能在循环中使用

break:终止循环,即代码执行遇到break,循环不再执行,立即结束

continue,跳过本次循环,即代码执行遇到continue,本次循环剩下的代码跳过

while语句

while i<=100:

print(i)

i++

列表去重

列表去重:列表中存在多个数据,需要,去除列表中的重复的数据
方式1.遍历 
list =[1,2,3,4,5,5,6,4]
list2 = []
list2.append(list[0])
for i in list:
    if i in list2:
        continue
    else:list2.append(i)
print(list2)
方式2
在python中用一种数据类型(集合) set
特点:集合中不能有重复的数据(如果有重复的数据会自动去重)
可以使用集合的特点对列表进行去重
1.使用set() 类型转换将列表转换为集合类型
2.再使用list()类型转换成集合 转换为列表

缺点:不能保证数据在原列表中出现的顺序(一般来说,也不需要考虑)

变量进阶

可变类型和不可变类型

数据类型:int float bool str list tuple dict set

可变不可变是指:数据所在的内容是否允许修改,允许修改就是可变类型,不允许修改就是不可变类型

可变类型:列表 list 字典 dict 集合 set
	列表.append()
	字典.pop(键)
不可变类型:int float bool str tuple

Python 交换两个变量的值和拆包

#python特有的
a,b = b,a
print(a,b)

组包和拆包

组包(pack):将多个数据值使用逗号连接,组成元组

拆包(unpack):将容器的数据值使用多个变量分别保存的过程,注意:变量的个数和容器中的个数要保持一致

赋值运算符,都是先执行等号右边的代码,执行的结果,保存到等号左边的变量中
将列表或者元组中的数据作为位置参数进行传递 *列表或者*元组
将字典中的数据作为关键字参数进行传递 **字典

局部变量和全局变量

变量:根据变量的定义位置,可以将变量分为局部变量和全局变量

局部变量

局部变量:在函数内部(函数的缩进中)定义的变量,称为局部变量
特点:
1.局部变量只能在当前函数内部使用,不能在其他函数和函数外部使用
2.在不同函数中,可以定义名字相同的局部变量,两者之间没有影响
3.生命周期
在函数被调用的时候,局部变量被创建,函数调用结束,局部变量的值被销毁(删除),不能使用

所以函数中的局部变量的值,如果想要在函数外部使用,需要使用return关键字,将这个值进行返回

全局变量

定义位置:在函数外部定义的变量,称为是全局变量
特点:
1.可以在任何函数中读取(获取) 全局变量的值
2.如何在函数中存在和全局变量名字相同的局部变量,在函数中使用的是 局部变量的值(就近)
3.函数内部想要修改全局变量的引用,需要添加global关键字,对变量进行声明为全部变量
4.生命周期
代码执行时候被创建,代码执行结束,被销毁(删除)

面向对象

基本的介绍

面向对象是一种编程思路(写代码的套路)
编程思想:
1.面向过程
2.面向对象
以上两种都是属于写代码的套路(方法),最终目的都是为了将代码写出来,只不过过程和思考方法不太一样

类和对象

面向对象的核心思想是 找一个对象去帮我们处理事情
在程序代码中 对象是由 类 创建的

类和对象,是 面向对象编程思想中非常重要的两个概念
  • 对象

类的组成

1.类名(给这多个事物起一个名字,在代码中 满足大驼峰命名法(每个单词的首字母大写))
2.属性(事物的特征,即有什么,一般文字中的名词)
3.方法(事物的行为,即做什么事,一般是动词)

类的抽象

类的抽象,其实就是找到 类的 类名 ,属性 和方法

面向对象基本代码

1.定义类

先定义简单的类,不包含属性,在python中定义类需要使用关键字

方法:方法的本质是在类中定义函数,只不过,第一个参数是:self
class 类名:
	def 方法名(self): #这就是一个方法

2.创建对象

创建对象是使用 类名() 进行创建 ,即
类名() #创建一个对象,这个对象在后续不能使用
#创建的对象想要在后续的代码中继续使用,需要使用一个变量,将这个对象保存起来
变量 = 类名()

#一个类可以创建多个对象,只要出现 类名() 就是创建一个对象,每个对象的地址是不一样的

class 类名:
	def 方法名(self):
        pass
变量 = 类名()

3.调用方法

对象.方法名()

4.案例的实现

需求:小猫爱吃鱼,小猫要喝水
类型:猫类 Cat
属性:暂无
方法:吃鱼(eat) 喝水(drink)
class cat:
    def eat(self):#self会自动出现,暂不管
        print('小猫爱吃鱼')

    def drink(self):
        print('小猫要喝水')

cat().eat()

self的说明

class cat:
    def eat(self):#self会自动出现,暂不管
        print('小猫爱吃鱼')

    def drink(self):
        print('小猫要喝水')

cat().eat()

1.从函数语法上说,self是形参,就可以是任意的变量名,只不过我们习惯将这个形参写出self

2.self是普通的形参,但在调用的时候没有传递实参数,原因是,python解释器在执行代码的时候,自动的将调用这个方法的对象,传递给了self,即self的本质是对象

3.验证,只需要确定,通过哪个对象调用,对象的引用和self的引用是一样的

4.self 是函数中的局部变量,直接创建对象是全局变量

5.self只能在方法内部使用,不能在方法外使用

对象的属性操作

添加属性

对象.属性名 = 属性值
  • 类内部进行添加

  • 在内部方法中,self是对象,
    self.属性名 = 属性值
    #在类中添加属性一般写在 _init_方法中
    
  • 类外部添加

  • 对象.属性名 = 属性值 #一般不使用
    

获取属性

对象.属性名

-类内部

在内部方法中,self是对象,
self.属性名

-类外部

对象.属性名 #一般很少用

魔法方法

python 中有一类方法,以两个下划线开头,两个下划线结尾,并且在满足某个条件的情况下,会自动调用,这个方法称为 魔法方法

学习:
1.什么情况下自动调用
2.有什么用,用在哪
3.书写的注意事项

__init__ 方法

1.什么情况下自动调用
	创建对象之后会自动调用
2.有什么用,用在哪
	给对象添加属性的,(初始化方法,构造方法) 2.某些代码,在每次创建对象之后,都要执行,就可以将这行代码写在__init__方法中
3.书写的注意属性
	1.不要写错了 2.如果init方法中,存在出现了 self 之外的参数 ,在创建对象的时候必须传参

__str__ 方法

1.什么情况下自动调用
	使用print(对象) 打印对象的时候,会自动调用
2.有什么用,用在哪
	在这个方法中一般书写对象的属性信息的,即打印对象的时候想要查看什么信息,在这个方法中进行定义
	如果类中没有定义__str__方法,print(对象),默认输出对象的引用地址
3.书写的注意属性
	这个方法必须返回!!!! 一个字符串
	
class Cat:
    """
    猫类,属性name,age,show_info(输出属性信息)
    """
    # 定义添加属性
    def __init__(self, name,age):  # 创建对象之后,输出
        self.name = name  # 添加属性 name
        self.age = age  # 添加age属性

    def show_info(self):
        print(f'小猫的名字是{self.name},年龄是;{self.age}')

    def __str__(self):
        # 方法必须返回一个字符串,只要是个字符串就行
        return f'小猫的名字是{self.name},年龄是;{self.age}'

blue_cat = Cat('蓝猫',22)  # 创建对象,会输出
print(blue_cat)
blue = blue_cat.show_info()  # 不是创建对象

__del__ (了解即可)

__init__方法,创建对象之后,会自动调用
__del__方法,对象被删除销毁时,自动调用的(遗言,处理后事)

1.调用场景,程序代码运行结束之后,所有对象都被销毁
2.调用场景,直接使用del 删除对象(如果对象有多个名字(多个对象引用一个对象),需要吧所有有的对象都删除才行)

dir(对象) 获取对象的所有方法

实例

1.

class Person:
    def __init__(self,name,weight):
        self.name =name
        self.weight = weight
    def __str__(self):
        return f'姓名:{self.name},体重:{self.weight}kg'

    def run(self):
        print(f'{self.name} 运动了,体重减少了')
        #减体重,即修改属性
        self.weight -=0.5
    def eat(self):
        print(f'{self.name} 大餐一顿,体重增加了')
        #修改体重
        self.weight +=1

xm = Person('小明',75.0)
print(xm)
xm.run()
print(xm)
xm.eat()
print(xm)

家具类

正在上传…重新上传取消

class HouseItem:
    """家具类"""
    def __init__(self,name,area):
        """添加方法"""
        self.name = name
        self.area = area
    def __str__(self):
        return f'家具名字{self.name},占地面积 {self.area} 平米'

class House:
    """房子类"""
    def __init__(self,name,area):
        self.name =name #户型
        self.total_area =area  #总面积
        self.free_area =area #剩余面积
        self.item_list =[] #家具名称列表
    def __str__(self):
        return f"户型:{self.name},总面积:{self.total_area}平米,剩余面积:{self.free_area} 平米 " \
               f"家具名称列表:{self.item_list}"
    def add_item(self,item): #item表示家具对象
        # 判断房子剩余面积(self.free_area)和家具的占地面积(item.area)之间的关系
        # self表示 房子对象 缺少一个家具对象
        if self.free_area >= item.area:
            #添加教具
            self.item_list.append(item.name)
            #修改剩余面积
            self.free_area -=item.area
            print(f'{item.name}添加成功')
        else:print('修改失败')
bed = HouseItem('席子',4)
chest = HouseItem('餐桌',2)
table = HouseItem('餐桌',1.5)

#创建房子对象
house = House('三室一厅',150)
print(house)

#添加 床
house.add_item(bed)
print(house)

web网站

正在上传…重新上传取消

class LoginPage:
    def __init__(self,username,password,code):
        self.username = username
        self.password = password
        self.code = code
        self.button = '登录'

    def login(self):
        print(f'1.输入用户名{self.username}')
        print(f'2.输入密码{self.password}')
        print(f'3.输入验证码{self.code}')
        print(f'4.点击按钮{self.button}')

login = LoginPage('admin','123456','8888')
login.login()

私有和公有

1.在python中定义的方法和属性,可以添加访问控制权限(即在什么地方可以使用这个属性和方法)
2.访问控制权限分为两种,公有权限,私有权限

3.公有权限
	直接书写的方法和属性,都是公有
	公有的方法和属性,可以在任意的地方访问和使用

4.私有权限
	在类内部,属性名或者方法名 前面加两个 下划线,这个属性或者方法 就变成 私有的
	私有的方法和属性,只能在当前类的内部使用

5.什么时候定义私有
	1.某个属性或者方法,不想在类外部访问和使用,就将他定义为私有即可
	2.测试中,一般不怎么使用,直接公有即可
	3.开发中,会根据需求文档,确定什么作为私有

6.如果想要在外部操作私有属性,方法是,在类内部定义共有的方法,我们通过这个方法进行操作

案例

定义一个Person类,属性name,age(私有)

代码

class Person:
    def __init__(self,name,age):
        self.name = name
        # 私有的本质,是python 解释器执行代码的时候发现属性名或者方法名前有两个_,会将这个名字重命名
        # 会在这个名字前边加上,_类名前缀,即self.__age ===> self._Person__age
        self.__age = age #年龄,将其定为私有,不能在外部修改

    def __str__(self):
        return f'名字{self.name},年龄{self.__age}'

xm = Person('小明',18)
# 在类外部直接访问age属性
# 直接修改 age 属性
xm.age = 20
#print(xm.__age)  不能在类外部进行使用
xm.__age =20 #这个不是修改私有属性,而是添加了一个公有属性__age
print(xm.age)

补充

# 对象.__dict__ 魔法属性,可以将对象具有的属性组成字典返回

继承

面向对象三大特征

  • 封装 根据 职责 将属性 和 方法 封装 到一个抽象的 类 中
  • 继承 实现代码的重用,相同的代码不需要重复的编写
  • 多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度

1.1继承的概率和语法

继承的概念:子类 拥有 父类 的所有 方法 和 属性

继承的语法

class A(object)
class A: #没有去写父类,但也有父类,object,object 类 是Python 中最顶级*原始的类
	pass

class B(A):
	pass

1.A 类,称为是 父类(基类)
2.B类,称为是 子类(派生类)

单继承:一个类只继承一个父类,称为单继承
继承之后的特点:
	子类(B)继承父类(A)之后,子类的对象可以直接使用父类中定义的公有属性和方法
  • 案例

    1.定义一个 动物类 吃
    2.定义一个 狗类 继承动物类,吃,叫
    3.定义一个 哮天犬类,继承 狗类
    
    """
    1.定义一个 动物类 吃
    2.定义一个 狗类 继承动物类,吃,叫
    3.定义一个 哮天犬类,继承 狗类
    """
    
    
    class Animal:
        def eat(self):
            print('要吃东西')
    
    class Dog(Animal):
        def bark(self):
            print('汪汪汪')
    
    class XTQ(Dog):
        pass
    
    ani = Animal()
    ani.eat()
    
    dog = Dog()
    dog.eat()
    dog.bark()
    
    xtq = XTQ()
    xtq.eat()
    

结论

python 中 对象.方法() 调用方法
1.现在自己的类中的去找有没有这个方法 如果有,直接调用
2.如果没有去父类中 查找,如果有,直接调用
3.如果没有,去父类的父类中查找,如果有直接调用
4....
5.如果object 类中有,直接调用,如果没有,代码报错

重写

重写:在子类中定义了和父类中名字相同的方法,就是重写
重写的原因:父类中的方法,不能满足子类对象的需求,所以重写
重写之后的特点:调用子类字节的方法,不再调用父类中的方法
重写的方式:
1.覆盖(父类中功能完全抛弃,不要,重写书写)
2.扩展(父类中功能还调用,只是添加一些新的功能)(使用较多)


覆盖

1.直接在子类中,定义和父类中名字相同的方法
2.直接在方法中书写新的代码
class Dog:
    def bark(self):
        print('汪汪汪叫....')

class Xitiao(Dog):
    # 重写bark方法
    def bark(self):
        print('嗷嗷嗷叫')

xtq = Xitiao()
xtq.bark()

扩展父类中的功能

1.直接在子类中,定义和父类中名字相同的方法
2.在合适的地方调用 父类中方法 super().方法()
3.书写添加的新功能
class Dog:
    def bark(self):
        print('汪汪汪叫....')

class Xitiao(Dog):
    # 重写bark方法
    # 1.先 嗷嗷嗷叫(新功能) 2,汪汪汪叫(父类中功能) 3.嗷嗷嗷叫(新功能)
    def bark(self):
        print('嗷嗷嗷叫')
        super().bark() #print() 如果父类中代码有多行呢
        print('嗷嗷嗷叫...')

xtq = Xitiao()
xtq.bark()

多态

1.是一种写代码,调用的一种技巧
2.同一个方法,传入不同的对象,执行得到不同的结果,这种现象称为多态
3.是调用方法的技巧,不会影响到类的内部设计

哪个对象调用方法,就去自己的类中去查找这个方法,找不到去父类中找

属性和方法

Python中一切皆为对象
即 使用class 定义的类 也是一种对象

对象的划分

实例对象(实例)

1.通过 类名() 创建的对象,我们称为实例对象,简称实例
2.创建对象的过程称为类的实例化
3.我们平时所说的对象就是指实例对象(实例)
4.每个实例对象,都有自己的内存空间,在自己的内存空间中保存自己的属性(实例属性)

类对象(类)

1.类对象 就是 类,或者可以认为是 类名
2.类对象是Python解释器在执行代码的过程中 创建的
3.类对象的作用:使用类对象创建实例 类名(),第二个作用 类对象 也有自己的内存空间,可以保存一些属性值信息(类属性)
4.在一个代码中,一个类 只有一份内存空间

属性的划分

实例属性

  • 是实例对象具有的属性

  • 定义和使用

    在__init__方法中,使用self.属性名 = 属性值 定义
    在方法中是 使用self.属性名 来获取(调用)
    
  • 内存

    实例属性,在每个实例中 都存在一份
    
  • 使用时机

    1.基本上 99% 都是实例属性,即通过self 去定义
    2.找多个对象,来判断这个值是不是都是一样的,如果都是一样,同时变化,则一般定义为类属性,否则定义为 实例属性
    

类属性

  • 是 类对象 具有的属性

  • 定义和使用

    在类内部,方法外部,直接定义的变量,就是类属性
    class Game:
        #类属性,游戏的最高分
        top_score = 0 这就是一个类属性
        def __init__(self,name):
            # 定义实例属性
            self.name = name
    使用:类对象.属性值 = 属性值 or 类名.属性值 = 属性值
    类对象.属性名 or 类名.属性名
    
  • 内存

    只有 类对象 中存在一份
    

实例方法(最常用)

  • 定义

    # 在类中直接定义的方法 就是 实例方法
    class Demo:
    	def func(self): #参数一般写作 self,表示的是实例对象
    		pass
    
  • 定义的时机(什么时候用)

    如果在方法中需要使用实例属性(即需要使用self),则这个方法定义为 实例方法
    
    
  • 调用

    对象.方法名() #不需要给  self 传参
    

类方法(会用)

  • 定义

    #在方法名字的上方书写 @classmethod 装饰器(使用@classmethod 装饰的方法)
    class Demo:
    	@classmethod
        def func(cls): # 参数一般写作 cls,表示的类对象(即类名) class
            pass
    
  • 定义时机(什么时候用)

    1.前提,方法中不需要使用 实例属性(即self)
    2.用到了类属性,可以将这个方法定义为类方法,(也可定位为实例方法)
    
  • 调用

    1.通过类对象调用
    类名.方法名() #也不需要给cls传参,python解释器自动传递
    2.通过实例对象调用
    实例.方法名() #也不需要给cls传参,python解释器自动传递
    

静态方法(基本不用)

  • 定义

    # 在方法名字的上方书写 @statimethod 装饰器(使用 @staticmethod 装饰的方法)
    class Demo:
    	@staticmethod
    	def func():		#一般没有参数
    		pass
    
  • 定义时机(什么时候用)

    1.前提,方法中不需要使用 实例属性(即self)
    2.也不使用 类属性,可以将这个方法定义为 静态方法
    
  • 调用

    1.通过类对象调用
    类名.方法名()
    2.通过实例对象调用
    实例.方法名()
    
  • 优化(使用 类方法 和静态方法)

        @staticmethod
        def show_help():
            print('help')
            
        @classmethod
        def show_top_score(cls):
            print(f'游戏的最高分为{Game.top_score}')
    

哈希

哈希(hash):是一个算法, 可以对数据产生一个唯一的值(指纹)

is 可以用来判断两个对象是不是同一个对象,即 两个对象的引用是否相同
a is b ====> id(a) == id(b)

面试中可能会问: is 和 == 区别?
== 只判断数据值是否相同,is 判断引用是否相同

文件

文件介绍

计算机的 文件,就是存储在某种 长期存储设备 上的一段 数据
作用:将数据长期保存下来,在需要的时候使用

1.计算机只认识 二进制(0,1)
2.文件中存储的数据都是以二进制(0 1)的形式去存储的

可以根据 文件中的二进制内容,能否使用记事本软件,将其转换为文字,将文件分为两种:文本文件和二进制文件
  • 文本文件

    • 能够使用记事本软件打开(能够使用记事本转换为文字)
    • txt ,md ,py ,html ,css , js ,json
  • 二进制文件

    • 不能使用记事本软件打开的,
    • exe,mp3,mp4,jpg,png

文件操作

文件的操作

1.打开文件
2.读或者写文件
3.关闭文件

1.打开文件

打开文件:将文件从磁盘中(硬盘) 中 读取到内存中
语法:
open(file,mode='r',encoding =None)
	参数file:要打开的文件,类型是字符串,文件的路径可以是相对路径可以相对路径,也可以是绝对路径(从根目录开始书写的路径)。建议使用相对路径(相对于当前代码文件所在的路径,./ ../)
	参数 mode:默认参数(缺省参数),表示的是打开文件的方式,
		r:read 只读打开
		w:write 只写打开
		a:append 追加打开,在文件的末尾写入内容
	参数 encoding:编码打开,(文件和二进制如何进行转换的)
		gbk:将一个汉字转换为 2个字节二进制
		utf-8:常用,将一个汉字转化为3个字节的二进制
	返回值:返回的是 文件对象 ,后续对文件的操作,都需要这个对象

2.读或者写文件

写文件

向文件中写入指定的内容
前提:文件的打开方式是w 或者 a(在文件末尾进行写入内容)
文件对象.close()
文件对象.write('写入文件的内容')
#注意:
1.文件不存在,会直接创建文件
2.文件存在,会覆盖原文件(将原文件中的内容清空)
# 返回值:写入文件的字符数,一般不关注
#1.打开文件
f = open('a.txt','w',encoding='utf-8')
#2.写文件
f.write('好好谢谢\n')
f.write('好好学习')
#3.关闭文件
f.close()

读文件

将文件中的内容读取出来
前提:文件的打开方式需要是 r
文件对象.read(n)
#参数 n 表示读取多少个字符,一般不写,表示读取全部内容
#返回值:读取到的文件内容,类型:  字符串
#1.打开文件
f = open('a.txt','r',encoding='utf-8')
#2.读文件
buf = f.read()
print(buf)
#3.关闭文件
f.close()

# r 方式打开文件,如果文件不存在,代码会报错

3.关闭文件

关闭文件:将文件占用的资源进行清理,同时会保存文件,文件关闭之后,这个文件对象就不能使用了
文件对象.close()

使用with open 打开文件

with open() 打开文件的好处:不用自己去书写关闭文件的代码,会自动进行关闭

with open(file,'r',encoding='utf-8') as 变量:
	#在缩进中读取或者写入文件
    
    #缩进中的代码执行结束,出缩进之后,文件会自动关闭

按行读取文件内容

按行读取文件:一行读取一行内容

文件对象.readline()

with open('a.txt','r',encoding='utf-8') as f:
	buf = f.readline()
	print(buf)
	print(f.readline())


with open('a.txt','r',encoding='utf-8') as f:
    for i in f:
        print(i,end='')

with open('b.txt',encoding='utf-8') as f:
	while True:
		buf = f.readline()
		if len(buf) == 0
			break
		else:
			print(buf,end='')

JSON操作

json文件 也是一种文本文件,就可以直接使用 read() 和 write()
去操作文件,只是使用这两个方法,不方便,所以对json文件有自己独特的读取和写入的方法

常用在 做测试的时候,将测试数据定义为 json 文件格式,使用 代码读取
json 文件,即读取测试数据,进行传参(参数化)


json的介绍

基于文本,独立于语言的轻量级的数据交换格式
- 基于文件,是一个文本文件,不能包含图片,音视频等
- 独立于语言,不是某一个语言特有的,每种编程语言都可以使用的
- 轻量级,相同的数据,和其他格式相比,占用的大小比较小
- 数据交换格式,后端程序员 给前端的数据(json,html xml)

json文件的语法

1.json 文件的后缀是 .json
2.json 中主要的数据类型为 对象({} 类似 python中 字典) 和 数组([],类似python中的列表),对象和 数组可以互嵌套
3.一个json文件是一个 对象或者数组(即 json 文件的最外层要么是一个{},要么是一个数组 [])
4.json 中的对象是由键值对组成的,每个数据之间使用 逗号隔开,但是最后一个数据后边不要写逗号
5.json中的字符串 必须使用 双引号""
6.json中的其他数据类型
数字类型  int float
string字符串 str
布尔类型 true false  ------ True False
null ---------None

json文件的书写

我叫小明,我今年 18 岁,性别男,爱好 听歌,游戏,购物,吃饭,睡觉,打豆豆
我的居住地址为 国家中国,城市上海
{
  "name": "小明",
  "age": 18,
  "Sex": "男",
  "like": [
    "听歌",
    "游戏",
    "动物",
    "吃饭",
    "打豆豆"
  ],
  "adress": {
    "country": "中国",
    "city": "上海"
  }
}

读取json文件

1.导包 import json
2.读打开文件
3.读文件
json.load(文件对象)

#返回的是 字典(文件中是对象)或者是列表(文件中是数组)

#1.导入json
import json

#2.读取打开文件
with open('info.json','r',encoding='utf-8') as f:
    # 3 .读取文件
    # buf = f.read()
    # print(buf,type(buf))

    result = json.load(f) #转化为dict

    print(type(result))
    #姓名
    print(result.get("name"))
    #年龄
    print(result.get("age"))
    #城市
    print(result.get("address").get("city"))
import json

with open('info2.json','r',encoding='utf-8') as f:
    info_list = json.load(f)
    print(type(info_list))
    for info in info_list:
        print(info.get('name'), info.get('age'), info.get('address').get('city'))

json的写入

文件对象.write(字符串) 不能直接将Python 的列表 和字典 作为参数传递
想要将 Python 中数据类型存为 json 文件,需要使用json 提供的方法,
不再使用write

步骤:
1.导包 improt json
2.写(w) 方式打开文件
3.写入
json.dump(Python 中的数据类型,文件对象)

import json
my_list = [('admin','123456','登录成功')]
with open('info4.json','w',encoding='utf-8') as f:
    json.dump(my_list,f,ensure_ascii=False) #直接显示中文,不以ASCII的方式显示
    
    #显示缩进
    json.dump(my_list,f,ensure_ascii=False,indent=4)

异常

程序在运行时,如果python 解释器 遇到一个错误,会停止程序执行,并且提示一些错误信息,这就是异常

程序停止执行并提示错误信息,这个动作,抛出异常(raise 关键字)
捕获异常:程序遇到异常,默认动作是终止代码程序的执行,遇见异常之后,可以使用 异常捕获,让程序代码继续运行,不会终止运行(重点!!!)

异常捕获

基本语法

try:
	书写可能发生的异常代码
except:#任何类型的异常都能捕获
	发生了异常执行的代码
    
    
try:
	书写可能发生异常的代码
except 异常类型:# 只能捕获指定类型的异常,如果不是这个异常,还是会报错
	发生了异常执行的代码

try:
    num = input("请输入数字:")

    num = int(num)

    print(num)
except:
    print('请输入正确的代码')f'c

捕获指定类型的异常

好处:可以针对不同的异常错误,进行单独的代码处理
try:
	书写可能发生异常的代码
except 异常类型1:
    发生了异常1执行的代码
except 异常类型2:
	发生了异常执行的代码
except 异常类型...
	发生了异常...执行的代码

异常捕获的完整版本

完整版本中的内容,不是说每一次都要全部书写,根据自己的需要,去选择其中进行使用

try:
	可能发生异常的代码
except 异常类型1:
	发生异常类型1执行的代码
    #Exception 是常见异常类的父类,这里书写Exception,可以捕获常见的所有异常,as 变量 ,这变量是一个异常类的对象,print(变量),可以打印异常信息
except	Exception as 变量:
	发生其他类型的异常,执行的代码
else:
	没有发生异常会执行的代码
finally:
	不管有没有发生异常,都会执行的代码

异常传递

异常传递是Python中实现好了,我们不需要操作,我们知道异常会进行传递,

异常传递:在函数嵌套调用中,被调用的函数,发生了异常,如果没有捕获,会将这个异常向外层传递,...如果传到最外层,还没有捕获,才会报错

模块和包

1.python 源代码文件就是一个模块
2.模块中定义的变量 函数 类,都可以让别人使用,同样,可以使用别人定义的
(好处:别人定义好的不需要我们再次书写,直接使用即可)
3.想要使用 别人的模块中的内容工具(变量,类,函数),必须先导入模块 才可以
4.我们自己写的代码,想要作为模块使用,代码的名字需要满足标识夫的规则(数字,字母下划线组成,不能以数字开头)

模块的查找顺序

在导入模块的时候,会先在当前目录中找到模块,如果找到,就直接使用
如果没有找到,则回到系统的目录中进行查找,找到,直接使用
没有找到,报错

注意点:
定义代码文件的时候,你的代码名字不能和你要导入的模块名字相同,

__name__的作用

1.每个代码文件都是一个模块
2.在导入模块的时候,会执行模块中的代码(三种方法都会)
3.__name__ 变量
3.__name__变量 是python解释器自动维护的变量
3.2 __name__ 变量,如果代码是直接运行,值是__main__

在 Python中,包 是一个目录,只不过在这个目录存在一个文件
__init__.py
将功能相近或者相似的代码放在一起

在Python 中使用的时候,不需要是区分包还是模块,使用方式是一样的

random 模块(某个代码文件)
json 包(目录)

UnitTest框架

  • 框架
说明:
1.框架英文单词framework 2.为解决一类事情的功能集合

需要按照框架的规定(套路) 去书写代码


  • 什么是UnitTest框架
  概念:UnitTest是Python自带的一个单元测试框架,用它来做单元测试
  
  自带的框架:不需要另外按照安装,只要安装Python,就可以使用
  第三方:想要使用 需要另外安装使用(pytest)
  
  单元测试框架:主要用来做单元测试,一般单元测试是开发做的
  对于测试来说,UnitTest 框架的作用是 自动化脚本(用例代码)执行框架
  (使用 unittest 框架 来管理 运行 多个测试用例的)

  • 为什么使用UnitTest框架
1.能够组织多个用例去执行
2.提供丰富的断言方法(让程序代码代替人工自动的判断预期结果和实际结果是否相符)
3.能够生成测试报告
  • UnitTest核心要素(unitest 的组成)
TestCase(测试用例),注意这个测试用例是 unittest 框架的组成部分
不是手工和自动化中我们所说的用例(Test case)

主要作用:每个 TestCase(测试用例) 都是一个代码文件,在这个代码文件中 来书写真正的用例代码

TestSuit(测试套件),用来管理 组装多个 TestCase(测试用例)

TestRunner(测试执行,测试运行) 用来去执行 TestSuite(测试套件)的

TestLoader(测试加载),功能是对 TestSuite(测试套件) 功能的补充,
管理 组装(打包)多个 TestCase(测试用例)的

Fixture(测试夹具),书写在 TestCase() 代码中, 是一种代码结构,可以在每个方法执行前后都会执行的内容

举例:
登录的测试用例,每个用例中重复的代码就写可以写在 Fixture 代码结构中,只写一遍,但每次用例方法的执行,都执行Fixture中代码
1.打开浏览器
2.输入网址
  • TestCase(测试用例)

    """
    案例练习
    """
    #1.导包
    import unittest
    
    #2.自定义测试类
    import tool
    
    
    class TestAdd(unittest.TestCase):
        #测试方法
        def test_method1(self):
            if tool.add(1,2) == 1+2:
                print('测试通过')
            else:
                print('测试失败')
    
        def test_method2(self):
            if tool.add(1,3) == 1+3:
                print('测试通过')
            else:
                print('测试失败')
    
        def test_method3(self):
            if tool.add(1,5) == 1+5:
                print('测试通过')
            else:
                print('测试失败')
    
  • TestSuite 和 TestRunner

    import unittest
    
    #实例化套件对象
    from testcase import TestAdd
    
    suite = unittest.TestSuite()
    #添加测试方法
    suite.addTest(unittest.makeSuite(TestAdd))
    
    #实例化执行对象
    runner = unittest.TextTestRunner()
    runner.run(suite)
    

  • TestLoader(测试加载)

    TestLoader(测试加载),作用和TestSuite 的作用是一样的,对 TestSuite 功能进行补充,用来组装测试用例
    
    比如:如果TestCase 代码文件有很多,(10 20 30)
    
    使用步骤
    1.导包
    2.实例化测试加载对象并添加用例 ——————>得到的是 suite对象
    3.实例化 运行对象
    4.运行对象执行套件对象
    
  • 代码实现

    在一个项目当中 TestCase(测试用例) 的代码一般放在一个单独的目录当中(case)
    
    
    """TestLoader 的使用"""
    #1.导包
    import unittest
    
    #2.实例化加载对象并添加用例
    #unittest.TestLoader().discover('用例的所在路径','用例的代码文件名')
    #用例所在路径,建议使用相对路径,用例的代码文件名可以使用 *(任意多个任意字符) 通配符
    suite = unittest.TestLoader().discover('./case','test*.py')
    
    #3.实例化运行对象
    runner = unittest.TextTestRunner()
    runner.run(suite)
    
    #1.导包
    #2.使用默认的加载对象并加载用例
    #3.实例化运行对象并运行
    

Fixture(测试夹具)

  Fixture(测试夹具) 是一种代码结构
  
  在某些特定的情况下,会自动执行
  

方法级别

  在每个测试方法(用例代码) 执行前后都会自动调用的结构
  # 方法执行之前
  def setUp(self):
      #每个测试方法执行之前都会执行
      pass
  
  # 方法执行之后
  def teardown(self):
      #每个测试方法执行之后都会执行
      pass
  

类级别[掌握]

  在每个测试类中所有方法执行前后,都会自动调用的结构(在整个类中 执行之前执行之后一次)
  # 类级别的Fixture 方法,是一个 类方法
  # 类中所有方法之前
  @classmethod
  def setUpClass(cls):
  	pass
  #类中所有方法之后
  @classmethod
  def teardownClass(cls):
  	pass

模块级别[了解]

  模块:代码文件
  在每个代码文件执行前后执行的代码结构
  #模块级别的需要写在类的外边直接定义函数即可
  # 代码文件之前
  def setUpModule():
      pass
  #代码文件之后
  def teardownModule():
      pass
      
  方法级别和类级别 前后的方法,不需要同时出现,根据用例代码的需要自行的选择使用

案例

  1.打开浏览器(整个测试过程中就打开一次浏览器) 类级别
  2.输入网址 (每个测试方法都像需要一次) 方法级别
  3.输入用户名 密码 验证码 点击登录(不同的测试数据) 测试方法
  4.关闭当前页面  (每个测试方法都需要一次) 方法级别
  5.关闭浏览器 类级别
  
  -------
  

  import unittest
  class TestLogin(unittest.TestCase):
      def setUp(self) -> None:
          """每个测试方法执行之前都会调用的方法"""
          print('输入网址....')
      def tearDown(self) -> None:
          """每个测试方法执行之后都会调用的方法"""
          print('关闭当前页面....')
  
      @classmethod
      def setUpClass(cls) -> None:
          print('1.打开浏览器')
      @classmethod
      def tearDownClass(cls) -> None:
          print('2.关闭浏览器')
  
      def test_1(self):
          print('输入用户名密码验证码,点击登录 1 ')
  
      def test_2(self):
          print('输入错误用户名密码验证码,点击登录 2')

断言

  让程旭代替人工自动的判断预期结果和实际结果是否相符
  
  断言的结果有两种
  Ture 用例通过
  False 代码抛出异常,用例不通过

assertEqual

  assertEqual(预期结果,实际结果) #判断预期结果和实际结果是否相等
  1.如果相等,用例通过
  2.如果不相等,用例不通过,抛出异常

assertIn

assertIn(预期结果,实例结果) #判断预期结果是否包含在实际结果中
1.包含,用例通过
2.不包含,用例不通过,抛出异常

assertIn('admin','admin') #包含
assertIn('admin','adminnnnn') #包含
assertIn('admin','aaaadminnn') #包含
asserttIn('admin','addddmin') #不是包含

参数化

参数化,在测试方法中,使用 变量 来代替具体的测试数据,然后使用传参的方法将测试数据传递给方法的变量
好处:相似的代码不需要多次书写

工作中场景:
1.测试数据一般放在 json 文件中
2.使用代码读取json 文件,提取我们想要的数据 ---->[()()()] or [[],[],[]]

安装插件

unittest 框架本身是不支持参数化,想要使用参数化,需要安装插件来完成

- 联网安装(在cmd 窗口安装)
- pip install parameterized

-------
pip 是 python 中包(插件) 的管理工具,使用这个工具下载安装插件

验证

pip list #查看到 parameterized

新建一个 python 代码文件,导包验证
from pa... import pa....

参数化代码

1.导包 unittest/pa
2.定义测试类
3.书写测试方法(用到的测试数据使用变量代替)
4.组织测试数据并传参
# 1.导包 unittest/pa
import unittest
from parameterized import parameterized

# 2.定义测试类
from login import login

#组织数据
data = [
    ('admin','123456','sucessful'),
    ('root','123456','defect'),
    ('admin','123123','defect'),
]


class TestLogin(unittest.TestCase):
# 3.书写测试方法(用到的测试数据使用变量代替)
    @parameterized.expand(data)
    def test_login(self,username,password,expect):
        self.assertEqual(expect,login(username,password))

# 4.组织测试数据并传参(装饰器)

正在上传…重新上传取消

# 1.导包 unittest/pa
import json
import unittest
from parameterized import parameterized

# 2.定义测试类
from login import login

#组织数据这边用的是将json中的数据传过来
def build_data():
    with open('test.json',encoding='utf-8') as f:
        result = json.load(f)
        data = []
        for i in result:#[{},{},{}]
            data.append((i.get("username"),i.get("password"),i.get("expect")))
    return data

class TestLogin(unittest.TestCase):
# 3.书写测试方法(用到的测试数据使用变量代替)
    @parameterized.expand(build_data())
    def test_login(self,username,password,expect):
        self.assertEqual(expect,login(username,password))

# 4.组织测试数据并传参(装饰器)

跳过

对于一些未完成的或者不满足测试条件的测试函数和测试类,不想执行,可以使用跳过使用方法,装饰器完成
代码书写在 TestCase 文件
# 直接将测试函数标记成跳过
@unittest.skip('跳过的原因')
# 根据条件判断测试函数是否跳过,判断条件成立,跳过
@unittest.skipIf(判断条件,'跳过原因')

import unittest

version = 29

class TestDemo(unittest.TestCase):
    @unittest.skip('不想运行这条!')
    def test_1(self):
        print('测试方法1')

    @unittest.skipIf(version >= 30,"版本大于等于30 不用执行" )
    def test_2(self):
        print('测试方法2')

    def test_3(self):
        print('测试方法3')

测试报告

自带的测试报告

只有单独运行 TestCase 的代码,才会生成测试报告

生成第三方的测试报告

1.获取第三方的 测试运行类模块,将其放在代码的目录当中
2.导包 unittest
3.使用 套件对象,加载对象,去添加用例方法
4.实例化 第三方运行对象,并运行 套件对象
import unittest
from HTMLTestRunner import HTMLTestRunner

# 3. 使用 套件对象,加载对象 去添加用例方法
suite = unittest.defaultTestLoader.discover('.','pa1.py')
#4. 实例化 第三方的运行对象 并运行 套件对象
HTMLTestRunner()
#stream = sys.stdout 必填,测试报告的文件对象(open),注意点,要使用wb 打开
#verbosity = 1, 可选,报告的详细程度,默认 1 简略,2 详细
#title = None ,可选,测试报告的标题
#description = None 可选,描述信息,Python的版本,pycharm版本

file = 'report.html'
with open(file,'wb') as f:
    runner = HTMLTestRunner(f,2,'测试报告') #运行对象
    # #运行对象执行套件
    runner.run(suite)

流程

1.组织用例文件(TestCase 里边),书写参数化,书写断言,书写Fixture,书写,跳过,如果只有单个测试文件,直接运行,得到测试报告,如果有多个测试文件,需要组装运行生成测试报告

2.使用 套件对象进行组装,或者使用 加载对象组装

3.运行对象, 运行
3.1 运行对象 = 第三方的运行类(文件对象(打开文件需要使用 wb 打开方式))
3.2 运行对象.run(套件对象)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值