Python 基础

文章目录


一、python 的安装

官网:https://www.python.org/downloads
尽量避开最新版,也不要低于3.6版本,其他任意都可。
安装后,python没有桌面快捷方式,需要在pycharm(vscode等编辑器)或者cmd中使用。
cmd中打开使用 python 文件.py
在这里插入图片描述
pycharm安装:https://www.jetbrains.com/pycharm/download

最后在编辑器中配置路径解释器就ok了

二、基本数据类型

1. 数字类型

  • 整型(int),就是整数,即不带小数点的数
  • 浮点型(float),就是小数
  • 布尔类型(bool),只有两个值:真True(1), 假False(0),非0即真
    True和False 都是Python 中的关键字,注意大小写,不要写错了
  • 复数类型3 + 4i,不会用的

2. 非数字类型

  • 字符串:(str)使用引号引起来的就是字符串 'name'
  • 列表(list) [1, 2, 3,4]
  • 元组(tuple) (1, 2, 4, 4)
  • 字典(hict) {'name': mario','age': 18}

3. type()函数

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

想要将这个变量的类型在控制台显示,需要使用print 输出
print(type(变量))

a=3
print(type(a)) # <class 'int'>
print(type('a')) # <class 'str'>

三、语法的使用

两个注释:

  1. # 注释
  2. ''' 注释内容 xxxxx '''

快捷键补充:
复制粘贴一行: ctrl + d
快速在代码下方,新建一行: shift + 回车

1. 输入input

获取用户使用键盘录入的内容:
使用的函数是input()
语法:变量= input( '提示的信息')

  1. 代码从上到下执行,遇到input 函数之后,会暂停执行,等待用户的输入,如果不输入会一直等待
  2. 在输入的过程中,遇到回车,代表本次输入结束
  3. 会将你输入的内容保存到等号左边的变量中,并且变量的数据类型一定是str
res = input('请输入你的姓名:')
# 不管输入的内容是什么,最后的类型都是 字符串str
print(type(res),res) # <class 'str'> momo

2. 类型的转换

根据代码的需要,将一种数据类型转换另一种数据类型
语法: 变量 = 要转换的类型(原数据)
1.数据原来是什么类型
2.你要转换为什么类型
注意点:数据类型转换,不会改变原来的数据的类型,会生成一个新的数据类型

1. 转int()类型

int()将其他类型转换为int整型
1.可以将float类型的数字转换为整型
2.可以将整数类型的字符串转换为整型3 123

2. 转float()类型

float()将其他类型转换为浮点型
1.可以将int类型转换为浮点型float(3)---> 3.0
2.可以将数字类型的字符串(整数类型和小数类型)转换为浮点型

3. 转str()类型

str()将其他类型转换为字符串类型
任何类型都可以使用str()将其转换为字符串,一般都是直接加上引号

print(float(3)) # 3.0
print(int(3.52)) # 3
print(int('momo')) # 报错

3.输出 print()

1. 基本输出

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

print('hello python!!')

2. % 格式化输出

在字符串中指定的位置,输出变量中存储的值:
1.在需要使用变量的地方,使用特殊符号占位
2.使用变量填充占位的数据
%格式化输出占位符号

  • %d:占位,填充整型数据
  • %f:占位,填充浮点型数据
  • %s:占位,填充字符串数据string

其实%s的占位符,可以填充任意类型的数据,但最好遵循标准的占位格式

name = input('请输入你得姓名:')
age = int(input('请输入你得年龄:'))
height = float(input('请输入你得身高:'))

print('你的姓名是:%s,年龄为:%d,身高为:%.2f cm' %(name,age,height))

# 补充:
# 1.小数显示默认为 6 位,如果要指定显示小数点后几位 %.nf ,n需要换成具体的数字,即保留的小数位数。

# 显示学号为:0001
stu_num = 1
# 2. %0nd ,n需要换成具体的数字,表示整数一共占几位
print('我的学号ID为 %04d' %stu_num)

num = 86
# 3.特殊符号用 %
print('成绩及格率为%%%d' %num)

f 字符串

1.需要在字符串的前边加上f" "或者F" "
2.占位符号统一变为 { }
3.需要填充的变量写在{ xx }

name='momo'
age=19
height=1.77
stu_num = 1
num = 86

# \n 为换行(转义符)
print(f'你的姓名是{name},年龄为{age},身高为{height} cm \n学号{stu_num:03d},及格率为{num}')

4. if 判断

缩进的语句都属于if判断的语句,符合判断即执行。

age = 18
if int(age) >= 18:
    print('符合年龄要求')
    print('我也属于判断句!')
    
print('我不属于判断句,一定会执行的语句')

5.if else 判断

只会执行其中一个语句结果,else要结合if使用!

name = input('please input your name:')
pwd = input('please input your password:')

if name=='admin' and pwd =='123456':
    print(f'欢迎回来:{name}')
else:
    print('错误!')

6. if elif else 判断

如果某个判断条件有多个,此时建议使用if elif else结构来实现
1.elif也是关键字,后边和判断条件之间需要一 个空格, 判断条件之后需要冒号
2.冒号之后回车需要缩进,处在这个缩进中的的代码表示是elif 的代码块
3.在一个if判断中,可以有很多个elif
4.只有if的条件不成立,才会去判断elif的条件
5.在一个if中,如果有多个elif,只要有一个条件成立,后续的所有都不再判断

7.random 随机数

# 1. 导入随机数工具包
import random
# 2. 使用工具包中的工具产生指定范围内的数字
num = random.randint(1,10) # 产生[a, b]之间的随机整数,包含a b的
print(num)

四、循环

循环就是让指定的代码循环执行。

1. while循环

确定这行代码执行几次,如果执行多次,就放在循环的缩进中,如果只执行一次,就不要放在循环的缩进中。

while True:
	... 
	if 判断条件:
		break # 关键字的作用就是终止循环,当代码执行遇到break ,这个循环就不再执行了
	if 判断条件:
	...
# 1.定义循环获取 1- 100之间的数字并求和
num = 0
i = 1
while i <= 100:
    num += i
    i+=1
print(num) # 5050

# 2.使用循环求 1-100之间偶数的和
num = 0
i = 1
while i <= 100:
    if i % 2 == 0:
        num += i 
    i+=1
print(num) # 2550

num = 0
i = 2
while i <= 100:
    num += i 
    i+=2
print(num) # 2550

2. for循环

for的基本使用

a = 'hello'

for i in a:
    print(i)

for做指定次数的循环range()

for 变量 in range(n):
	...

for 变量 in range(a,b):
	...
  1. range() 是Python 中的函数,作用使用可以生成[0,n)之间的整数,
    range(n) 不包含n的,一个有n个数字,所以这个循环循环n次
    range(a, b)作用是生成 [a, b)之间的整数数字,不包含b
  2. 想让for循环 循环多少次,n就写几
  3. 变量的值也是每次循环从[0,n)取出一个值,第一次取得是0 ,最后一次取得是n-1

3. break 和 continue

这两个关键字只能在循环中使用!

  • break:终止循环,即代码执行遇到break, 循环不再执行,立即结束
  • continue:跳过本次循环。即代码执行遇到continue ,本次循环剩下的代码不再执行,继续下一次循环

五、容器

1. 字符串

注意:空格也算字符串。

1. 切片

切片:可以获取字符串中多个字符(多个字符的下标是有规律的,等差数列)
语法: 字符串[start : end : step]
start是开始位置的下标,end 是结束位置的下标(注意,不能取到这个位置的字符) step步长,等差数列的差值,所取的相邻字符下标之间的差值,默认是1,可以不写

num = '123456'

# 1.如果最后一个字符也要取,可以不写,但是冒号必须有
print(num[1:]) # 23456
# 2.如果开始位置为0,可以不写,但是冒号必须有
print(num[:3]) # 123
# 3.如果开始和结束都不写。获取全部内容,但是冒号必须有
print(num[:]) # 123456
# 4.获取123字符
print(num[0:3:1]) # 123
# 5.如果步长是1可以不写,最后一个冒号也不写
print(num[0:2]) # 12
# 6.获取456字符
print(num[3:6]) # 456
print(num[-3:6]) # 456

# 7.获取135,对应下标0 2 4,所以步长为2
print(num[0:6:2]) # 135
print(num[::2]) # 135
# 8.特殊应用,步长为负数,开始和结束不写,意思全变,一般不用管,只有一种使用场景
#反转(逆置)字符串字符串[::-1]
print(num[::-1]) # 654321

2. 查找方法find

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

str = 'hello world and other and'
res = str.find('and')
print(res) # 12
# 在字符串中查找第二个and出现的下标,从第一次出现的后一位开始找
res1 = str.find('and',res + 1)
print(res1) # 22
#在字符串中查找第三个and出现的下标,从第二次出现的后一位开始找
res2 = str.find('and',res1 + 1)
print(res2) # -1

3. 替换方法replace

字符串.replace(old_ str, new_ str, count) :将字符串中old_str替换为new_str
old_str: 被替换的内容
new_str: 替换为的内容
count: 替换的次数,一般不写,默认是全部替换

str = 'good good study'

# 1.将str中所有good改为GOOD
res = str.replace('good','GOOD')
print(res) # GOOD GOOD study
# 2.将str中第一个good改为GOOD
res1 = str.replace('good','GOOD',1)
print(res1) # GOOD good study

4. 拆分 split

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

str = 'one and two and three and other'

# 1.将str中按照 and 字符进行拆分
res = str.split('and')
print(res) # ['one ', ' two ', ' three ', ' other']
# 2.将str中按照 and 字符进行拆分,拆分1次
res1 = str.split('and',1)
print(res1) # ['one ', ' two and three and other']

# 3.将str中按照 空格 进行拆分
res2 = str.split()
print(res2) # ['one', 'and', 'two', 'and', 'three', 'and', 'other']
# 将str中按照 空格 进行拆分一次
res2 = str.split(maxsplit=1)
print(res2) # ['one', 'and two and three and other']

5. 字符串拼接 join

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

list = ['good','dood','study']
# 1.将list中按照 空格 进行拼接
res = ' '.join(list)
print(res) # good dood study

# 2.将list中按照 and 进行拼接
res1 = ' and '.join(list)
print(res1) # good and dood and study

2. 列表

1. 下标和切片

列表支持下标和切片操作,使用方法和字符串中的使用方法一致
区别:列表的切片得到的是列表

list1 = ['小明'181.71True]
#获取第一个数据,名字
print(list1[0])
#获取最后一个数据
print(list1[-1])

#第一第二个数据
print(list1[0:2]) # ['小明',18]
#列表页支持len()求长度的,求数据元素个数
print(1en(list1)) # 4

2. index()查找列表中数据下标的方法

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

list = [1,2,4,8,2,5]
# 找出数字 2 出现的下标
res = list.index(2)
print(res) # 1

3. 判断数据是否存在

判断容器中某个数据是否存在可以使用in关键字
数据in容器,如果存在返回True ,如果不存在,返回False

list = [1,2,4,8,2,5]

# 找出数字 3 出现的下标
if 3 in list:
    print(list.index(3))
else:
    print('list不存在数字 3')

4. 统计出现的次数

统计出现的次数,使用的是count() 方法
列表.count(数据) 返回数据出现的次数

list = [1,2,4,8,2,5]

# 找出数字 2 出现的次数
if 2 in list:
    print(list.count(2)) # 2
else:
    print('list不存在数字 2')

5. append尾部添加数据的方法

列表.append(数据) 将数据添加到列表的尾部
返回:返回的None(关键字,空),一般就不再使用变量来保存返回的内容
想要查看添加后的列表,需要打印的是列表

list = []

# 向列表中添加数据
list.append('apple')
print(list) # ['apple']

6. insert指定下标位置添加数据

列表.insert(下标,数据) 在指定的下标位置添加数据,如果指定的下标位置本来有数据,原数据会后移
返回:返回的None(关键字,空),- -般就不再使用变量来保存返回的内容
想要查看添加后的列表,需要打印的是列表

list = ['apple']

# 向列表下标位置为 1 中添加数据
list.insert(1,'orange')
print(list) # ['apple','orange']
# 再次向列表下标位置为 1 中添加数据(位置会全部后移)
list.insert(1,'pear')
print(list) # ['apple', 'pear', 'orange']

7. extend列表合并

列表1.extend(列表2) 将列表 2中的所有数据逐个添加的列表1的尾部
返回:返回的None(关键字,空),一-般就不再使用变量来保存返回的内容想要查看添加后的列表,需要打印的是列表

list = ['apple', 'pear', 'orange']

list1 = ['computer','tv']
# 把列表的内容分别放进去
list1.extend(list)
print(list1) # ['computer', 'tv', 'apple', 'pear', 'orange']

# 把列表的内容整体放进去
list1.append(list)
print(list1) # ['computer', 'tv', 'apple', 'pear', 'orange', ['apple', 'pear', 'orange']]

8. 修改操作

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

my_list=[1,3,5,7]

# 1.想要将下标为1的数据修改为22
my_list[1]=22
print(my_list) # [1, 22, 5, 7]
#修改最后一个位置的数据,改为' hello'
my_list[-1]='hello'
print(my_list) # [1, 22, 5, 'hello']

# 2,如果指定的下标不存在,会报错的
my_list[10]=10 #代码会报错

9. 删除操作

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

  1. 根据下标删除
    列表. pop(下标) 删除指定下标位置对应的数据
    1.下标不写,默认删除最后一个数据(常用)
    2.书写存在的下标,删除对应下标位置的数据
    返回:返回的删除的数据
  2. 根据数据值删除
    列表.remove (数据值) 根据数据值删除
    返回: None
    注意:如果要删除的数据不存在,会报错
  3. 清空数据(一般不用)
    列表.clear()
my_list=[1,3,5,7,9,2,4,6,8,0]

# 1.删除最后一个位置的数据
num = my_list.pop()
print(my_list,num) # [1, 3, 5, 7, 9, 2, 4, 6, 8]  0
# 2.删除下标为 1 的数据
my_list.pop(1)
print(my_list) # [1, 5, 7, 9, 2, 4, 6, 8]

# 3.删除数据为7的数据
my_list.remove(7) # 注意,如果列表中有多个7,只能删除第一个
print(my_list) # [1, 5, 9, 2, 4, 6, 8]
# 再次 删除数据为7的数据(报错)
my_list.remove(7)
print(my_list) # 报错

# 清空
my_list.clear()
print(my_list) # []

10.列表的反转(倒置)

字符串中反转倒置:字符串[::-1]
列表中反转和倒置:
1.列表[::-1] 使用切片的方法,会得到一个新列表,原列表不会发生改变
2.列表.reverse() 直接修改原列表,返回None

my_list=[1,3,5,7,9]

#使用切片的方法反转,会得到一个新列表
res = my_list[::-1]
print(my_list) # [1, 3, 5, 7, 9]
print(res) # [9, 7, 5, 3, 1]

#使用 reverse 方法,直接修改原列表
my_list.reverse()
print(my_list) # [9, 7, 5, 3, 1]

11.列表的复制

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

  1. 使用切片:变量=列表[:]
  2. 使用copy 方法:变量=列表.copy()
my_list=[1,3,5]

# 1. 切片
new_list = my_list[:]
print(my_list,new_list) # [1, 3, 5] [1, 3, 5] 
# 改其中一个列表内容不会影响另一个列表
my_list[0] = 'hello'
print(my_list,new_list) # ['hello', 3, 5]  [1, 3, 5]

# 2. copy()
newList = my_list.copy()
print(my_list,newList) # [1, 3, 5] [1, 3, 5] 
# 改其中一个列表内容不会影响另一个列表
my_list[-1] = 'other'
print(my_list,newList) # [1, 3, 'other'] [1, 3, 5]

# 3. 这是同一个列表,只是多了一个名字
newList1 = my_list
print(my_list,newList1) # [1, 3, 5] [1, 3, 5]
# 改其中一个列表内容会影响另一个列表
my_list[0] = 'momo'
print(my_list,newList1) # ['momo', 3, 5] ['momo', 3, 5]

12.列表的排序

列表的排序,一般来说都是对数字进行排序的:
列表. sort() 按照升序排序,从小到大
列表.sort( reverse=True ) 降序排序,从大到小

my_list=[3,7,5]

# 1. 升序排序
my_list.sort()
print(my_list) # [3, 5, 7]

# 2. 降序排序
my_list.sort(reverse=True)
print(my_list) # [7, 5, 3]

13.列表去重

列表去重:列表中存在多个数据,需求,去除列表中重复的数据.

  1. 方式1:
    遍历原列表中的数据判断在新列表中是否存在,如果存在,不管,如果不存在放
    入新的列表中
    遍历: for循环实现
    判断是否存在:可以使用in
    存入数据: append()
my_list = [1,3,3,1,2,2,3,5]

new_list = []
for i in my_list:
    if i not in new_list:
        new_list.append(i)

print(new_list) # [1,3,2,5]
  1. 方法2:
    在Python 中还有一种数据类型(容器) , 称为是集合(set)
    特点:集合中不能有重复的数据(如果有重复的数据会自动去重)
    可以使用集合的特点对列表去重
    1.使用set() 类型转换将列表转换为集合类型
    2.再使用list() 类型转换将集合转换为列表
    缺点:不能保证数据在原列表中出现的顺序(一般来说,也不考虑这件事)
my_list = [1,2,3,1,2,2,3,5]
list = list(set(my_list))
print(list)

3. 元组

元组: tuple, 元组的特点和列表非常相似
1.元组中可以存放任意类型的数据
2.元组中可以存放任意多个数据
区别:
1.元组中的数据内容不能改变。列表中的可以改变的
2.元组使用(),列表使用[]
应用:在函数的传参或者返回值中使用,保证数据不会被修改
定义
1.使用类实例化的方式
2.直接使用()方式

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

  1. 在元组中也可以使用下标和切片获取数据
  2. 在元组中存在 index 方法
  3. 在元组中存在 count 方法
  4. 在元组中可以使用 in 操作 以上方法的使用和列表中一样的
# 直接使用()定义
my_tuple4 = (1, "小王"3.14, False)
print(my_tup1e4)
# 特殊点,定义只有一个数据的元组时,数据后边必须有一个逗号
my_tuple5 = (1,)
print(my_tup1e5)

print(my_tup1e4[1]) # 小王

4. 字典

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

# 直接使用{}定义
my_dirt= {"name":"小明","age": 18,"height":1.71,"like":['跑步','看书']}

print(my_dirt)
print(len(my_dirt)) # 4

1. 增加和修改操作

语法: 字典[键] = 数据值
1.如果键已经存在,就是修改数据值
2.如果键不存在,就是添加数据(即添加键值对)

my_dirt= {"name":"小明","age": 18,"height":1.71,"like":['跑步','看书']}

print(my_dirt)
# 1.添加性别信息sex ,只能添加在最后面
my_dirt['sex'] = '男'
print(my_dirt)
# 2.修改年龄为19
my_dirt['age'] = 19
print(my_dirt)
# 3.添加一个爱好,学习-->本质是向列表中添加一个数据
my_dirt['like'].append('健身')
print(my_dirt)

2. 删除指定键值对

del 字典[键]
字典.pop(键) 键必须书写
清空: 字典.clear()

my_dirt= {"name":"小明","age": 18,"height":1.71,"like":['跑步','看书']}

# 1.删除身高信息
del my_dirt['height']
print(my_dirt)

my_dirt.pop('name')
print(my_dirt)

# 清空键值对
my_dirt.clear()
print(my_dirt)

3. 根据键获取对应的值

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

  • 使用 字典[键]
    1.如果键存在返回键对应的数据值,
    2.如果键不存在,会报错
  • 使用 字典.get(键,数据值)
    1.数据值一般不写,默认是None
    返回:
    1.如果键存在返回键对应的数据值
    2.如果键不存在,返回的是括号中书写的数据值(None)
    一般建议使用get 方法
my_dirt= {"name":"小明","age": 18,"height":1.71,"like":['跑步','看书']}

# 
print(my_dirt['age']) # 18
print(my_dirt.get('age')) # 18

print(my_dirt['gender']) # 报错
print(my_dirt.get('gender')) # None

4. 字典了遍历

  1. 对字典的键进行遍历
for 变量 in 字典:
	print(变量) # 变量就是字典的key,键
	
for 变量 in 字典.keys(): # 字典.keys()可以获取字典中所有的键
	print(变量)

my_dirt= {"name":"小明","age": 18,"height":1.71}
for k in my_dirt:
    print(k)

for k in my_dirt.keys():
    print(k)
  1. 对字典的值进行遍历
for 变量 in 字典.values(): # 字典.values()可以获取字典中所有的值
	print(变量)

my_dirt= {"name":"小明","age": 18,"height":1.71}
for v in my_dirt.values():
    print(v)
  1. 对字典的键值对进行遍历
#变量1就是键,变量2就是键对应的值
for 变量1,变量2 in 字典.items(): # 字典.items()获取键值对
	print(变量1,变量2)

my_dirt= {"name":"小明","age": 18,"height":1.71}
for k,v in my_dirt.items():
    print(k,v)

容器部分总结

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

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

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

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

六、函数

函数,就是把具有独立功能的代码块组织为一个小模块,在需要的时候调用,将多行代码写在一块,起个名字,在需要这多行代码的时候,可以直接使用这个名字来代替。
函数好处:减少代码的冗余(重复的代码不用多写),提高程序的编写效率

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

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

1. 函数基本使用

def say_hello():
    print('hello1')
    print('hello2')
    print('hello3')

# 调用
say_hello()
say_hello()

2. 函数传参

形参和实参的使用。

# num1和num2 是函数定义时候的参数,起到占位的作用,没有具体的数据值,称为形式参数,简称形参
def my_fun(num1,num2):
    num = num1 + num2 # 在什么时候定义参数,函数中使用的数据会会变化的时候,就可以定义为参数
    print(num)

# 在函数调用的时候,括号中的数据会传递给形参,是具体的数据值,称为实际参数,简称实参
my_fun(1,10) # 11
my_fun(200,200) # 400

3. 数据类型的改变

数据类型: int float bool str list tuple dict set
可变不可变是指:数据所在的内存是否允许修改,允许修改就是可变类型,不允许修改就是不可变类型(不使用=,变量引用的数据中的内容是否会变化,会变化是可变的,不会变化是不可变的)

可变类型:列表list,字典dict,集合set
不可变类型:int float bool str tuple

1.只有 =,可以改变引用
2.可变类型做参数,在函数内部,如果不使用=直接修改形参的引用,对形参进行的数据修改会同步到实参中

def func(list):
    list.append(10)

my_list = [1,6]
func(my_list)
print(my_list) # [1,6,10]


# list= my_list #此时两个变量的引用是相同的
def func1(list):
    list = [2,9] # list变量的引用发生了改变,my_list的引用没有改变,数据不会变

my_list = [1,6]
func1(my_list)
print(my_list) # [1,6]

4. 变量值的交换

重点掌握,Python 特有

a,b = b,a
print(a, b)

原理:组包和拆包
组包(pack):将多个数据值使用逗号连接,组成元组
拆包(unpack):将容器中的数据值使用多个变量分别保存的过程
注意:变量的个数和容器中数据的个数要保持一致

5. 局部变量和全局变量

  1. 局部变量
    局部变量:在函数内部(函数的缩进中)定义的变量,称为是局部变量
    特点:
    1.局部变量只能在当前函数内部使用,不能在其他函数和函数外部使用
    2.在不同函数中,可以定义名字相同的局部变量,两者之间没有影响
    3.生存周期(生命周期,作用范围)–>在哪能用
    在函数被调用的时候,局部变量被创建,函数调用结束,局部变量的值被销毁(删除),不能使用
    所以函数中的局部变量的值如果想要在函数外部使用, 需要使用return 关键字,将这个值进
    行返回
  2. 全局变量
    定义位置:在函数外部定义的变量,称为是全局变量
    特点:
    1.可以在任何函数中读取(获取)全局变量的值
    2.如何在函数中存在和全局变量名字相同的局部变量,在函数中使用的是局部变量的值(就近)
    3.在函数内部想要修改全局变量的引用,需要添加global 关键字,对变量进行声明为全局变量
    4.生命周期
    代码执行的时候被创建,代码执行结束,被销毁(删除)
g_num = 100
def func3():
	global g_num # 这个函数中使用的g_num 都是全局变量
	g_num = 30 #修改了全局变量
	print(f'func3中{g_num}')
func3()

6. 函数返回多个数据值

函数中想要返回一个数据值,使用return 关键字
将多个数据值组成容器进行返回,一般是元组(组包)

def num(n1,n2):
    num1 = n1 + n2
    num2 = n1 - n2
    return num1,num2
# 1.结果返回一个元组
res = num(20,10)
print(res,res[0],res[1]) # (30, 10) 30 10

# 2.拆包
a,b = num(30,10)
print(a,b) # 40 20

7. 函数的传参

def func(a,b,c):
    print(f'a:{a},b:{b},c:{c}')

# 位置传参
func(1,28,'l')
# 关键宇传参
func(a=1,c=20,b=9)
# 混合使用,关键字必须放在最后
func(1,'k',c=20)

缺省参数

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

def func(name,age='秘密'):
    print(f'name:{name},age:{age}')

func('mario')

不定长参数

当我们在书写函数的时候,不确定参数的具体个数时,可以使用不定长参数。

  • 不定长位置参数(不定长元组参数)
    1.书写,在普通参数的前边,加上一个*,这个参 数就变为不定长位置参数
    2.特点,这个形参可以接收任意多个位置传参的数据
    3.数据类型,形参的类型是元组
    4.注意,不定长位置参数要写在普通的参数的后面
    5.一般写法,不定长位置参数的名字为args, 即(*args )
  • 不定长关键字参数(不定长字典参数)
    1.书写,在普通参数的前边,加上两个*,这个参 数就变为不定长关键字参数
    2.特点,这个形参可以接收任意多个关键字传参的数据
    3.数据类型,形参的类型是字典
    4.注意,不定长关键字参数,要写在所有参数的最后边
    5.一般写法,不定长关键字参数的名字为kwargs, 即(**kwargs),
  • 完整的参数顺序
def 函数名(普通函数,*args, 缺省参数,**kwargs):
	pass
# 一般在使用的时候,使用1-2种,按照这个顺序挑选书写即可
def func(*args,**kwargs):
    print(args)
    print(kwargs)

func(1,2,3) # (1, 2, 3) {}
func(a=1,b=2,c=4) # () {'a': 1, 'b': 2, 'c': 4}
func(1,2,a=1,b=2) # (1, 2) {'a': 1, 'b': 2}

# 使用定义好的字典和列表中的数据,如何传参的问题
my_list = [1, 2, 3, 4]
my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
func(*my_list)
func(**my_dict)

func(my_list) # 报错

8. 匿名函数 lambda

匿名函数:就是使用lambda 关键字定义的函数
标准函数:一般称为使用def关键字定义的函数
匿名函数只能书写一行代码
匿名函数的返回值不需要return,一行代码(表达式)的结果就是返回值
语法:lambda 参数:一行代码
匿名函数一般不需要我们主动的调用,一般作为函数的参数使用的|

numa = lambda a,b:print(a+b)
numa(1,10) # 11

参数只是一个占位的作用,定义的时候没有具体的数据值,形参的值是在调用的时候进行传递,此时,形参才有数据值形参的类型就是由实参来决定的,在函数定义的时候,参数只是一个符号,写什么都可以,想让其是字典类型,只需要保证实参是字典即可

# 1.定义一个匿名函数可以求两个数的乘积()
func = lambda a,b: a*b
print(func(10,10)) # 100

# 2.定义一个匿名函数,参数为字典,返回字典中键为age的值
# 这里实参是字典即可
func1 = lambda x: x.get('age')
print(func1({'name':"aa",'age':19})) # 19

字典排序

列表的排序,默认是对列表中的数据进行比大小的,可以对数字类型和字符串进行比大小,但是对于字典来说,就不知道该怎么比大小,此时,我们需要使用sort 函数中的key这个参数,来指定字典比大小的方法,key这个参数,需要传递一个函数, 一般是匿名函数,字典的排序,其实要指定根据字典的什么键进行排序,我们只需要使用匿名函数返回字典的这个键对应的值即可
列表.sort(key=Lambda x: x[ '键'])

user_list = [{'name':'a','age':18},{'name':'b','age':13},{'name':'c','age':28}]
#根据年龄排序
user_list.sort( key=lambda x:x['age'] )
print(user_list) # 按年龄升序排

user_list.sort( key=lambda x:x['age'],reverse=True )
print(user_list) # 按年龄降序排

七、面向对象

步骤:

  1. 定义类,在定义类之前先设计类
    先定义简单的类,不包含属性,在python 中定义类需要使用关键字 class
    方法: 方法的本质是在类中定义的函数,只不过,第一个参数是self
class类名:
# 在缩进中书写的内容, 都是类中的代码
	def方法名(self): # 就是一个方法
		pass
  1. 创建对象,使用第一步定义的类创建对象
    创建对象是使用类名()进行创建,即
    类名() 创建一个对象,这个对象在后续不能使用
    创建的对象想要在后续的代码中继续使用,需要使用一个变量,将这 个对象保存起来
    变量=类名() 这个变量中保存的是对象的地址,一般可以成为这个变量为对象
    一个类可以创建多个对象,只要出现类名()就是创建一个对象,每个对象的地址是不一样的
  2. 通过对象调用方法
    对象.方法名()

self是一个形参,不需要手动传递实参值,python解释器会自动将调用该方法的对象作为实参值进行传递 self就是对象自己

1. 封装

  1. 添加属性:对象.属性名=属性值
    类内部添加:
    在内部方法中,self是对象,self.属性名=属性值
    在类中添加属性一般写作__init__方法中
    类外部添加:
    对象.属性名=属性值 一般不使用
  2. 获取属性:对象.属性名
    类内部:
    在内部方法中,self是对象,self.属性名
    类外部:
    对象.属性名 一般很少使用
# 定义类
class Cat:
    def eat(self):
        print(f'{self.name} 爱吃鱼,今年{self.age}岁')

# 创建对象
blue_cat = Cat()
# 添加属性
blue_cat.name = '小蓝猫'
blue_cat.age = 2
# 调用方法
blue_cat.eat()

black_cat = Cat()
black_cat.name = '小黑猫'
black_cat.age = 4
black_cat.eat()

1. 魔法方法

python中有一类方法,以两个下划线开头,两个下划线结尾,并且在满足某个条件的情况下,会自动调用,这类方法称为魔法方法
学习:
1.什么情况下自动调用
2.有什么用,用在哪
3.书写的注意事项

__init__方法
  1. 什么情况下自动调用
    创建对象之后会自动调用
  2. 有什么用,用在哪
    1.给对象添加属性的 (初始化方法,构造方法)
    2.某些代码,在每次创建对象之后,都要执行,就可以将这行代码写在init__ 方法
  3. 书写的注意事项
    1.不要写错了
    2.如果init方法中,存在出了self 之外的参数,在创建对象的时候必须传参
class Cat:
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
    def show_info(self):
        print(f'小猫名字是:{self.name},年龄是{self.age}')

# 创建对象
blue_cat = Cat('蓝猫',3)
blue_cat.show_info()
str
  1. 什么情况下自动调用
    使用print(对象)打印对象的时候会自动调用
  2. 有什么用,用在哪
    在这个方法中一般书写对象的属性信息的,即打印对象的时候想要查看什么信息,在这个方法中进行定义的
    如果类中没有定义__str__ 方法,print(对象), 默认输出对象的引用地址
  3. 书写的注意事项
    这个方法必须返回一个字符串
    def __init__(self,name,age):
        self.name = name
        self.age = age
    # def show_info(self):
    #     print(f'小猫名字是:{self.name},年龄是{self.age}')
    
    # 此方法必须返回一个字符串,只要是字符串就行
    def __str__(self):
        return f'小猫名字是:{self.name},年龄是{self.age}'

# 创建对象
blue_cat = Cat('蓝猫',3)
print(blue_cat)
del

init_方法, 创建对象之后,会自动调用(构造方法)
__del__ 方法,对象被删除销毁时,自动调用的(处理残留) (析构方法)

class Cat:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __del__(self):
        print(f'{self.name}被删除了')

# 创建对象
blue_cat = Cat('蓝猫',3)
print(blue_cat)

del blue_cat # 删除销毁对象
print('end')

2. 案例

# 1.小明体重 75.0公斤
# 2.小明每次跑步会减肥 0.5 公斤
# 3.小明每次吃东西体重增加 1公斤
class Person:
    def __init__(self,name,weight):
        self.name = name
        self.weight = weight

    def __str__(self):
        return f'姓名:{self.name},体重 {self.weight}kg'
    
    def run(self):
        print(f'{self.name}跑步5公里,体重减少了')
        self.weight -= 0.5
        
    def eat(self):
        print(f'{self.name}吃一顿美食,体重增加了')
        self.weight += 1

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

房子添加家具

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},家具名称列表:{self.item_list}'
    
    def add_item(self,item): # item 表示家具的对象
        if self.total_area > item.area:
            self.item_list.append(item.name)
            self.free_area -= item.area
            print(f'{item.name}添加成功')
        else:
            print('房子剩余面积不足')        


class HouseItem:
    def __init__(self,name,area):
        self.name = name
        self.area = area
        
    def __str__(self):
        return f'家具名{self.name},占地面积{self.area}'

# 创建家具类
bed = HouseItem('席梦思',4)
chest = HouseItem('衣柜',2)
table = HouseItem('餐桌',1.5)
print(bed)
print(chest)
print(table)

# 创建房子类
house = House('三室一厅',150)
print(house)
# 添加床
house.add_item(bed)
print(house)

3. 私有和公有权限

  1. 公有权限:
    直接书写的方法和属性,都是公有的
    公有的方法和属性,可以在任意地方访问和使用
  2. 私有权限
    在类内部,属性名或者方法名前边加上两个下划线,这个属性或者方法就变为私有
    私有的方法和属性,只能在当前类的内部使用
  3. 什么时候定义私有
    1.某个属性或者方法,不想在类外部被访问和使用,就将其定义为私有即可
    2.测试中,一般不怎么使用,直接公有即可
    3.开发中,会根据需求文档,确定什么作为私有
  4. 如果想要在类外部操作私有属性,方法是,在类内部定义共有的方法,我们通过这个方法去操作
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('小明',25)
print(xm)

#在类外部直接访问age属性
print(xm.__age) # 会报错,在类外部不能直接使用私有属性
#直接修改age属性
xm.__age = 20 # 这个不是修改私有属性,是添加了一个公有的属性__age
print(xm) # 姓名:小明,年龄 25岁

2. 继承

1.继承描述的是类与类之间的关系
2.继承的好处:减少代码的冗余(相同的代码不需要多次重复书写),可以直接使用!
语法:

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

术语:

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

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

class Animal:
    def eat(self):
        print('eat!!!')
class Dog(Animal):
    def wan(self):
        print('wang...')
class Quan(Dog):
    pass
    
dog = Dog()
dog.wan() # 调用自己类中方法
dog.eat() # 调用父类中的方法

x = Quan()
x.eat() # 可以调用父类的父类中的方法
x.wan() # 调用父类Dog类的方法

1. 重写

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

  1. 覆盖
    直接在子类中定义和父类中名字相同的方法
    直接在方法中书写新的代码
class Dog(Animal):
    def bark(self):
        print('wang...')
class Quan(Dog):
    # quan 类bark 方法不再是wang...,改为 aoaoao...
    def bark(self):
        print('aoaoao...')

x = Quan()
x.bark() 
  1. 扩展
    直接在子类中定义和父类中名字相同的方法
    在合适的地方调用父类中方法 super().方法()
    书写添加的新功能
class Dog:
    def bark(self):
        print('wang...')
        print('wang...')
        
class Quan(Dog):
    # quan 类bark 方法不再是wang...,
    # 改为 先aoaoao... 再wang...
    def bark(self):
        print('aoaoao...')
        # 调用父类中的代码
        super().bark()
        print('aoao~~~')

x = Quan()
x.bark() 

3. 多态

1.是一种写代码,调用的一-种技巧
2.同一个方法,传入不同的对象,执行得到不同的结果,这种现象称为是多态
3.多态可以增加代码的灵活度

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

4. 类方法和静态方法

  1. 实例方法
    在类中直接定义的方法就是实例方法

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

class Demo:
	def func(self):
#参数一般写作 self,表示的是实例对象
	pass
  1. 类方法(会用)
    在方法名字的上方书写@classmethod 装饰器(使用@classmethod 装饰的方法)

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

class Demo:
	@classmethod
	def func(cls): # 参数一般写作cls,表示的是类对象(即类名) class
		pass
  1. 静态方法(基本不用)
    在方法名字的上方书写@staticmethod 装饰器(使用@staticmethod装饰的方法)

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

class Demo:
	@staticmethod
	def func(): # 一般没有参数
		pass

例:

class Game:
    top_score = 0 # 类属性
    def __init__(self,name): # 实例方法
        self.name = name

    # 静态方法
    @staticmethod
    def show_help():
        print('这是游戏的帮助信息')

    # 类方法
    @classmethod
    def show_top_score(cls):
        print(f'游戏最高分为:{Game.top_score}')

5. 补充

哈希(hash) :是一个算法,可以对数据产生一 个唯一的值(指纹)
is可以用来判断两个对象是不是同一个对象,即两个对象的引|用是否相同
a is b == > id(a) == id(b)
面试中可能会问: is 和 ==的区别?
== 只判断数据值是否相同,is 判断引用是否相同

八、文件

计算机的文件,就是存储在某种长期储存设备上的一段数据
作用:将数据长期保存下来,在需要的时候使用
1.计算机只认识二进制(0 1)
2.文件中存储的数据都是以二进制(0 1)的形式去存储的
可以根据文件中的二进制内容,能否使用记事本软件将其转换为文字,将文件分为两种:文本文件和二进制文件:

  1. 文本文件
    能够使用记事本软件打开(能够使用记事本转换为文字)
    txt,md, py html, css, js,json
  2. 二进制文件
    不能使用记事本软件打开的
    exe, mp3,mp4, jpg, png

1. 文件的操作

  1. 打开文件
    打开文件:将文件从磁盘(硬盘)中读取到内存中
    语法:open(file,mode='r',,encoding-None)
    参数file:是要打开的文件,类型是字符串,文件的路径可以是相对路径,也可以是绝对路径(从根目录开始书写的路径) ,建议使用相对路径(相对于当前代码文件所在的路径,./ …/ )
    参数mode: 默认参数(缺省参数),表示的是打开文件的方式
    r:read 只读打开
    w:write 只写打开
    a:append 追加打开,在文件的末尾写入内容
    参数encoding: 编码方式,(文字和二进制如何进行转换的)
    gbk:将一个汉字转换为2个字节二进制
    utf-8: 常用,将一个汉字转换为3个字节的二进制
    返回值:返回的是文件对象,后续对文件的操作,都需要这个对象
  2. 读或者写文件
    写文件:
    向文件中写入指定的内容
    前提:文件的打开方式是w或者a
    文件对象. write(‘写入文件的内容’)
    返回值:写入文件的字符数,一般不关注
    读文件:
    将文件中的内容读取出来
    前提:文件的打开方式需要是r
  3. 关闭文件
    关闭文件:将文件占用的资源进行清理,同时会保存文件,文件关闭之后,这个文件对象就不能使用了
    文件对象. close()
# 1. 打开文件
f = open('a.txt','w',encoding='utf-8')

# 2. 写文件
f.write('hello python\n')
f.write('hello test')

# 3. 关闭文件
f.close()

1. 使用with open 打开文件(推荐)

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

with open(file, mode, encoding='utf-8') as 变量:
# 在缩进中去读取或者写入文件
# 缩进中的代码执行结束,出缩进之后,文件会自动关闭
# 1. 打开文件
with open('a.txt','a',encoding='utf-8') as f:
    f.write('\n我是追加内容~~')

# a方式打开文件,文件不存在会创建文件,文件存在,在文件的末尾写入内容

2. 按行读取文件内容

按行读取文件:一次读取一行内容
文件对象.readline()

# 读取所有文件
# 方法一
with open('a.txt',encoding='utf-8') as f:
    print(f.readline()) # 一行一行读取
    print(f.readline())

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

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

2. json文件的处理

json文件也是一个文本文件,就可以直接使用read() 和write()方法去操作文件,只是使用这两个方法,不方便,所以对json文件有自己独特的读取和写入的方法。
常用在在做测试的时候,将测试数据定义为json文件格式,使用代码读取json文件,即读取测试数据,进行传参(参数化)

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

1. 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

2. json 文件的书写

{
    "name":"mario",
    "age":22,
    "gender":"female",
    "like":["听歌","健身","跑步","看书"],
    "address":{
        "country":"中国",
        "city":"武汉"
    }
}

3. json 文件的读取

1.导包 import json
2.读打开文件
3.读文件:json.load(文件对象)
返回的是字典(文件中是对象)或者列表(文件中是数组)

import json

with open('info.json',encoding='utf-8') as f:
    res = json.load(f) # 读取文件
    # print(type(res)) # <class 'dict'>
    print(res)
    print(res['name'])
    print(res['address']['city'])

json读取多个文件:

# json文件
[
    {
        "name":"mario",
        "age":22,
        "gender":"female",
        "like":["听歌","健身","跑步","看书"],
        "address":{
            "country":"中国",
            "city":"武汉"
        }
    },
    {
        "name":"大鹏",
        "age":19,
        "gender":"male",
        "like":["健身","打游戏","看电影"],
        "address":{
            "country":"中国",
            "city":"广州"
        }
    }
]
import json

with open('info.json',encoding='utf-8') as f:
    res_list = json.load(f) # 读取文件
    for info in res_list:
        print(info['name'],info['age'],info['address']['city'])

案例

某网站的测试数据如下data.json, 需求,提取json文件中的用户名,密码和预期结果,
组成格式: [(),(),()] (自动化参数化需要的数据格式)

# json文件
[
    {
        "desc": "正确的用户名密码",
        "username": "admin",
        "password": "123456",
        "expect": "登录成功"
    },
    {
        "desc": "错误的用户名",
        "username": "root" ,
        "password": "123456",
        "expect": "登录失败"
    },
    {
        "desc": "错误的密码",
        "username": " admin",
        "password": "123123" ,
        "expect": "登录失败"
    }
]
import json

def read_data():
    with open('info.json',encoding='utf-8') as f:
        data = json.load(f)
        # print(data)
        new_list = []
        for i in data:
            # print((i['desc'],i['username'],i['password'],i['expect']))
            new_list.append((i['desc'],i['username'],i['password'],i['expect']))
        # print(new_list)
    return new_list

4. json 文件的写入

文件对象. write(字符串)不能直接将 Python的列表和字典作为参数传递
想要将Python 中的数据类型存为json 文件,需要使用json 提供的方法,不再使用write
步骤:
1.导包 import json
2.写(w)方式打开文件
3.写入json. dump(Python中的数据类型,文件对象)

import json

my_list = [('admin', '123456', '登录成功'), ('root', '123456', '登录失败'), ('admin', '123123', '登录失败')]
with open('info1.json','w',encoding='utf-8') as f :
    # 显示中文,不以ASCII码显示;缩进显示
    json.dump(my_list,f,ensure_ascii=False,indent=3)

九、异常

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

1. 异常的捕获(重点)

基本语法

try:
	书写可能发生异常的代码
except: # 任何类型的异常都能捕获
	发生了异常执行的代码
	
try:
	书写可能发生异常的代码
except 异常类型: # 只能捕获指定类型的异常,如果不是这个异常,还是会报错
	发生了异常执行的代码
try:
    num = input('请输入数字')
    num = int(num)
    print(num)
except:
    print('请输入正确的数字')

print('后续代码不会被阻断,继续执行...')

捕获多个指定类型的异常:

try:
    num = input('请输入数字')
    num = int(num)
    print(num)
    a = 100 / num # 100 / 0 ,除数不能为0
    print(f'a:{a}')
except ValueError:
    print('发生了异常,请输入正确的数字')
except ZeroDivisionError:
    print('除数不能为0')

2. 捕获异常的完整版本

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

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

常用写法:

try:
	可能发生异常的代码
except Exception as e:
	发生异常执行的代码

3. 异常的传递(了解)

异常传递是Python 中已经实现好了,我们不需要操作,我们知道异常会进行传递.
异常传递:在函数嵌套调用的过程中,被调用的函数,发生了异常,如果没有捕获,会将这个异常向外层传递,… 如果传到最外层还没有捕获,才报错

def func1():
    num = 10 / 0
    print(num)

def func2():
    func1()
    print(1111)

func2()

在这里插入图片描述

十、模块和包

模块和包一个用法。

1. 模块

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

方式一:

import 模块名
#使用模块中的内容
模块名.工具名

#举例
import random
import json
random.randint(a, b)
json.load()
json.dump()

方式二:

from 模块名 import 工具名
#使用
工具名 # 如果是函数和类需要加括号

#举例
from random import randint
from json import load, dump
randint(a, b)
load()
dump()

对于导入的模块和工具可以使用as关键字给其起别名
注意:如果起别名,原来的名字就不能用了只能使用别名

1. 模块的查找顺序

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

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

十一、unitTest 框架

概念:UnitTest是Python自带的一个单元测试框架,用它来做单元测试。
自带的框架:不需要单外安装,只要安装了Python, 就可以使用

第三方框架:想要使用需要先安装后使用( pytest):selenium,appium,requests
单元测试框架:主要用来做单元测试,一般单元测试是开发做的.
对于测试来说,unittest框架的作用是自动化脚本(用例代码)执行框架(使用unittest 框架来管理运行多个测试用例的)

为什么使用UnitTest框架?
1.能够组织多个用例去执行
2.提供丰富的断言方法(让程序代码代替人工自动的判断预期结果和实际结果是否相符)
3.能够生成测试报告

1. UnitTest核心要素(unitest的5大组成)

  1. TestCase(最核心的模块)
    TestCase (测试用例),注意这个测试用例是unittest 框架的组成部分,不是手工和自动化中我们所说的用例(Test Case)
    主要作用:每个TestCase(测试用例)都是一个代码文件,在这个代码 文件中来书写 真正的用例代码
  2. TestSuite
    TestSuite(测试套件),用来管理组装(打包)多个TestCase (测试用例)的
  3. TestRunner
    TestRunner(测试执行,测试运行),用来执行TestSuite(测试套件)
  4. TestLoader
    TestLoader(测试加载),功能是对TestSuite(测试套件)功能的补充,
    管理组装(打包)多个TestCase(测试用例)的
  5. Fixture
    Fixture(测试夹具),书写在TestCase( 测试用例)代码中,是一个代码结构,可以在每个方法执行前后都会执行的内容
    举例:
    登录的测试用例,每个用例中重复的代码就可以写在Fixture 代码结构中,只写一遍,但每次用例方法的执行,都会执行Fixture 中的代码
    1.打开浏览器
    2.输入网址

TestCase(测试用例)

1.是一个代码文件,在代码文件中来书写真正的用例代码
2.代码文件的名字必须按照标识符的规则来书写(可以将代码的作用在文件的开头使用注释说明)
步骤
1.导包(unittest)
2.自定义测试类
3.在测试类中书写测试方法
4.执行用例

# 1.导包
import unittest

# 2.自定义测试类,需要继承unittest 模块中的TestCase类即可
class TestDemo1(unittest.TestCase):
    # 3.书写测试方法,即用例代码。目前没有真正的用例代码,使用 print代替
    # 书写要求,测试方法必须以test_开头(本质是以test开头)
    def test_method1(self):
        print('这是测试1的代码')

    def test_method2(self):
        print('这是测试2的代码')

# 4,执行用例(方法)
# 4.1将光标放在类名的后边运行,会执行类中的所有的测试方法
# 4.2将光标放在方法名的后边运行,只执行当前的方法

TestSuite(测试套件) & TestRunner(测试执行)

TestSuite(测试套件):管理打包组装TestCase( 测试用例)文件的
TestRunner (测试执行):执行TestSuite(套件)
步骤
1.导包( unittest)
2.实例化(创建对象)套件对象
3.使用套件对象添加用例方法
4.实例化运行对象

TestSuite(测试套件):是用来管理多个TestCase(测试用例)的,
先创建多个TestCase( 测试用例)文件

# 1.导包
import unittest

from testDemo1 import TestDemo1
from testDemo2 import TestDemo2

# 2.实例化(创建对象)套件对象,
suit = unittest.TestSuite()

# 3.使用套件对象添加用例方法
# 方式一: 套件对象.addTest(测试类名('方法名')) 建议测试类名和方法名直接去复制,不要手写
suit.addTest(TestDemo1('test_method1'))
suit.addTest(TestDemo1('test_method2'))
suit.addTest(TestDemo2('test_method1'))
suit.addTest(TestDemo2('test_method2'))

# 4.实例化运行对象
runner = unittest.TextTestRunner()
# 5.使用运行对象去执行套件对象
# 运行对象.run (套件对象)
runner.run(suit)
# 1.导包
import unittest

from testDemo1 import TestDemo1
from testDemo2 import TestDemo2

# 2.实例化(创建对象)套件对象,
suit = unittest.TestSuite()

# 3.使用套件对象添加用例方法
# 方式二: 将一个测试类中的所有方法进行添加
# 套件对象.addTest(unittest.makeSuite(测试类名))
suit.addTest(unittest.makeSuite(TestDemo1))
suit.addTest(unittest.makeSuite(TestDemo2))

# 4.实例化运行对象
runner = unittest.TextTestRunner()
# 5.使用运行对象去执行套件对象
# 运行对象.run (套件对象)
runner.run(suit)

登录测试案例

源代码(不能修改):

def login(username,password):
    if username == 'admin' and password == '123456':
        return '登录成功'  
    else:
        return '登录失败'

测试用例:

import unittest
from testDemo1 import login

class TestLogin(unittest.TestCase):
    def test_log1(self):
        if login('admin','123456') == '登录成功':
            print('success!')
        else:
            print('Error!')
    
    def test_log2(self):
        if login('root','123456') == '登录失败':
            print('success!')
        else:
            print('Error!')
            
    def test_log3(self):
        if login('admin','123123') == '登录失败':
            print('success!')
        else:
            print('Error!')

套件和执行的代码:

import unittest
from testCase import TestLogin

suit = unittest.TestSuite()
suit.addTest(unittest.makeSuite(TestLogin))

runner = unittest.TextTestRunner()
runner.run(suit)

在这里插入图片描述

TestLoader(测试加载)

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

代码实现
在一个项目中TestCase( 测试用例)的代码,一般放在一个单独的目录(case)

# 1. 导包
import unittest

# 2.实例化加载对象并添加用例
# 2.1用例所在的路径,建议使用相对路径,用例的代码文件名可以使用*(任意多个任意字符)通配符
suit = unittest.TestLoader().discover('./case','test*.py')
# 2.2也可以使用默认的加载对象并加载用例
suit = unittest.defaultTestLoader.discover('case','test*.py')

# 3,实例化运行对象 
unittest.TextTestRunner().run(suit)  

Fixture(测试夹具)

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

  1. 方法级别[掌握]
    在每个测试方法(用例代码)执行前后都会自动调用的结构
#方法执行之前
def setUp(self):
	# 每个测试方法执行之前都会执行
	pass

测试方法...

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

方法级别 和 类级别的前后的方法,不需要同时出现,根据用例代码的需要自行的选择使用

  1. 模块级别[了解]
    模块:代码文件
    在每个代码文件执行前后执行的代码结构
#模块级别的需要写在类的外边直接定义函数即可
#代码文件之前
def setUpModule():
	pass
#代码文件之后
def tearDownModule( ):
	pass

登录案例

# 1. 导包
import unittest

class TestLogin(unittest.TestCase):
    # 每个测试方法执行之前都会先调用的方法
    def setUp(self):
        print('2.输入网址...')  
    # "每个测试方法执行之后都会调用的方法
    def teatDown(self):
        print('4.关闭当前网址页面...')  

    # 定义测试类之前调用的方法
    @classmethod
    def setUpClass(cls):
        print('1.打开浏览器')
    # 定义测试类之后调用的方法
    @classmethod
    def tearDownClass(cls):
        print('5.关闭浏览器')
    
    # 测试方法
    def test_1(self):
        print('3.输入正确用户名密码验证码,点击登录1')
    def test_2(self):
        print('3.输入错误用户名密码验证码,点击登录2')

在这里插入图片描述

2. 断言

让程序代替人工自动的判断预期结果和实际结果是否相符.
断言的结果有两种:
True, 用例通过
False,代码抛出异常,用例不通过
在unittest 中使用断言,都需要通过self.断言方法来试验

  1. assertEqual
    self.assertEqual(预期结果,实际结果) 判断预期结果和实际结果是否相等
    1.如果相等,用例通过
    2.如果不相等,用例不通过,抛出异常
  2. assertIn
    self.assertIn(预期结果,实际结果) 判断预期结果是否包含在实际结果中
    1.包含,用例通过
    2.不包含,用例不通过,抛出异常
assertIn('admin', 'admin') # 包含
assertIn('admin''adminnnnnnn') # 包含
assertIn('admin', 'aaaadminnnnn') # 包含
assertIn('admin', 'addddmin') # 不包含

登录案例

源代码:

def login(username,password):
    if username == 'admin' and password == '123456':
        return '登录成功'  
    else:
        return '登录失败'

断言测试:

import unittest
from testDemo1 import login

class TestLogin(unittest.TestCase):
    def test_log1(self):
        self.assertEqual('登录成功',login('admin','123456'))       
    
    def test_log2(self):
        self.assertEqual('登录失败',login('root','123456'))
            
    def test_log3(self):
        self.assertEqual('登录失败',login('admin','123123'))

	# assertIn:包含”失败“也可以
	def test_log3(self):
        self.assertIn('失败',login('admin','123123'))

error

3. 参数化

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

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

安装插件
unittest框架本身是不支持参数化,想要使用参数化,需要安装插件来完成
联网安装(在cmd 窗口安装或者)
pip install parameterized
pip是Python 中包(插件)的管理工具,使用这个工具下载安装插件

# 1. 导包
import unittest
from parameterized import parameterized
from testDemo1 import login

# 组织测试数据[(), (), ()] or [[], [], []]
data = [
    ('admin','123456', ' 登录成功'),
    ('root', '123456', '登录失败'),
    ('admin','123123', '登录失败')
]

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

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

实际数据放在单独的 json文件:

# 1. 导包
import unittest
import json
from parameterized import parameterized
from testDemo1 import login # 测试的源代码

# 组织测试数据[(), (), ()] or [[], [], []]
def build_data():
    with open('data.json',encoding='utf-8') as f:
        res = json.load(f)
        data = []
        for i in res:
            data.append(i['username'],i['password'],i['expect'])
        return data

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

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

4. 跳过

对于一些未完成的或者不满足测试条件的测试函数和测试类,不想执行,可以使用跳过使用方法,装饰器完成
代码书写在TestCase 文件

import unittest
#直接将测试函数标记成跳过
@unittest.skip( '跳过额原因' )
#根据条件判断测试函数是否跳过,判断条件成立,跳过
@unittest.skipIf(判断条件,' 跳过原因')
import unittest

verson = 3.0 # 版本号

class TestDemo(unittest.TestCase):
    @unittest.skip('此代码未完善,跳过测试!')
    def test1(self):
        print('测试方法1')

    @unittest.skipIf(verson >= 3.0,'版本号大于3.0不用测!')
    def test2(self):
        print('测试方法2')

5. 测试报告

自带的测试报告:
只有单独运行TestCase 的代码,才会生成测试报告
在这里插入图片描述

第三方测试报告 HTMLTestRunner

HTMLTestRunner是一个第三方的类库,用来执行测试用例并生成HTML格式的测试报告
网上有多种不同的实现版本,用法都类似,只是生成的HTML报告样式有差别
注意:下载的文件要与Python的版本兼容(有些版本只支持Python2.x)

# 1.获取第三方的测试运行类模块,将其放在代码的目录中
# 2.导包unittest
import unittest
from HTMLTestRunner import HTMLTestRunner

# 3.使用套件对象,加载对象去添加用例方法
suite = unittest.defaultTestLoader.discover('.','demo.py')

# 4.实例化第三方的运行对象并运行套件对象
# HTML TestRunner() 参数可选如下:
# stream=sys.stdout, 必填,测试报告的文件对象(open),注意点,要使用wb打开
# verbosity=1, 可选,报告的详细程度,默认1简略,2详细
# title=None,可选,测试报告的标题
# description=None 可选,描述信息,Python 的版本,pycharm 版本

# file = 'report.htmL' # 报告的后缀是 .htmL
file = 'report.html'
with open(file,'wb') as f:
    # runner = HTMLTestRunner(f) # 运行对象
    runner = HTMLTestRunner(f,2,'测试报告','python 3.6.6') # 运行对象
    # .运行对象执行套件,要写在with的缩进中
    runner.run(suite)

中文的报告:

import unittest
from HTMLTestRunnerCN import HTMLTestReportCN
#组装用例方法
suite = unittest . defaultTestLoader .discover('.', '*pa1.py') 
#实例化运行对象
with open( 'report_ cn.htm1''wb') as f:
runner = HTMLTestReportCN(f )
runner . run(suite)
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值