【python】python基础与unittest基础



Python编程

文章目录

  • Python编程
    • 前言
      • 1. 目标
    • 一、python基础
      • 1. Python 介绍
      • 2. 语言的分类
      • 3. `print`函数的简单使用
      • 4. 注释
      • 5. python代码中三种波浪线和PEP8
      • 6. 变量
      • 7. 数据类型
      • 8. 类型转换
      • 9. 输入:input()函数
      • 10. 输出:print()函数
      • 11. 运算符
    • 二、判断
      • 1. if 的基本结构
      • 2. if else 结构
      • 3. if elif else 结构
      • 4. if 嵌套
    • 三、循环
      • 1. while 循环
      • 2. 死循环和无限循环
      • 3. for 循环
      • 4. break 和 continue
    • 四、容器
      • 1.字符串
        • 语法:**字符串[下标]** # 获取指定位置的字符
        • 语法: **字符串[start: end :step]**
        • 字符串.find(sub_str, start, end)
        • 字符串.replace(old_str, new_str, count)
        • 字符串.split(sep, maxsplit)
        • 字符串.join(列表)
      • 2. 列表
        • 列表.index(数据, start, end)
        • 数据 in 容器
        • 列表.count(数据)
        • 列表.append(数据)
        • 列表.insert(下标, 数据)
        • 列表1.extend(列表2)
        • 列表[下标] = 数据
        • 列表.pop(下标)
        • 列表.remove(数据值)
        • 列表.clear()
        • 变量 = 列表[:]
        • 变量 = 列表.copy()
        • **列表.sort() ** 按照升序排序, 从⼩到⼤
        • **列表.sort(reverse=True) ** 降序排序, 从⼤到⼩
      • 3. 元组
      • 4. 字典
        • 字典[键] = 数据值
        • del 字典[键] or 字典.pop(键) 键必须书写
        • 字典.clear()
        • 字典[键]
        • 字典.get(键, 数据值)
      • 5. 容器部分总结
    • 五、函数基础
      • 1. 函数的概念
      • 2. 函数的定义
      • 3. 函数的调用
      • 4. ⽂档注释[了解]
      • 5. 函数的嵌套调用
      • 6. 函数的参数
      • 7. 函数的返回值
    • 六、变量进阶[理解 知道]
      • 1. 变量的引用[理解]
      • 2. 可变类型和不可变类型
      • 3. 面试题
      • 4. 拆包与组包
      • 5. 局部变量和全局变量
    • 七、函数进阶
      • 1. 返回值[函数返回多个数据值]
      • 2. 函数参数
      • 3. 多值参数[可变参数/不定长参数]
      • 4. Print 函数的解析
      • 5. 匿名函数
    • 八、面向对象
      • 1. 基本的介绍
      • 2. 类和对象
      • 3. 类的组成
      • 4. 类的抽象[类的设计]
      • 5. 面向代码的步骤
      • 6. 面向对象基本代码的书写
      • 7. self 的说明
      • 8. 对象的属性操作
        • 对象.属性名 = 属性值
        • self.属性名 = 属性值
        • 对象.属性名 = 属性值
        • 对象.属性名
        • self.属性名
        • 对象.属性名
      • 9.魔法方法
    • 九、文件操作
      • 1. 文件介绍
      • 2. 文件操作
        • open(file, mode='r', encoding=None)
        • ⽂件对象.write('写⼊⽂件的内容')
        • ⽂件对象.read(n)
        • ⽂件对象.close()
      • 3. 使⽤ with open 打开⽂件
      • 4. 按行读取文件内容
      • 5. json 文件的处理
    • 十、异常
      • 1.异常捕获[重点]
      • 2. 异常传递[了解]
    • 十一、模块和包
      • 1. 导入模块的语法
      • 2. 模块的查找顺序
      • 3. `__name__` 的作用
      • 4. 包(package)
    • 十二、UnitTest框架
      • 1. 介绍
      • 2. UnitTest的组成
      • 3. TestCase(测试用例)
      • 4. TestSuite & TestRunner
      • 5. TestLoader (测试加载)
      • 6. Fixture(测试夹具)
      • 7. 断言
        • self.assertEqual(预期结果, 实际结果) # 判断预期结果和实际结果是否相等
        • self.assertIn(预期结果, 实际结果) # 判断预期结果是否包含在实际结果中
      • 8. 参数化
      • 9. 跳过
      • 10. 测试报告

前言

1. 目标

  1. 学习掌握 python 的基本语法

  2. 在代码中遇到常见的错误,自己能够动手解决问题

    Python 只是⼀个编程语⾔,在⼯作中需要结合其他的⼯具使⽤
    Python + selenium web ⾃动化(功能测试转换为代码)
    Python + appium 移动端(⼿机端 APP)⾃动化
    Python + requests 接⼝
    

一、python基础

1. Python 介绍

作者: 吉多·范罗苏姆(Guido van Rossum) 龟叔;1989 年开始书写, 1991年诞生

  • 问什么学习 Python?

    1. 简单, 易学, 免费, 开源, 适用人群广泛
    2. 应用领域广泛(自动化测试)
  • Python 的版本

    1. Python2 (2.x 2.7)

    2. Python3(主流使用的版本, 3.6 之后的版本(即大于等于3.6))

2. 语言的分类

计算机只认识二进制(0 和 1)

编程语言是人和计算机沟通的语言

编程语言分类: 编译型语言, 解释型语言
执行效率:
机器语言>汇编语言>高级语言(编译型>解释器)
开发效率:
机器语言<汇编语言<高级语言(编译型<解释器)
跨平台性:
解释器语言跨平台性极强

【python】python基础与unittest基础_第1张图片

3. print函数的简单使用

print("hello world!")

print() 是 Python 中自带的函数,作用在控制台中输出括号中的内容;后续看到这个函数就是输出打印 数据的, 或者想要在控制台中显示某个内容,就要使用 print() 函数
print() 主要在学习阶段使用, 便于我们确认结果的正确性;在实际工作的代码中,基本不会使用 print,会使用其他的内容代替(日志模块)
print() 函数中是什么内容,就会显示什么内容, 里边的文字信息可以使用单引号,也可以使用双引号

4. 注释

  1. 注释是对代码解释说明的文字, 不会执行, 可以增加代码的可读性

  2. Python 中的注释分为两种, 单行注释和多行注释

  3. 单行注释

    使⽤ 井号空格进行注释(单独⼀个# 也可以)
    快捷键 : Ctrl(cmd) /
    	可以选中多行,使用快捷键
    	如果代码已经添加注释, 再次使用快捷键,会取消注释
    
  4. 多⾏注释

    多行注释中的内容 可以换行书写
    多行注释可以使用 3 对 双引号或者 3 对 单引号 , 被三对引号包括的内容就是注释的内容
    三对引号的注释,⼀般写在文件的最开始部分,或者文档注释处(函数)
    
    # 这是单行注释,代码不会执行
    # 以井号键开始的注释
    print("helloworld!!")
    
    """
    使用三对双引号包括起来的内容也是注释,
    可以换行,不会执行
    """
    '''
    使用三对单引号包括起来的内容也是注释,
    可以换行,不会执行
    '''
    print("end")
    

5. python代码中三种波浪线和PEP8

  1. 红色

    红色波浪线是代码的错误, 必须处理,代码才能执行
    	# 注意 :在后续课程中,某些代码没有写完,也会出现红色波浪线
    
  2. 灰色

    灰色波浪线, 不会影响代码的正常执行, 基本上所有的灰色波浪线都是 PEP8 造成的
    # PEP8: 是 Python 代码的书写规范, 如果不按照这个规范书写,会给灰色波浪线提示,建议代码的书写按照 PEP8 的规范书写
    	1. 可以书写代码的时候注意 PEP8 的代码规范
    	2. 可以在书写完成之后,使用快捷键 Ctrl  + Alt + L 来按照PEP8 的规范自动格式化代码
    
  3. 绿色

    绿色波浪线, 不影响代码的正常执行, 在引号中, 认为你书写的内容不是⼀个单词,就会给你绿色提示
    

6. 变量

  1. 作用

    用来存储数据的(在程序代码中出现的数据,想要保存下来使用, 就必须使用变量), 如: 测试数据, 用户名, 密码, 验证码
    变量注意事项: 变量必须先定义(保存数据)后使用(取出数据)

  2. 定义变量

    变量名 = 数据值 	#	理解为将数据值保存到变量中
    
    # 比如:name = '张三' 	  # 定义⼀个变量 name, 存储的数据值是 张三
    
  3. 使用变量

    变量定义之后, 想要是使用变量中的数据, 直接使用变量名即可
    # 使用变量获取数据, 打印
    print(name)
    
    # 定义⼀个变量,存储你的名字
    name = '张三'
    
    # 使用变量打印名字, 不需要加引号
    print(name)  # 张三
    
    # 如果给 name 添加引号, 添加引号之后,输出的就是引号中的内容
    print('name')  # name
    
  4. 变量的命名规范

    1. 必须由字母、数字和下划线组成, 并且不能以数字开头

    2. 不能使用 Python 中的关键字作为变量名

      # 关键字 :Python 自带的已经使用的标识符,具有特殊的作用
      
    3. 区分大小写

    4. 建议性的命名

      驼峰命名法
       	# 大驼峰: 每个单词的首字母大写MyName
       	# 小驼峰: 第⼀个单词的首字母小写,其余单词的首字母大写 myName
      
      下划线连接法
      	# Python 中的变量的定义使用的是下划线连接
      	# 每个单词之间使用下划线连接 my_name
      	
      见名知意
      	# name 姓名 age 年龄 height 身高
      

7. 数据类型

  1. 数据类型

    整型(int),就是整数,即不带小数点的数
    
    • 浮点型(float),就是小数

    • 布尔类型(bool),只有两个值真True , 1;假 False0, 非 0 即真

    • 复数类型 3 + 4i,不会用的

  1. 非数据类型

    • 字符串(str): 使用引号引起来的就是字符串

    • 列表(list) :[1, 2, 3, 4]

    • 元组(tuple): (1, 2, 4, 4)

    • 字典(dict) :{‘name’: ‘小明’, ‘age’: 18}

  2. type()函数

    # 可以获取变量的数据类型
    
    type(变量)
    print(type(变量))
    
    # 整型 
    age = 18
    print(type(age))  # type(age).print 回车
    # 浮点型 
    height = 1.71
    print(type(height))
    # 布尔类型  True False
    isMen = True
    print(type(isMen))
    # 字符串类型, 使用引号引起来的就是字符串 
    name = '小明'
    print(type(name))  # str
    
    num = '18'
    print(type(num))  # str
    
    num = 'True'
    print(type(num))  # str
    

8. 类型转换

根据代码的需要, 将⼀种数据类型转换另⼀种数据类型

语法:变量 = 要转换为的类型(原数据)
注意点: 数据类型转换,不会改变原来的数据的类型, 会生成⼀个新的数据类型

  1. int():将其他类型转换为int类型

    • float类型的数字转换为整型

    • 整数类型的字符串转换为整型

  2. float():将其他类型转换为浮点型

    • int类型转换为浮点型float(3) —> 3.0

    • **数字类型的字符串(整数类型和⼩数类型)**转换为浮点型

  3. str():将其他类型转换为字符串类型

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

9. 输入:input()函数

获取用户键盘输入的内容;使用函数input()

变量 = input(‘提示的信息’)

# 1. 代码从上到下执行, 遇到 input 函数之后,会暂停执行,等待用户的输⼊, 如果不输⼊会一直等待
# 2. 在输⼊的过程中,遇到回车,代表本次输⼊结束
# 3. 会将你输⼊的内容 保存到等号左边的变量中, 并且变量的数据类型 一定是 str
result = input('请输入内容:')
print(type(result), result)  # 打印数据类型和数据值

# 将input 输⼊得到的数字转换为整型
age = input('请输入你的年龄:')
print('age本来的类型', type(age))

# 类型转换
age1 = int(age)
print('转换后age的类型', type(age))
print('age1的类型', type(age1))

'''
请输入你的年龄:18
age本来的类型 
转换后age的类型 
age1的类型 
'''

10. 输出:print()函数

输出使用的函数是 print() 函数

作用:将程序中的数据或者结果打印到控制台(屏幕)

print('hello world')
name ='⼩明'
print(name)

age = 18
print(name, age)	# 可以使⽤逗号输出多个内容
  1. 格式化输出

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

    % 格式化输出占位符号

    • %d 占位,填充整型数据
    • %f 占位,填充浮点型数据
    • %s 占位,填充字符串数据
    # 定义变量 姓名 年龄 身高
    
    name = "小明"
    age = 18
    height = 1.71
    
    # 按照我的名字是xx,年龄是xx,身高是xx
    # 使用格式化输出实现
    print('我的名字是%s,年龄是%d,身高是%f m' % (name, age, height))
    
    # 小数默认显示6位,如果要指定显示小数点后几位,%.nf n表示小数点后保留几位位数
    print('我的名字是%s,年龄是%d,身高是%.2f m' % (name, age, height))  # 保留2位小数
    
    # 补充
    stu_num = 1
    # 我的学号是000001
    print('我的学号是%d' % stu_num)
    # %0nd n表示整数一共占几位
    print('我的学号是%06d' % stu_num)
    
    # 某次考试的及格率是90%
    num = 90
    # 格式化中显示%,书写时需要两个%%才可以
    print('某次考试的及格率是%d%%' % num)
    
  2. F-string(f字符串的格式化⽅法)

    f-string 格式化的⽅法,想要使⽤,Python 的版本 >= 3.6

    • 需要在字符串的前边加上 f"" 或者 F""

    • 占位符号统⼀变为 {}

    • 需要填充的变量写在 {} 中

# 定义变量 姓名 年龄 身高 学号 及格率
name = "小明"
age = 18
height = 1.71
stu_num = 1
num = 90

# 使用格式化输出实现
print(f'我的名字是{name},年龄是{age},身高是{height}m,学号是{stu_num},及格率{num}%')

# 一般没有这样的需求
print(f'我的名字是{name},年龄是{age},身高是{height:.3f}m,学号是{stu_num:06f},及格率{num}%')

# 在字符串中输出换行  \n (转移字符)
print(f'我的名字是{name},年龄是{age},身高是{height:.3f}m,学号是{stu_num:06f},\n及格率{num}%')
  1. 字符串格式化

    字符串.format()

    • 在需要使用变量的地方使用{}占位
    • ‘{},{},…’.format(变量,变量)
    # 定义变量 姓名 年龄 身高 学号 及格率
    name = "小明"
    age = 18
    height = 1.71
    stu_num = 1
    num = 90
    
    # 字符串.format()
    print('我的名字是{},年龄是{},身高是{}m,学号是{},及格率{}%'.format(name,age,height,stu_num,num))
    
    print('我的名字是{},年龄是{},身高是{:.3f}m,学号是{:06d},及格率{}%'.format(name,age,height,stu_num,num))
    

11. 运算符

  1. 算数运算符

    优先级: 先算谁,再算谁;不确定优先级,就使⽤ () () > ** > * / // % > + -

运算符 描述 实例(x =10 y = 20)
+ x + y = 30
- x - y = -10
* x * y = 200
/ x / y = 0.5 得到的是浮点类型数据
// 求商 x // y = 0 得到的是整数类型数据
% 求余 x % y = 10 得到的是整数类型数据
** 幂运算 2 ** 3 = 8
  1. 比较运算符

    ⽐较运算符得到都是 bool 类型

    # > 、< 、 >= 、<=
    	== 	判断两个数是否相等, 相等为 True, 不相等为 False
    	!= 	 判断两个数是否不相等, 不相等为 True, 相等为 False
    
  2. 逻辑运算符

    逻辑运算符可以连接多个条件,在判断和循环中使用

    and 逻辑与 和,并且 and 连接两个条件 , 都必须为 True , 整体结果才为 True , 即一假为假 (当第一个条件为False 的时候,第二个条件就不再判断)
    or 逻辑或 或者,or 连接的两个条件 , 只要有一个条件为 True , 整体结果就为 True , 即 一真为真 (当第一个条件为 True的时候,第二个条件就不再判断)
    not 逻辑非 取反 , not 后边的条件 , 如果本来是 True , 变为 False , 本来是 False , 变为 True
    
  3. 赋值运算符

    赋值运算符 =, 作用就是将等号右边的值保存到等号左边的变量中
    复合赋值运算符(将算术运算符和赋值运算符进行结合)
    += -= *= /= //= %=
    a += b ===> a = a + b
    
  4. 运算符优先级

    不需要刻意去记忆优先级,因为可以使用 () 改变优先级

二、判断

在日常生活中说的 如果… ,否则… 这就是判断,在程序代码中需要使用if(如果) elif(如果) else(否则) 三个关键字来实现

在代码中有判断语句,代码不会全部执行,有一部分不会执行

1. if 的基本结构

只有如果的情况,如果条件成立,会执行的代码

  1. 基本语法

    if 判断条件:
    	书写条件成立(为真),会执行的代码
    	书写条件成立(为真),会执行的代码
      
    # 1. if 是一个关键字, 和后续的判断条件之间需要一个空格
    # 2. 判断条件后边需要一个冒号,不要少了
    # 3. 冒号之后,回车,代码需要缩进, 在 pycharm 中会自动进行缩进, 一般是 4 个空格 或者 一个 tab键
    # 4. 所有在 if 代码下方的缩进中书写的代码,属于 if 语句的代码块, 判断条件为 True 的时候会执行
    # 5. if 代码块中的代码,要么都执行,要么都不执行
    # 6. if 代码块结束之后, 代码要顶格书写(不再有缩进), 表示是和 if 无关的代码
    
  2. 代码案例

    # 1. 使用 input 获取用户的年龄
    age = input('请输入你的年龄:')
    # 2. 判断年龄是否满足 18 岁
    if int(age) >= 18:  # 字符串和 int 类型不能比大小, 先类型转换,再比大小
        # 3. 如果年龄大于等于(满足)18 岁, 输出 '满 18 岁了,可以进入网吧为所欲为了'
        print('满 18 岁了,可以进入网吧为所欲为了')
    
    print('我和 if 判断没有关系,不管怎样,都会执行')
    

2. if else 结构

如果条件成立,做什么事;否则(条件不成立),做另一件事

  1. 基本语法

    if 判断条件:
      书写条件成立(为真),会执行的代码
      书写条件成立(为真),会执行的代码	
    else:
      书写条件不成立(为假),执行的代码
      书写条件不成立(为假),执行的代码
      
    # 1. else 是关键字, 后边需要冒号
    # 2. 冒号之后回车,同样需要缩进
    # 3. 处于 else 代码下方缩进中的内容,属于 else 的代码块
    # 4. if 和 else 的代码块, 只会执行其中的一个
    # 5. else 需要结合 if 使用
    # 6. if else 之间不能有其他顶格书写的内容(不提 elif)
    
  2. 代码案例

    # 1.使用 input 获取用户的年龄
    age = input('请输入你的年龄:')
    if int(age) >= 18:  # 字符串和 int 类型不能比大小, 先类型转换,再比大小
        # 3. 如果年龄大于等于(满足)18 岁, 输出 '满 18 岁了,可以进入网吧为所欲为了'
        print('满 18 岁了,可以进入网吧为所欲为了')
    # 4. 如果不满足, 输出 '不满 18 岁,回去写作业吧'
    else:
        print('不满 18 岁,回去写作业吧')
    
  3. if 和逻辑运算符结合使用

    案例一:

    #1. 获取用户输入的用户名和密码
    name = input('请输入用户名:')
    pwd = input('请输入密码:')
    # 2. 判断用户名是 admin 并且密码是 123456 时, 在控制台输出: 登录成功!
    if name == 'admin' and pwd == '123456':
        print('登录成功!')
    # 3. 否则在控制台输出: 登录信息错误!
    else:
        print('登录信息错误!')
    

    案例二:

    # 1. 获取用户输入的用户名
    name = input('请输入用户名:')
    # 2. 判断用户名是 admin 时, 在控制台输出: 欢迎 admin 登录!
    # 3. 用户名是 test 时, 在控制台输出: 欢迎 test 登录!
    if name == 'admin' or name== 'root':
        print(f'欢迎{name}')
    # 4. 如果是其他信息, 在控制台输出: 查无此人!
    else:
        print('查无此人!')
    

3. if elif else 结构

如果某个判断条件有多个时,建议使用if elif else 结构

  1. 基本语法

    if 判断条件1:
      判断条件1成立,执行的代码
    elif 判断条件2:
       判断条件2成立,执行的代码
    else:
      以上条件都不成立,执行的代码
      
    # 1. elif 也是关键字,后边和判断条件之间需要一个空格,判断条件之后需要冒号
    # 2. 冒号之后回车需要缩进, 处在这个缩进中的的代码表示是 elif 的代码块
    # 3. 在一个 if判断中,可以有很多个 elif
    # 4. 只有 if 的条件不成立,才会去判断 elif 的条件
    # 5. 在一个if 中, 如果有多个 elif , 只要有一个条件成立,后续的所有都不再判断
    # 6. if elif else 结构, 和 if 的缩进相同的只能是 elif 和 else,如果是其他的,就表示 这个判断结构结束了
    
    if 判断条件1:
      执行的代码
    if 判断条件2:
      执行的代码
    if 判断条件3:
      执行的代码
    # 多个 if 的结构, 每个 if 都会进行判断,之间没有关联系
    
  2. 代码案例

    elif 实现:

    # 1. 定义 score 变量记录考试分数
    score = int(input('请输入你的成绩:'))
    # 2. 如果分数是大于等于90分应该显示优
    if score >= 90:
        print('优')
    # 3. 如果分数是大于等于80分并且小于90分应该显示良
    elif score >= 80 and score <= 90:
        print('良')
    # 4. 如果分数是大于等于70分并且小于80分应该显示中
    elif score >= 70 and score <= 80:
        print('中')
    # 5. 如果分数是大于等于60分并且小于70分应该显示差
    elif score >= 60 and score <= 70:
        print('差')
    # 6. 其它分数显示不及格
    else:
        print('不及格')
    

    多个 if 实现:

    # 1. 定义 score 变量记录考试分数
    score = int(input('请输入你的成绩:'))
    # 2. 如果分数是大于等于90分应该显示优
    if score >= 90
        print('优')
    # 3. 如果分数是大于等于80分并且小于90分应该显示良
    if score >= 80 and score <= 90:
        print('良')
    # 4. 如果分数是大于等于70分并且小于80分应该显示中
    if score >= 70 and score <= 80:
        print('中')
    # 5. 如果分数是大于等于60分并且小于70分应该显示差
    if score >= 60 and score <= 70:
        print('差')
    # 6. 其它分数显示不及格
    if score < 60:
        print('不及格')
    

4. if 嵌套

if 嵌套, 是指在一个 if(elif else) 中嵌套另一个 if

使用场景: 判断条件存在递进关系(只有第一个条件满足了,才会判断第二个条件)

  1. 基本语法

    if 判断条件1:
      判断条件1成立,执行的代码
      if 判断条件2:
        判断条件2成立,执行的代码
      else:
          判断条件2不成立,执行的代码
    else:
      判断条件1不成立,执行的代码
    
  2. 代码案例

    案例一:

    # 取款机取钱的过程, 假定 你的密码是: 123456, 账户余额为 1000
    pwd = '123456'
    money = 1000
    # 1. 提示用户输入密码
    password = input('请输入密码:')
    # 2. 判断密码是否正确
    if password == pwd:
        print('密码正确,登录成功')
        # 3. 密码正确后,提示输入取款的金额
        get_money = int(input('请输入取款金额:'))
        # 4. 判断取款的金额和余额的关系
        if money >= get_money:
            print('取款成功')
        else:
            print('余额不足')
    else:
        print('密码错误,请重新尝试')
    

    案例二:

    # 假定某网站用户名固定为 'admin', 密码固定为'123456', 验证码 固定为 '8888'
    # 1. 获取用户输入的用户名,密码和验证码
    username = input('请输入用户名:')
    pwd = input('请输入密码:')
    code = input('请输入验证码:')
    # 2. 先判断验证码是否正确,如果正确打印输出验证码正确,再判断用户名和密码是否正确
    if code == '8888':
        print('验证码正确')
        if username == 'admin' and pwd == '123456':
            print('用户名与密码正确,登录成功')
        else:
            print('用户名或密码正确,请再次尝试')
    # 3. 如果验证吗不正确,直接输出 验证码不正确,请重新输入
    else:
        print('验证码不正确,请重新输入')
    
  3. 案例:猜拳游戏

    随机出拳

    # 案例中需要电脑随机出拳,即随机出 1 2 3
    # 在 Python 中想要随机获得整数数字可以使用如下方法
    # 1. 导入随机数工具包
    # import random
    # 2. 使用工具包中的工具产生指定范围内的数字
    # random.randint(a, b) # 产生[a, b] 之间的随机整数,包含 a b 的
    
    import random # 这行代码习惯性的放在第一行
    num = random.randint(1, 3)
    print(num)
    
    import random
    
    # 案例的步骤:
    # 1. 自己出拳(石头(1)/剪刀(2)/布(3)) input (player)
    player = int(input('请出拳(石头(1)/剪刀(2)/布(3)):'))
    # 2. 电脑随机出拳 (使用随机数模块(工具)完成) (computer)
    computer = random.randint(1, 3)
    # 3. 判断输赢
    # 3.1 玩家胜利
    if player == 1 and computer == 2 or player == 2 and computer == 3 or player == 3 and computer == 1:
        print('恭喜你获得胜利')
    # 3.2 平局 player == computer
    elif player == computer:
        print('平局')
    # 3.3 玩家输了 else
    else:
        print('输了,不要放弃,再来一局')
    

三、循环

程序开发中(写代码), 有三大流程(三大结构):

  1. 顺序, 代码从上到下,全部执行

  2. 分支, 判断语句,代码有选择性的执行

  3. 循环, 重复执行某一部分的代码

1. while 循环

循环的作用就是让指定的代码重复的执行

  1. 语法

    # 1. 设置循环的初始条件(计数器)
    # 2. 书写循环的判断条件
    
    while 判断条件:
      # 3. 需要重复执行的代码
      # 4. 改变循环的初始条件(计数器)
      
    # 1. while 是关键字
    
  2. 案例

    案例一:

    # 1.设置循环的初始条件 记录说了几遍 我错了
    i = 0
    # 2. 书写判断条件
    while i < 5:
        # 3.重复执行的代码
        print('我错了')
        # 4.改变初始条件
        i = i + 1
    

    案例二:1-100 之间数字的和

    # 1.定义变量保存求和结果
    num = 0
    # 2. 定义循环求1~100的数字和
    i = 0
    while i <= 100:
        num = num + i
        i = i + 1
    
    # 3. 打印结果
    print('求和的结果是:', num)
    

2. 死循环和无限循环

  • 死循环: 一般是由写代码的人不小心造成的 bug, 代码一直不停的运行下去
  • 无限循环: 写代码的人故意让代码无限制的去执行,代码一直不停的运行下去

无限循环的使用场景: 在书写循环的时候,不确定循环要执行多少次

无限循环的使用一般会在循环中添加一个 if 判断, 当 if 条件成立,使用关键字 break 来终止循环

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

while True:
  重复执行的代码 # 可以在 if 的上边
  if 判断条件:
    break # 关键字的作用就是终止循环, 当代码执行遇到 break,这个循环就不再执行了
    
重复执行的代码 # 可以在 if 的下边
import random

while True:
    # 案例的步骤
    # 1. 自己出拳(石头(1)/剪刀(2)/布(3)) input (player)
    player = int(input('请出拳(石头(1)/剪刀(2)/布(3))退出(0)/:'))
    if player == 0:
        break
    # 2. 电脑随机出拳 (使用随机数模块(工具)完成) (computer)
    computer = random.randint(1, 3)
    # 3. 判断输赢
    # 3.1 玩家胜利
    if player == 1 and computer == 2 or player == 2 and computer == 3 or player == 3 and computer == 1:
        print('恭喜你获得胜利')
    # 3.2 平局 player == computer
    elif player == computer:
        print('平局')
    # 3.3 玩家输了 else
    else:
        print('输了,不要放弃,再来一局')

3. for 循环

for循环也可以让指定的代码重复执行(循环)

for循环也可以遍历容器中的数据

  • 遍历: 从容器中把数据⼀个⼀个取出
  • 容器: 可以简单理解为盒⼦, 盒⼦中可以存放很多的数据(字符串 str, 列表 list, 元组 tuple, 字典 dict))

for 循环 也可以称为 for 遍历

  1. 基本的 for 循环语法

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

    案例:

    # 定义字符串
    my_str = 'hello'
    # 遍历字符串 字符串有5个字符,循环就会执行5次
    for i in my_str:  # 每次循环i的值为字符串的字符
        print('我错了', i)
    
  2. for 做指定次数的循环

    for 变量 in range(n):
      重复执⾏的代码
    #1.  range() 是 Python 中的函数, 作⽤使⽤可以⽣成[0, n) 之间的整数, 不包含 n 的 , ⼀个有 n 个数字, 所以这个循环循环 n 次
    #2.  想让 for 循环循环多少次,n 就写⼏
    #3.  变量的值 也是每次循环从 [0, n) 取出⼀个值, 第⼀次取得是 0 ,最后⼀次取得是 n-1
    

    range() 变形:

    # 需求: 使⽤ for 循环获取 5 到 10 之间的数字
    for 变量 in range(a, b):
      重复的代码
    # range(a, b) 作⽤是⽣成 [a, b) 之间的整数数字, 不包含 b
    

    案例:

    for i in range(5):  # [0,1,2,3,4]
        print(i)
    print('-' * 30)
    # 需求: 使⽤ for 循环获取 5 到 10 之间的数字
    for m in range(5, 11):
        print(m)
    

4. break 和 continue

  • break 和 continue 是 Python 中的两个关键字, 只能在循环中使⽤

  • break: 终⽌循环, 即代码执⾏遇到 break, 循环不再执⾏,⽴即结束

  • continue: 跳过本次循环,即代码执⾏遇到 continue,本次循环剩下的代码不再执⾏, 继续下⼀次循环

# continue
# 1.获取输入的字符串
result = input('请输入一个字符串:')
# 2.遍历打印字符串
for i in result:
    if i == 'e':
        continue  # 本次循环后续代码不执行,执行下一个循环
    print(i)
print('-' * 30)

四、容器

容器:也可以称为是数据序列, 或者⾼级数据类型, 也是Python 中的数据类型

容器中可以存放多个数据

1.字符串

字符串是容器, 因为字符串中可以包含多个字符

  1. 定义

    使⽤引号(单引号, 双引号, 三引号)引起来的内容就是字符串

    # 1.使用单引号定义
    my_str1 = 'hello'
    print(my_str1, type(my_str1))
    # 2.使用双引号定义
    my_str2 = "hello"
    print(my_str2, type(my_str2))
    # 3.使用三引号定义
    my_str3 = '''hello'''
    print(my_str3, type(my_str3))
    my_str4 = """hello"""
    print(my_str4, type(my_str4))
    # 4.字符串本身包含引号
    # 4.1 字符串本身包含单引号,定义时不能使用单引号
    # 4.2 字符串本身包含双引号,定义时不能使用双引号
    my_str5 = "I'm 小明"
    print(my_str5)
    # 5. 字符串本身包含单引号,定义时使用单引号
    # 5.1 使用 \ 转义字符,将字符串本身的单引号进行转义
    my_str6 = 'I\'m 小明'
    print(my_str6)
    # 5.2 字符串I\'m 小明  \\ --> \
    my_str7 = 'I\\\'m 小明'
    print(my_str7)
    # 5.3 字符串前加 r""  原生字符串中的\ 不会作为转义字符,文件操作时会用
    my_str8 = r'I\\\'m 小明'
    print(my_str8)
    
  2. 下标

    下标(索引):就是指字符在字符串中的位置编号, 这个编号就是下标

    这个编号⼀般来说都是从左到右进⾏编号的, 从 0 开始的(Python 中⽀持负数下标,从右到左进⾏编号的, 从-1 开始)
    下标作⽤: 可以使⽤下标获取字符串中某个位置的字符

    语法:字符串[下标] # 获取指定位置的字符
    正数下标 0 1 2 3 4 5 6
    字符串 a b c d e f g
    负数下标 -7 -6 -5 -4 -3 -2 -1
    str1 = 'abcdefg'
    
    # 打印字符串最开始位置的字符
    print(str1[0])  # a
    
    # 打印字符串最后位置的字符
    print(str1[-1])  # g
    
    # 打印字符串倒数第二位的字符
    print(str1[-2])  # f
    
    # 打印下标位2 的字符
    print(str1[2])  # c
    
    # 获取字符串的长度(字符的个数)
    # len(字符串)
    num = len(str1)
    print(num)
    print(str1[num - 1])  # g
    print(str1[len(str1) - 1])  # g
    
  3. 切片

    切⽚: 可以获取字符串中多个字符(多个字符的下标是有规律的,等差数列)

    语法: 字符串[start: end :step]
    • start 是开始位置的下标
    • end 是结束位置的下标(注意,不能取到这个位置的字符)
    • step 步⻓,等差数列的差值, 所取的相邻字符下标之间的差值,默认是 1, 可以不写
    # 切片会得到一个字符串,即可以获取字符串中的多个字符串
    str1 = 'abcdefg'
    # 1.获取abc字符
    print(str1[0:3:1])  # abc
    # 1.1 步长位 1 ,可以不写
    print(str1[0:3])  # abc
    # 1.2 开始位置为 0 ,可以不写,但是冒号必须写
    print(str1[:3])  # abc
    
    # 2. 获取efg字符
    print(str1[4:7])  # efg
    print(str1[-3:7])  # efg
    # 2.1 如果最后一个字符也要取,可以不写,但是冒号必须写
    print(str1[4:])  # efg
    # 2.2 如果开始和结束都不写,获取全部内容
    print(str1[:])  # abcdefg
    
    # 3. 获取aceg
    print(str1[0:7:2])  # aceg
    print(str1[::2])  # aceg
    
    # 4.特殊应用 步长位负数,开始和结束不写,意思全变,一般不用管,只有一种使用场景
    # 反转(逆置)
    print(str1[::-1])  # gfedcba 
    
  4. 字符串查找方法 find

    字符串.find(sub_str, start, end)

    作⽤: 在字符串中查找是否存在 sub_str 这样的字符串

    • sub_str: 要查找的⼩的字符串

    • start: 开始位置, 从哪个下标位置开始查找, ⼀般不写,默认是 0

    • end: 结束位置, 查找到哪个下标结束, ⼀般不写,默认是len()

    • 返回:(代码执⾏之后会得到什么, 如果有返回,就可以使⽤变量保存)

       #1. 如果在字符串中找到了 sub_str , 返回 sub_str第⼀次出现的正数下标(sub_str 中第⼀个字符在⼤字符串中的下标)
      #2. 如果没有找到,返回 -1
      
    str1 = "and itcast and itheima and Python"
    
    # 在字符串中查找and
    num = str1.find('and')
    print(num)  # 0
    
    # 在字符串中查找第二个and 第二个 and 出现的下标, 从第一次出现的后位一开始找
    num1 = str1.find('and', num + 1)
    print(num1)  # 11
    
    # 在字符串中查找第三个and 第三个 and 出现的下标, 从第二次出现的后位一开始找
    num2 = str1.find('and', num1 + 1)
    print(num2)  # 23
    
    # 在字符串中查找第4个and 第4个 and 出现的下标, 从第3次出现的后位一开始找
    num3 = str1.find('and', num2 + 1)
    print(num3)  # -1
    
  5. 字符串替换方法 replace

    字符串.replace(old_str, new_str, count)

    作⽤: 将字符串中old_str 替换为 new_str

    • old_str: 被替换的内容
  • new_str: 替换为的内容

    • count: 替换的次数, ⼀般不写,默认是全部替换
    • 返回: 替换之后的完整的字符串, 注意: 原来的字符串没有发⽣改变
    sr1 = 'good good study'
    
    # 1.将str1中所有的g 改为G
    str2 = str1.replace('g', 'G')
    print('str1:', str1)  # str1: good good study
    print('str2:', str2)  # str2: Good Good study
    
    # 2.将str1 第一个good 改为GOOD
    str3 = str1.replace('good', 'GOOD', 1)
    print('str3', str3)  # str3 GOOD good study
    
    # 3.将str1 第二个good 改为GOOD
    # 3.1 先将全部的 good --> GOOD
    str4 = str1.replace('good', "GOOD")
    # 3.2 再将第⼀个 GOOD --> good
    str4 = str4.replace('GOOD', 'good', 1)
    print('str4:', str4)  # str4: good GOOD study
    
  1. 字符串的拆分 split

    字符串.split(sep, maxsplit)

    作⽤:将字符串按照 sep 进⾏分割(拆分)

    • sep: 字符串按照什么进⾏拆分, 默认是空⽩字符(空格, 换⾏\n, tab键\t)

    • max_split: 分割次数,⼀般不写, 全部分割

  • 返回: 将⼀个字符串拆分为多个,存到列表中

    • 注意: 如果 sep 不写, 想要指定分割次数 则需要按照如下⽅式使⽤字符串.split(maxsplit=n)n次数
    str1 = "hello world and itcast and itheima and Python"
    
    # 1.将str1 按照and 字符进行拆分
    str2 = str1.split('and')
    print(str2)  # ['hello world ', ' itcast ', ' itheima ', ' Python']
    
    # 2.将str1 按照and 字符进行拆分一次
    str3 = str1.split('and', 1)
    print(str3)  # ['hello world ', ' itcast and itheima and Python']
    
    # 3.按照空白字符进行拆分
    str4 = str1.split()
    print(str4)  # ['hello', 'world', 'and', 'itcast', 'and', 'itheima', 'and', 'Python']
    
    # 4.按照空白字符进行拆分一次
    str5 = str1.split(maxsplit=1)
    print(str5)  # ['hello', 'world and itcast and itheima and Python'] 
    
  1. 字符串的链接 join

    字符串.join(列表)

    作⽤: 将字符串插⼊到列表中每相邻的两个数据之间, 组成⼀个新的字符串

    • 列表中的数据使⽤ 逗号 隔开的
      • 注意点: 列表中的数据必须都是字符串, 否则会报错
      • 括号中的内容主要是列表,可以是其他容器
    list1 = ['good', 'good', 'study']
    # 1.将列表中的字符串使用空格连接起来
    str1 = ' '.join(list1)
    print(str1)  # good good study
    # 2.将列表中的字符串使用and连接起来
    str2 = ' and '.join(list1)
    print(str2)  # good and good and study
    

2. 列表

列表 list, 是使⽤最多的⼀种容器(数据类型)

列表中可以存储多个数据, 每个数据之间使⽤逗号隔开

列表中可以存放任意类型的数据

  1. 定义

    # 1.类实例化的方式(不常用)
    # 1.1 定义空列表
    # 变量=list()
    list1 = list()
    print(list1, type(list1))  # [] 
    # 1.2 类型转换 list(容器) 将其他容器转换为列表
    # 转换字符串会将字符串中的每个字符作为一个数据存入列表中
    list2 = list('hello')
    print(list2, type(list2))  # ['h', 'e', 'l', 'l', 'o'] 
    
    # 2.直接使用[]定义(常用)
    # 2.1 定义空列表
    my_list = []
    print(my_list)  # []
    # 2.2 定义非空列表
    my_list1 = [1, '小明', 3.14, False]
    print(my_list1)  # [1, '小明', 3.14, False]
    
  2. 下标和切片

    列表⽀持下标和切⽚操作, 使⽤⽅法和字符串中的使⽤⽅法⼀致
    区别: 列表的切⽚得到的是列表

    list1 = ['小明', 18, 1.71, True]
    
    # 获取第一个数据,名字
    print(list1[0])  # 小明
    
    # 获取最后一个数据,名字
    print(list1[-1])  # True
    
    # 获取第一第二个数据
    print(list1[0:2])  # ['小明', 18]
    
    # 列表支持len()求数据元素的个数
    print(len(list1))  # 4
    
  3. 查找

    1. 查找:列表中数据下标的方法

      在字符串中使⽤的 find ⽅法查找下标的,不存在返回的是 -1
      在列表中没有 find ⽅法, 想要查找数据的下标,使⽤的 index() ⽅法

      列表.index(数据, start, end)

      使⽤和 find ⽅法⼀样, 同时在字符串中也有 index ⽅法

      区别: 返回, index() ⽅法,找到返回第⼀次出现的下标, 没有找到代码直接报错

    2. 查找:判断是否存在

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

      数据 in 容器
    3. 查找:统计出现的次数

      统计出现的次数,使⽤的是 count() ⽅法;返回 数据出现的次数

      列表.count(数据)
    my_list = [1, 3, 5, 7, 2, 3]
    
    # 查找数据3出现的下标
    print(my_list.index(3))  # 1
    
    # 查找数据4出现的下标
    # print(my_str.index(4))# ValueError: 4 is not in list
    
    if 4 in my_list:
        print(my_list.index(4))
    else:
        print('不存在数据 4')
    
    if my_list.count(4) > 0:  # 统计4出现的次数
        print(my_list.index(4))
    else:
        print('不存在数据 4')
    
  4. 添加

    1. 尾部添加(最常⽤)

      列表.append(数据)

      将数据添加到列表的尾部

      返回: 返回的 None(关键字,空), ⼀般就不再使⽤ 变量 来保存返回的内容;想要查看添加后的列表,需要打印的是列表

    2. 指定下标位置添加

      列表.insert(下标, 数据)

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

    3. 列表合并

      列表1.extend(列表2)

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

    my_list = []
    print(my_list)  # []
    
    # 1. 向列表中添加一个数据 郭德纲
    my_list.append('郭德纲')
    print(my_list)  # ['郭德纲']
    
    # 2. 向列表中添加一个数据 郭麒麟
    my_list.append('郭麒麟')
    print(my_list)  # ['郭德纲', '郭麒麟']
    
    # 3.在下标位置为 1 的位置添加数据 岳岳
    my_list.insert(1, '岳岳')
    print(my_list)  # ['郭德纲', '岳岳', '郭麒麟']
    
    # 4. 在下标位置为 1 的位置添加数据 于谦
    my_list.insert(1, '于谦')
    print(my_list)  # ['郭德纲', '于谦', '岳岳', '郭麒麟']
    
    # 5. 定义一个新的列表
    list1 = ['孙越', '烧饼']
    # 将 list1 中数据逐个添加到 my_list 中
    my_list.extend(list1)
    print(my_list)  # ['郭德纲', '于谦', '岳岳', '郭麒麟', '孙越', '烧饼']
    # 将 list1 作为⼀个整体添加到 my_list
    my_list.append(list1)
    print(my_list)  # ['郭德纲', '于谦', '岳岳', '郭麒麟', '孙越', '烧饼', ['孙越', '烧饼']]
    
  5. 修改

    修改列中的指定下标位置的数据

    列表[下标] = 数据

    字符串中字符不能使⽤下标修改

    # 定义列表
    my_list = [1, 3, 5, 7]
    
    # 1. 想要将下标为 1 的数据修改为 22
    my_list[1] = 22
    print(my_list)
    
    # 修改最后⼀个位置的数据, 改为 'hello'
    my_list[-1] = 'hello'
    print(my_list)
    
    # 2. 如果指定的下标不存在, 会报错的
    # my_list[10] = 10 # 代码会报错
    
  6. 删除

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

    1. 根据下标删除

      列表.pop(下标)

      删除指定下标位置对应的数据

      • 下标不写,默认删除最后⼀个数据(常⽤)
      • 书写存在的下标, 删除对应下标位置的数据
      • 返回: 返回的删除的数据
    2. 根据数据值删除

      列表.remove(数据值)
      • 根据数据值删除

      • 返回: None

      • 注意: 如果要删除的数据不存在, 会报错

    3. 清空数据(⼀般不⽤)

      列表.clear()
    my_list = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
    
    # 1. 删除最后⼀个位置的数据
    print(my_list.pop())  # 0
    print(my_list)  # [1, 3, 5, 7, 9, 2, 4, 6, 8]
    
    # 2. 删除下标位1 位置的数据
    print(my_list.pop(1))  # 3
    print(my_list)  # [1, 5, 7, 9, 2, 4, 6, 8]
    
    # 3. 删除数据位7 的数据
    print(my_list.remove(7))  # None # 注意, 如果列表中有多个 7, 只能删除第⼀个, 如果数据不存在,会报错的
    print(my_list)  # [1, 5, 9, 2, 4, 6, 8]
    
    # 4.清空
    print(my_list.clear())  # None
    print(my_list)  # []
    
  7. 反转(倒置)

    字符串中 反转倒置:字符串[::-1]
    列表中反转和倒置:
    1. 列表[::-1]
    	# 使⽤切⽚的⽅法,会得到⼀个新列表, 原列表不会发⽣改变
    2. 列表.reverse()
    	# 直接修改原列表, 返回 None
    
    my_list = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
    
    # 使用切片的方法反转,会得到一个新列表
    list1 = my_list[::-1]
    print(list1)  # [0, 8, 6, 4, 2, 9, 7, 5, 3, 1]
    print(my_list)  # [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
    
    # 使用reverse方法,直接修改原列表
    my_list.reverse()
    print(my_list)  # [0, 8, 6, 4, 2, 9, 7, 5, 3, 1]
    
  8. 复制

    将列表中的数据复制⼀份,给到⼀个新的列表

    使⽤场景: 有⼀个列表, 需要修改操作列表中的数据, 修改之后, 需要和原数据进⾏对⽐,即原数据不能改

    1. 使⽤切⽚
    变量 = 列表[:]
    1. 使⽤ copy ⽅法
    变量 = 列表.copy()
    my_list = [1, 2, 3]
    
    my_list1 = my_list[:]
    print('my_list1', my_list1)
    print('my_list:', my_list)
    my_list1[1] = 22
    print('my_list :', my_list)
    print('my_list1:', my_list1)
    print('-' * 30)
    
    my_list2 = my_list.copy()
    print('my_list :', my_list)
    print('my_list2:', my_list2)
    my_list2[2] = 33
    print('my_list :', my_list)
    print('my_list2:', my_list2)
    print('-' * 30)
    
    my_list3 = my_list  # 这是同⼀个列表,多了⼀个名字, 引⽤
    print('my_list :', my_list)
    print('my_list3:', my_list3)
    my_list3[0] = 11
    print('my_list :', my_list)
    print('my_list3:', my_list3)
    
  9. 排序

    列表的排序, ⼀般来说都是对数字进⾏排序的

    **列表.sort() ** 按照升序排序, 从⼩到⼤
    **列表.sort(reverse=True) ** 降序排序, 从⼤到⼩
    my_list = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
    # 升序排序
    my_list.sort()
    print(my_list)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    
    # 降序排序
    my_list.sort(reverse=True)
    print(my_list)  # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
    
  10. 列表嵌套

    列表嵌套,列表中的内容还是列表;使⽤下标来确定获取的是什么类型的数据,然后确定可以继续进⾏什么操作

    person_info = [["张三", "18", "功能测试"], ["李四", "20", "⾃动化测试"]]
    
    print(len(person_info))  # 2
    print(person_info[0])  # ['张三', '18', '功能测试']
    print(person_info[0][0])  # 张三
    print(person_info[0][0][0])  # 张
    
    # 将 18 改为 19
    person_info[0][1] = "19"
    print(person_info)  # [['张三', '19', '功能测试'], ['李四', '20', '⾃动化测试']]
    
    # 给李四添加一个性别信息
    person_info[1].append("男")
    print(person_info)  # [['张三', '19', '功能测试'], ['李四', '20', '⾃动化测试', '男']]
    
    # 删除张三的年龄信息
    # person_info[0].pop(1)
    person_info[0].remove('19')
    print(person_info)  # [['张三', '功能测试'], ['李四', '20', '⾃动化测试', '男']]
    
  11. 列表去重

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

    ⽅式1.思路
    遍历原列表中的数据判断在新列表中是否存在,如果存在,不管;如果不存在放⼊新的列表中
    遍历: for 循环实现
    判断是否存在:可以 使⽤ in
    存⼊数据: append()
    ⽅法 2:
    在 Python 中还有⼀种数据类型(容器) ,称为是 集合(set)
    特点: 集合中不能有重复的数据(如果有重复的数据会⾃动去重)可以使⽤集合的特点对列表去重
    1. 使⽤ set() 类型转换将列表转换为 集合类型
    2. 再使⽤ list() 类型转换将集合 转换为列表
    
    缺点: 不能保证数据在原列表中出现的顺序(⼀般来说,也不考虑这件事)
    
    
    my_list = [3, 2, 4, 1, 2, 3, 3, 2, 1, 2, 3, 1]
    # print(set(my_list))
    # new_list = list(set(my_list))
    # print(new_list)
    new_list = []
    for i in my_list:
        if i in new_list:
            pass
        else:
            new_list.append(i)
    print(new_list)
    

3. 元组

元组: tuple, 元组的特点和列表⾮常相似

应用:在函数的传参或者返回值中使⽤, 保证数据不会被修改

  • 元组中可以存放任意类型的数据

  • 元组中可以存放任意多个数据

    区别:

  • 元组中的数据内容不能改变, 列表中的可以改变的

  • 元组使⽤ (), 列表 使⽤ []

  1. 定义

    1. 使⽤ 类实例化的⽅式
    2. 直接使⽤ () ⽅式
  2. 常用方法

    由于元组中的数据不能修改,所以只有查看的⽅法(以下⽅法的使⽤ 和列表中⼀样的)

    1. 在元组中也可以使⽤ 下标和切⽚获取数据
    2. 在元组中存在 index ⽅法, 查找下标, 如果不存在,会报错
    3. 在元组中存在 count ⽅法, 统计数据出现的次数
    4. 在元组中可以使⽤ in 操作, 判断数据是否存在
    5. len() 统计个数
    # 1. 使⽤ 类实例化的⽅式
    # 1.1 定义空元组(不会使用)
    my_tuple1 = tuple()
    print(type(my_tuple1), my_tuple1)  #  ()
    # 1.2 类型转换,将列表转换为元组,只需要将 [], 变为 (), 同时 可以将元组转换列表 , 将() 变为 []
    
    my_tuple2 = tuple([1, 2, 3])
    print(my_tuple2)  # (1, 2, 3)
    # 转换字符串, 和列表中⼀样
    my_tuple3 = tuple("hello")
    print(my_tuple3)  # ('h', 'e', 'l', 'l', 'o')
    
    # 2. 直接使⽤ () ⽅式
    my_tuple4 = (1, "⼩王", 3.14, False)
    print(my_tuple4)
    
    #  3. 特殊点, 定义只有⼀个数据的元组时, 数据后边必须有⼀个逗号
    my_tuple5 = (1,)
    print(my_tuple5)  # (1,)
    print(my_tuple4[1])  # ⼩王
    

4. 字典

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

    # 1.使用类实例化的方法
    my_dict = dict()
    print(type(my_dict), my_dict)  #  {}
    
    # dict() 不能转列表、元组和字符串
    
    # 2. 直接使用{}定义
    # 2.1 定义空字典
    my_dict1 = {}
    print(type(my_dict1), my_dict1)
    # 2.2 ⾮空字典, ⼩明('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))  # 5
    
  2. 增加和修改

    字典[键] = 数据值
    • 如果键已经存在,就是修改数据值

    • 如果键不存在,就是添加数据(即添加键值对)

    # 定义字典⼩明 18 爱好
    my_dict = {"name": "⼩明", "age": 18, "like": ['抽烟', '喝酒', '烫头']}
    print(my_dict)
    
    # 1. 添加性别信息 sex
    my_dict["sex"] = "男"
    print(my_dict)  # {'name': '⼩明', 'age': 18, 'like': ['抽烟', '喝酒', '烫头'], 'sex': '男'}
    
    # 2. 修改年龄为 19
    my_dict["age"] = 19
    print(my_dict)  # {'name': '⼩明', 'age': 19, 'like': ['抽烟', '喝酒', '烫头'], 'sex': '男'}
    
    # 3. 添加⼀个爱好, 学习--> 本质是向列表中添加⼀个数据
    my_dict["like"].append("学习")
    print(my_dict)  # {'name': '⼩明', 'age': 19, 'like': ['抽烟', '喝酒', '烫头', '学习'], 'sex': '男'}
    
  3. 删除

    • 删除指定键值对

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

      字典.clear()
    my_dict = {'name': '⼩明', 'age': 19, 'like': ['抽烟', '喝酒', '烫头', '学习'], 'sex': '男'}
    # 删除 sex 键值对
    del my_dict["sex"]
    print(my_dict)  # {'name': '⼩明', 'age': 19, 'like': ['抽烟', '喝酒', '烫头', '学习']}
    
    # 字典.pop('键')
    my_dict.pop("age")
    print(my_dict)
    {'name': '⼩明', 'like': ['抽烟', '喝酒', '烫头', '学习']}
    
    # 删除抽烟爱好---> 本质操作是在列表中删除 数据值
    my_dict["like"].remove("抽烟")
    print(my_dict)  # {'name': '⼩明', 'like': ['喝酒', '烫头', '学习']}
    
    # 清空键值对
    my_dict.clear()
    print(my_dict)  # {}
    
  4. 查询

    根据键获取对应的值;字典中没有下标的概念,想要获取数据值,要使⽤ key(键)来获取使⽤ 字典[键]

    • 使用 字典[键]

      字典[键]
      # 1. 如果键存在 返回键对应的数据值,
      # 2.如果键不存在, 会报错
      
    • 使⽤ 字典.get(键)

      字典.get(键, 数据值)
      # 1. 数据值⼀般不写, 默认是 None
      # 返回:
      		1. 如果键存在,返回键对应的数据值
      		2.如果键不存在,返回的是 括号中书写的数据值(None),⼀般建议使⽤ get ⽅法
      
    my_dict = {'name': '⼩明', 'age': 19, 'like': ['抽烟', '喝酒', '烫头', '学习']}
    
    # 1. 获取我的名字
    print(my_dict['name'])  # ⼩明
    print(my_dict.get("name"))  # ⼩明
    print(my_dict.get("name", 'zzz'))  # ⼩明
    
    # 2. 获取性别
    # print(my_dict["sex"])# 代码会报错, 原因 key 不存在
    
    print(my_dict.get('sex'))  # None
    print(my_dict.get('sex', "保密"))  # 保密
    
    # 3. 获取第二个爱好
    print(my_dict['like'][1])  # 喝酒
    print(my_dict.get('like')[1])  # 喝酒
    
  5. 字典的遍历

    1. 字典的键 进⾏遍历

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

      for 变量 in 字典.values(): # 字典.values() 可以获取字典中所有的值
        print(变量)
      
    3. 字典的键值对 进⾏遍历

      # 变量1 就是 键, 变量2 就是键对应的值
      for 变量1, 变量2 in 字典.items(): # 字典.items() 获取键值对
        print(变量1, 变量2)
      
    # 定义字典
    my_dict = {'name': '⼩明', 'age': 18, 'sex': '男'}
    # 1. 遍历字典的键
    for i in my_dict:
        print(i)
    
    for i in my_dict.keys():
        print(i)
    
    # 2. 遍历字典的值
    for i in my_dict.values():
        print(i)
    
    # 3. 遍历键值
    for i, j in my_dict.items():
        print(i, j)
    

5. 容器部分总结

  1. 字符串,列表,元组 ⽀持加法运算

    str1 = 'hello' + ' world' # 'hello world'
    list1 = [1, 2] + [3, 4] # [1, 2, 3, 4]
    tuple1 = (1, 2) + (3, 4) # (1, 2, 3, 4)
    
  2. 字符串,列表,元组, ⽀持 乘⼀个数字

    'hello ' * 3 	   # ===> 'hello hello hello '
    [1, 2] * 3		# ===> [1, 2, 1, 2, 1, 2]
    (1, 2) * 3		# ===> (1, 2, 1, 2, 1, 2)
    
  3. len() 在 容器中都可以使⽤

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

五、函数基础

1. 函数的概念

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

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

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

2. 函数的定义

  • 将多⾏代码放在⼀块,起名字的过程, 称为函数定义
  • 函数必须先定义后调⽤
  1. 语法

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

3. 函数的调用

使⽤多⾏代码的时候, 称为函数调⽤

  1. 语法

    函数名()
    
    # 1. 函数调⽤的时候会执⾏函数体中代码
    # 2. 函数调⽤的代码,要写在 函数体外边
    
def say_hello():
    print('hello 1')
    print('hello 2')
    print('hello 3')


# 调⽤
say_hello()
say_hello()
say_hello()

4. ⽂档注释[了解]

⽂档注释的本质,还是注释, 只不过书写的位置和作⽤⽐较特殊.

  1. 书写位置:在函数名的下⽅使⽤ 三对双引号进⾏的注释
  2. 作⽤: 告诉别⼈这个函数如何使⽤的, ⼲什么的
  3. 查看:在调⽤的时候, 将光标放到函数名上,使⽤快捷键Ctrl q(Windows)/Mac(ctrl j)
  4. ctrl(cmd) B 转到函数声明中查看(按住Ctrl(cmd) ⿏标左键点击)

5. 函数的嵌套调用

在⼀个函数定义中调⽤另⼀个函数

  1. 函数定义不会执⾏函数体中的代码
  2. 函数调⽤会执⾏函数体中的代码
  3. 函数体中代码执⾏结束会回到函数被调⽤的地⽅继续向下执⾏
def func1():
    print(1)
    print('func1')
    print(2)


def func2():
    print(3)
    func1()
    print(4)


print(5)
func2()
print(6)

6. 函数的参数

# 1. 定义⼀个函数, my_sum ,对两个数字进⾏求和计算
def my_sum():
    num1 = 10
    num2 = 20
    num = num1 + num2
    print(num)


my_sum()

# 函数存在的问题, 这个函数只能对 10 和 20 进⾏求和, 不能对任意的函数进⾏求和计算.
# 问题的解决: 想要解决这个问题,可以使⽤函数参数来解决

函数参数: 在函数定义的时候,使⽤变量代替具体的数据值(进⾏占位),在函数调⽤的时候,传递具体的数据值

好处: 让函数更加通⽤,能够解决一类问题,⽽不是单纯的⼀个

# 1. 定义⼀个函数, my_sum ,对两个数字进⾏求和计算
# num1 和 num2 是函数定义时的参数,起到占位的作用,没有具体的数据值,称为形式参数,简称形参
def my_sum(num1, num2):
    num = num1 + num2  # 在什么时候定义参数,函数使用过程中使用的数据会变化的时候,就可以定义为参数
    print(num)


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

# 目前,书写的函数正在定义的时候,如果有形参;那么,在调用的时候,必须传递实参值,个数要对应,否则会报错

7. 函数的返回值

函数的返回值,可以理解为是 函数整体执⾏的结果是什么

什么时候需要书写返回值: 函数中得到的数据在后续的代码中还要使⽤,这个时候就应该将这个数据作为返回值返回,以供后续使⽤

print()		--->None
input()	   --->键盘输入的内容
type()	  --->类型
len()		  --->数据的长度(元素的个数)

在函数中想要将⼀个数据作为返回值 返回, 需要使⽤ return关键字(只能在函数中使⽤)

作⽤:

  • 将数据值作为返回值返回
  • 函数代码执⾏遇到 return, 会结束函数的执行
def my_sum(a,b):
    num= a+b
    # print(num) # 代码中没有返回值,只有print,这个结果只能在函数中使用一次,不能继续使用

my_sum(1,2)# 3 此结果在后续不能被使用
def my_sum(a, b):
    num = a + b
    # print(num) # 代码中没有返回值,只有print,这个结果只能在函数中使用一次,不能继续使用
    # 想要将求和的结果,在后续的代码中使用,需要使用return 将求和的结果进行返回
    return num  # 将结果返回到调用的地方
    # return 之后的代码会执⾏吗
    print('我是 return 之后的代码, 我会执⾏吗---> 不会执⾏')


# 1.  函数中没有print,只有return ,想要查看结果,需要子啊调用的时候使用print
print(my_sum(1, 2))

# 2.想要将函数中返回的结果,在后续代码中使⽤, 即需要将这个数据保存下来, 需要使⽤变量来接收(保存) 函数的返回值(执⾏结果)
# 变量 = 函数()
result = my_sum(10, 20)  # 将求和的结果保存到变量result 中, 可以在后续代码中使⽤
print('使用1:直接打印', result)
print('使用1:对数字加10', result + 10)
  • 返回值的说明

    def 函数名():		# 返回值None
      pass 					#代码中没有return
    
    def 函数名():
      return				# return 后边没有数据, 返回值 None
    
    def 函数名():
      return xx			# 返回值是 xx
    

六、变量进阶[理解 知道]

在这⼀部分我们了解 Python 底层是如何处理数据的

1. 变量的引用[理解]

  1. 在定义变量的时候 变量 = 数据值, Python 解释器会在内存中开辟两块空间

  2. 变量和数据都有自己的空间

  3. ⽇常简单理解:将数据保存到变量的内存中,本质是将数据的地址保存到变量对应的内存中

  4. 变量中存储数据地址的⾏为 就是引⽤ (变量引⽤了数据的地址, 简单说就是变量中存储数据), 存储的地址称为 引⽤地址

  5. 可以使⽤ id()来获取变量中的引⽤地址(即数据的地址),如果两个变量的 id() 获取的引⽤地址⼀样, 即代表着, 两个变量引⽤了同⼀个数据,是同⼀个数据

  6. 只有 赋值运算符=, 可以改变变量的引⽤(等号左边数据的引⽤)

  7. python 中数据的传递,都是传递的引⽤

a = 1  # 将数据 1 的地址 存到 a 对应的内存中
print('a:', id(a))

b = a  # 将 变量a 中的引用保存到变量b 中
print('b:', id(b))

a = 10  # 将数据 10 的地址 存到 a 对应的地址中,即 a 的引用变了
print('a:', id(a))

print('b:', id(b))

【python】python基础与unittest基础_第2张图片

2. 可变类型和不可变类型

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

可变不可变是指: 数据所在的内存是否允许修改, 允许修改就是可变类型, 不允许修改就是不可变类型(不使⽤=, 变量引⽤的数据中的内容是否会变化,会变化是可变的, 不会变化是不可变的)

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

图片1:
【python】python基础与unittest基础_第3张图片

图片2:
【python】python基础与unittest基础_第4张图片

3. 面试题

题目1:

def func(list1):
  list1.append(10)
  
  
my_list = [1, 2]
func(my_list)
print(my_list)[1, 2][1, 2, 10]


def func(list1):
  list1[0] = 10
  
  
my_list = [1, 2]
func(my_list)
print(my_list)[1, 2][10, 2]

【python】python基础与unittest基础_第5张图片

【python】python基础与unittest基础_第6张图片

题目2:

def func(list1):
  list1 = [2, 1]
  
  
my_list = [1, 2]
func(my_list)
print(my_list)[1, 2][2, 1]

【python】python基础与unittest基础_第7张图片

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

题⽬3:列表的+=操作

对于列表来说, += 的本质是 extend 操作

def func(list1):
  list1 += [1, 2] 
  
  
my_list = ['a', 'b']
func(my_list)
print(my_list) ===> ?
① ['a', 'b']['a', 'b', 1, 2] 

【python】python基础与unittest基础_第8张图片

题⽬4:交换两个变量的值

a = 10
b = 20

# ⽅法⼀: 常规⽅法		引⼊第三个变量
c = a  # 将 变量 a 中的值先保存起来 10
a = b  # 将变量 b 中的值 给 a
b = c  # 将变量 c中的值(即最开始 a 的值) 10 给 b
print(a, b)

# ⽅法⼆, 不使⽤第三个变量, 使⽤数学中的⽅法
a = a + b  # a 的值 30
b = a - b  # 30 - 20 ===> 10
a = a - b  # 30 - 10 ===> 20
print(a, b)

# ⽅法三, 重点掌握, Python 特有
a, b = b, a
print(a, b)

4. 拆包与组包

  • 组包(pack): 将多个数据值使⽤逗号连接, 组成元组
  • 拆包(unpack): 将容器中的数据值使⽤多个变量分别保存的过程,注意: 变量的个数和容器中数据的个数要保持⼀致
  • 赋值运算符, 都是先执⾏等号右边的代码, 执⾏的结果,保存到等号左边的变量中
# 组包
a = 10
b = 20
c = b, a  # 组包
print(type(c), c)  #  (10, 20)

# 拆包
a, b = c
print(a, b)
x, y, z = [1, 2, 3]
print(x, y, z)

5. 局部变量和全局变量

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

  1. 局部变量

    局部变量: 在函数内部(函数的缩进中)定义的变量,称为是局部变量
    特点:

    • 局部变量只能在当前函数内部使⽤, 不能在其他函数和函数外部使⽤

    • 在不同函数中,可以定义名字相同的局部变量, 两者之间没有影响

    • ⽣存周期(⽣命周期, 作⽤范围)–> 在哪能用 在函数被调⽤的时候,局部变量被创建;函数调⽤结束, 局部变量的值被销毁(删除), 不能使⽤;所以函数中的局部变量的值, 如果想要在函数外部使⽤, 需要使⽤ return 关键字, 将这个值进⾏返回

    def func1():
        num = 10  # num 就是局部变量
        print(f'func1 函数中{num}')
    
    
    def func2():
        num = 100  # 可以在不同函数中定义名字相同的局部变量,没有影响
        print(f'func2 函数中{num}')
    
    
    func1()  # 10
    func2()  # 100
    func1()  # 10
    
  2. 全局变量

    定义位置: 在函数外部定义的变量, 称为是 全局变量
    特点:

    • 可以在任何函数中读取(获取) 全局变量的值

    • 如何在函数中存在和全局变量名字相同的局部变量, 在函数中使⽤的是 局部变量的值(就近)

    • 在函数内部想要修改全局变量的引⽤(数据值), 需要添加 global 关键字, 对变量进⾏声明为全局变量

    • ⽣命周期:代码执⾏的时候被创建, 代码执⾏结束,被销毁(删除)

    g_num = 10  # 全局变量
    
    
    def func1():
        print(f'func1中 {g_num}')  # 在函数中可以读取全局变量的值
    
    
    def func2():
        g_num = 20  # 定义局部变量, 不会影响全局变量
        print(f'func2中 {g_num}')
    
    
    def func3():
        global g_num  # 这个函数中使⽤的 g_num 都是全局变量, 写在函数的第⼀⾏
        g_num = 30  # 修改了全局变量
        print(f'func3中 {g_num}')
    
    
    func1()  # 10
    func2()  # 20
    func1()  # 10
    func3()  # 30
    func1()  # 30
    

七、函数进阶

1. 返回值[函数返回多个数据值]

函数中想要返回⼀个数据值,使⽤ 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)

2. 函数参数

形参的不同书写⽅法

  1. 函数传参的⽅式

    • 位置传参:在函数调⽤的时候, 按照形参的顺序, 将实参值传递给形参

    • 关键字传参:在函数调⽤的时候, 指定数据值给到那个形参

    • 混合使⽤:1. 关键字传参必须写在位置传参的后⾯ 2. 不要给⼀个形参传递多个数据值

    def func(a, b, c):
        print(f'a:{a},b:{b},c:{c}')
    
    
    # 位置传参
    func(1, 2, 3)  # a:1,b:2,c:3
    
    # 关键字传参
    func(a=2, b=3, c=1)  # a:2,b:3,c:1
    
    # 混合使用
    func(1, 3, c=5)  # a:1,b:3,c:5
    
  2. 缺省参数

    缺省参数,默认参数
    列表.pop()不写参数,删除最后⼀个

    列表.sort(reverse=True)

    1. 定义⽅式:在函数定义的时候,给形参⼀个默认的数据值,这个形参就变为缺省参数;注意,缺省参数的书写要放在普通参数的后边

    2. 特点(好处):缺省参数,在函数调⽤的时候,可以传递实参值,也可以不传递实参值;如果传参,使⽤的就是传递的实参值;如果不传参,使⽤的就是默认值

    def show_info(name, sex='保密'):
        print(name, sex)
    
    
    show_info('⼩王')
    show_info('⼩王', '男')
    

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

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

  1. 不定⻓位置参数(不定⻓元组参数)

    • 书写:在普通参数的前边,加上⼀个 *,这个参数就变为不定⻓位置参数
    • 特点:这个形参可以接收 任意多个位置传参的数据
    • 数据类型:形参的类型是 元组
    • 注意:不定⻓位置参数 要写在普通的参数的后⾯
    • ⼀般写法:不定⻓位置参数的名字为 args, 即(*args)arguments
  2. 不定⻓关键字参数(不定⻓字典参数)

    1. 书写:在普通参数的前边,加上 两个 *,这个参数就变为不定⻓关键字参数

    2. 特点:这个形参可以接收 任意多个关键字传参的数据

    3. 数据类型:形参的类型是 字典

    4. 注意:不定⻓关键字参数,要写在所有参数的最后边

    5. ⼀般写法:不定⻓关键字参数的名字为 kwargs,即(**kwargs),keyword arguments

  3. 完整的参数顺序

    def 函数名(普通函数, *args, 缺省参数, **kwargs):
      pass
    
    # ⼀般在使⽤的时候, 使⽤ 1-2种, 按照这个顺序挑选书写即可
    
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
func(1, 2, 3, a=4, b=5, c=6)
  1. 不定⻓参数[函数调⽤时的拆包]

    def my_sum(*args, **kwargs):
        num = 0
        # 定义变量,保存求和的结果
        for i in args:
            num += i
        for j in kwargs.values():
            num += j
        print(num)
    
    
    # 需求, my_list = [1, 2, 3, 4] 字典 my_dict = {'a':1, 'b': 2, 'c': 3, 'd': 4}
    my_list = [1, 2, 3, 4]
    my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
    
    # 将字典和列表中的数据使⽤ my_sum 函数进⾏求和, 改如何传参的问题
    my_sum(1, 2, 3, 4)
    my_sum(a=1, b=2, c=3, d=4)
    
    # 想要将列表(元组)中的数据 分别作为位置参数,进⾏传参,需要对列表进⾏拆包操作
    my_sum(*my_list)  # my_sum(1, 2, 3, 4)
    
    # 想要将字典中的数据, 作为关键字传参,, 需要使⽤ 使⽤ **对字典进⾏拆包
    my_sum(**my_dict)  # my_sum(a=1, b=2, c=3, d=4)
    

4. Print 函数的解析

# print()
# sep=' ', 多个位置参数之间的间隔
# end='\n' 每⼀个 print 函数结束, 都会打印的内容 结束符

print(1, end=' ')
print(2, end=' ')

print(3)
print(1, 2, 3, 4, 5, 6, sep='_')
print(1, 2, 3, 4, 5, 6, sep='_*_')

5. 匿名函数

匿名函数: 就是使⽤ lambda 关键字定义的函数;⼀般称为使⽤def 关键字定义的函数为 标准函数

匿名函数只能书写⼀⾏代码

匿名函数的返回值不需要 return,⼀⾏代码(表达式) 的结果就是返回值

使用场景:作为函数的参数,这个函数⽐较简单,值使用⼀次,没有必要使⽤ def 定义

  1. 语法

    lambda 参数: ⼀⾏代码		# 这⼀⾏代码,称为是表达式
    
    # 匿名函数⼀般不需要我们主动的调⽤, ⼀般作为函数的参数使⽤的
    # 我们在学习阶段为了查看匿名函数定义的是否正确,可以调⽤
    # 1, 在定义的时候 ,将匿名函数的引⽤保存到⼀个变量中
    变量 = lambda 参数: ⼀⾏代码
    # 2. 使⽤变量进⾏调⽤
    变量()
    
  2. 代码

    # 1. ⽆参⽆返回值
    def func1():
        print('hello world')
    
    
    func1()
    
    lambda: print('hello world')  # 匿名函数的定义
    func11 = lambda: print('hello lambda')
    func11()
    
    
    # 2. ⽆参有返回值
    def func2():
        return 10
    
    
    print(func2())
    
    lambda: 10
    func22 = lambda: 10
    print(func22())
    
    
    # 3. 有参⽆返回值
    def my_sum(a, b):
        print(a + b)
    
    
    my_sum(1, 2)
    my_sum11 = lambda a, b: print(a + b)
    my_sum11(10, 20)
    
    
    # 4. 有参有返回值
    def func4(a, b):
        return a + b
    
    
    print(func4(1, 2))
    func44 = lambda a, b: a + b
    print(func44(10, 20))
    
  3. 练习

    # 1. 定义⼀个匿名函数可以求两个数的乘积(参数需要两个)
    num = lambda a, b: a * b
    
    print(num(4, 5))
    
    # 2. 定义⼀个匿名函数, 参数为字典,返回字典中键为 age 的值
    # 参数只是⼀个占位的作⽤,定义的时候没有具体的数据值,形参的值是在调⽤的时候进⾏传递,此时,形参才
    # 有数据值形参的类型就是由实参来决定的, 在函数定义的时候,参数只是⼀个符号,写什么都可以,
    # 想让其是字典类型,只需要保证实参是字典即可
    func2 = lambda x: x.get('age')
    func3 = lambda x: x['age']
    my_dict = {'name': '张三', 'age': 18}
    print(func2(my_dict))
    print(func3(my_dict))
    
  4. 匿名函数作为函数的参数[列表中的字典排序]

    user_list = [{"name": "zhangsan", "age": 18}, {"name": "lisi","age": 19}, {"name": "wangwu", "age": 17}]
    列表排序(列表中的数字):
    列表.sort() # 升序
    列表.sort(reverse=True)
    # 降序
    列表中的内容都是字典, 想要排序?
    
    user_list = [{"name": "zhangsan", "age": 18}, {"name": "lisi", "age": 19}, {"name": "wangwu", "age": 17}]
    
    # user_list.sort()
    # 列表的排序,默认是对列表中的数据进行比大小的,可以对数字类型和字符串进行比大小
    # 但是对于字典来说,就不知道该怎么⽐⼤⼩, 此时,我们需要使⽤ sort 函数中的 key 这个参数, 来指定字典⽐⼤⼩的⽅法
    # key 这个参数, 需要传递⼀个函数,⼀般是匿名函数, 字典的排序,其实要指定根据字典的什么 键进⾏排序, 我们只需要使⽤
    # 匿名函数返回字典的这个键对应的值即可
    # 列表.sort(key=lambda x: x['键'])
    # 根据年龄排序
    user_list.sort(key=lambda x: x['age'])
    print(user_list)
    user_list.sort(key=lambda x: x['age'], reverse=True)
    print(user_list)
    
    
    # user_list.sort(key=lambda x: x['age'])
    # 说明: 匿名函数中的参数是 列表中的数据, 在 sort 函数内部,会调⽤ key 这个函数(将列表中每个数据作为实参传递给形参),
    # 从列表中的获取函数的返回值, 对返回值进⾏⽐⼤⼩操作(<)
    def get_value(x):
        return x['age']
    
    
    user_list.sort(key=get_value)
    
  5. 字符串比大小

    字符比大小,是⽐较字符对应的 ASCII 码值
    A < Z < a < z

    ord(字符):获取字符对应的 ASCII 的值

    chr(ASCII 值):获取对应的字符

    字符串比大小:对应下标位置字符的大小, 直到比出大小, 如果全部比完了,还没有比出大小,就是相等

八、面向对象

1. 基本的介绍

面向对象是一种编程思想(写代码的套路)

编程思想: 1. 面向过程 2. 面向对象

以上两种都属于写代码的套路(⽅法),最终⽬的都是为了将代码书写出来,只不过过程和思考⽅法不太⼀样

  • ⾯向过程:关注的是具体步骤的实现, 所有的功能都⾃⼰书写亲力亲为;定义⼀个个函数, 最终按照顺序调⽤函数
  • ⾯向对象:关注的是结果,谁(对象) 能帮我做这件事偷懒找⼀个对象(), 让对象去做

2. 类和对象

⾯向对象的核⼼思想是:找⼀个对象去帮我们处理事情。在程序代码中,对象是由 类 创建的

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

    • 抽象的概念:对 多个 特征和⾏为相同或者相似事物的统称

    • 泛指的(指代多个,⽽不是具体的⼀个)

  1. 对象

    • 具体存在的⼀个事物,看得⻅摸得着的
    • 特指的,(指代⼀个)
苹果---> 类
红苹果----> 类
张三嘴⾥正在吃的那个苹果---> 对象

3. 类的组成

  1. 类名 (给这多个事物起⼀个名字,在代码中满⾜⼤驼峰命名法(每个单词的⾸字⺟⼤写))
  2. 属性 (事物的特征,即有什么,⼀般⽂字中的名词)
  3. ⽅法 (事物的⾏为,即做什么事,⼀般是动词)

4. 类的抽象[类的设计]

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

【python】python基础与unittest基础_第9张图片

类名:⼈类(Person, 	People)
属性:名字(name),	年龄(age), 	身⾼(height)
⽅法:跑步(run)	吃(eat)

5. 面向代码的步骤

  1. 定义类:在定义类之前先设计类
  2. 创建对象:使⽤第⼀步定义的类创建对象
  3. 通过对象调⽤⽅法

6. 面向对象基本代码的书写

  1. 定义类

    先定义简单的类,不包含属性,在 python 中定义类需要使⽤关键字 class
    ⽅法: ⽅法的本质是在类中定义的函数,只不过,第⼀个参数是 self

    class 类名:
      
      # 在缩进中书写的内容,都是类中的代码
      def ⽅法名(self): 		# 就是⼀个⽅法
        pass
    
  2. 创建对象

    创建对象是使⽤ 类名() 进⾏创建

    类名() 					# 创建⼀个对象, 这个对象在后续不能使⽤
    # 创建的对象想要在后续的代码中继续使⽤, 需要使⽤⼀个变量,将这个对象保存起来
    
    变量 = 类名() 		# 这个变量中保存的是对象的地址, ⼀般可以成为这个变量为对象
    # ⼀个类可以创建多个对象, 只要出现 类名() 就是创建⼀个对象,每个对象的地址是不⼀样的
    
  3. 调⽤⽅法

    对象.方法名()

  4. 案例实现

    # 需求:⼩猫爱吃⻥,⼩猫要喝⽔
    # 类名: 猫类 Cat
    # 属性: 暂⽆
    # ⽅法: 吃⻥ (eat)	喝⽔ (drink)
    
    # 1. 定义方法
    class Cat:
        def eat(self):  # self 会⾃动出现,暂不管
            print('⼩猫爱吃⻥')
    
        def drink(self):
            print('⼩猫要喝⽔')
    
    
    # 2. 创建对象
    blue_cat = Cat()
    
    # 3. 调用方法
    blue_cat.eat()
    blue_cat.drink()
    
    # 创建对象
    black_cat = Cat()
    black_cat.eat()
    black_cat.drink()
    Cat()  # 是
    

7. self 的说明

class Cat:
  # 在缩进中书写 ⽅法
  def eat(self):
    # self 会⾃动出现,暂不管
    print('⼩猫爱吃⻥..')
    
    
black_cat.eat()
  1. 从函数的语法上讲,self是形参,就可以是任意的变量名,只不过我们习惯性将这个形参写作 self
  2. self 是普通的形参,但是在调⽤的时候没有传递实参值;原因是 Python 解释器在执⾏代码的时候,⾃动的将调⽤这个⽅法的对象传递给了 self,即 self 的本质是对象
  3. 验证:只需要确定通过哪个对象调⽤, 对象的引⽤和 self的引⽤是⼀样的
  4. self 是函数中的局部变量,直接创建的对象是全局变量

8. 对象的属性操作

  1. 添加属性

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

      在内部⽅法中,self 是对象,在类中添加属性⼀般写在_init__ ⽅法中

      self.属性名 = 属性值
    • 类外部添加(一般不使用)

      对象.属性名 = 属性值
  2. 获取属性

    对象.属性名
    • 类内部

      在内部⽅法中,self 是对象:

      self.属性名
    • 类外部(一般不使用)

      对象.属性名
class Cat:
    def eat(self):  # self 会⾃动出现,暂不管
        print(f'{id(self)},self')
        print(f'⼩猫{self.name}爱吃⻥')


# 2. 创建对象
blue_cat = Cat()
print(f'{id(blue_cat)},blue_cat')
# 给蓝猫添加一个name 属性
blue_cat.name = '蓝猫'
# 3. 通过对象调用类中的方法
blue_cat.eat()

# 创建对象
black_cat = Cat()
black_cat.name = "黑猫"
black_cat.eat()

9.魔法方法

python 中有⼀类⽅法,以两个下划线开头,两个下划线结尾,并且在满⾜某个条件的情况下, 会⾃动调⽤,这类⽅法称为魔法⽅法

学习:

  • 什么情况下⾃动调⽤

  • 有什么⽤, ⽤在哪

  • 书写的注意事项

  1. __init__ ⽅法 [重要]

    • 什么情况下⾃动调⽤:创建对象之后会⾃动调⽤

    • 有什么⽤,⽤在哪:

      给对象添加属性的,(初始化⽅法,构造⽅法);

      某些代码, 在每次创建对象之后,都要执⾏,就可以将这⾏代码写在__init__ ⽅法

    • 书写的注意事项:1. 不要写错了 2. 如果 init ⽅法中,存在出了 self之外的参数,在创建对象的时候必须传参

    """
    猫类:属性name ,age ,show_info(输出属性信息)
    """
    
    
    class Cat:
        # 定义添加属性的方法
        def __init__(self, name, age):
            self.name = name  # 给对象添加属性name
            self.age = age  # 给对象添加属性age
            # 下方代码只是验证该方法被调用,实际代码中不要书写
            print('我是__init__,我被调用了')
    
        # 输出属性信息方法
        def show_info(self):
            print(f'小猫的名字是:{self.name},年龄是:{self.age}')
    
    
    # 创建对象,不要在⾃⼰类缩进中创建
    # Cat() # 创建对象 ,会输出
    blue_cat = Cat('蓝猫', 2)
    blue = blue_cat
    blue.show_info()
    
    # 创建黑猫
    black_cat = Cat('黑猫', 3)  # 创建对象
    black_cat.show_info()
    
  2. __str__ ⽅法 [知道]

    • 什么情况下⾃动调⽤:使⽤ print(对象) 打印对象的时候会⾃动调⽤

    • 有什么⽤,⽤在哪:

      在这个⽅法中⼀般书写对象的 属性信息的,即打印对象的时候想要查看什么信息,在这个⽅法中进⾏定义的

      如果类中没有定义__str__ ⽅法,print(对象),默认输出对象的引⽤地址

    • 书写的注意事项:这个⽅法必须返回 ⼀个字符串

    """
    猫类:属性name ,age ,show_info(输出属性信息)
    """
    
    
    class Cat:
        # 定义添加属性的方法
        def __init__(self, name, age):
            self.name = name  # 给对象添加属性name
            self.age = age  # 给对象添加属性age
            # 下方代码只是验证该方法被调用,实际代码中不要书写
            print('我是__init__,我被调用了')
    
        # 输出属性信息方法
        def show_info(self):
            print(f'小猫的名字是:{self.name},年龄是:{self.age}')
    
        def __str__(self):
            # ⽅法必须返回⼀个字符串, 只要是字符串就⾏
            return f'小猫的名字是:{self.name},年龄是:{self.age}'
    
    
    # 创建对象,不要在⾃⼰类缩进中创建
    # Cat() # 创建对象 ,会输出
    blue_cat = Cat('蓝猫', 2)
    print(blue_cat)
    
    # 创建黑猫
    black_cat = Cat('黑猫', 3)  # 创建对象
    print(black_cat)
    
  3. __del__ ⽅法 [了解]

    __init__ ⽅法,创建对象之后,会⾃动调⽤(构造⽅法)
    __del__ ⽅法,对象被删除销毁时,⾃动调⽤的(遗⾔, 处理后事)(析构⽅法)

    1. 调⽤场景:程序代码运⾏结束,所有对象都被销毁
    2. 调⽤场景:直接使⽤ del 删除对象(如果对象有多个名字(多个对象引⽤⼀个对象),需要吧所有的对象都删除才⾏)
    class Demo:
        def __init__(self, name):
            print('我是__init__,我被调用了')
            self.name = name
    
        def __del__(self):
            print(f'{self.name}没了,给他处理后事。。。')
    
    
    # Demo('a')
    
    a = Demo('a')
    b = Demo('b')
    del a  # 删除销毁 对象
    print('代码运行结束')
    
  4. 案例

    案例1:

    """
    类名: ⼈类 Person
    属性: 姓名 name, 体重 weight
    ⽅法: 跑步 run
    吃东⻄ eat
    添加属性:__init__
    属性信息:__str__
    """
    
    
    class Person:
        def __init__(self, name, weight):
            self.name = name
            self.weight = weight
    
        def __str__(self):
            return f"'姓名':{self.name},'体重':{self.weight}"
    
        def run(self):
            print(f'{self.name}跑步5km,体重减少了')
            # 减体重,即修改属性
            self.weight -= 0.5
    
        def eat(self):
            print(f'{self.name}吃东西,体重增加了')
            # 增加体重,即修改属性
            self.weight += 1
    
    
    xm = Person('小明', 75)
    print(xm)
    xm.run()
    print(xm)
    xm.eat()
    print(xm)
    

九、文件操作

1. 文件介绍

计算机的⽂件,就是存储在某种⻓期储存设备上的⼀段数据

作⽤: 将数据⻓期保存下来,在需要的时候使⽤

- 计算机只认识⼆进制(0 1)
- ⽂件中存储的数据都是以⼆进制(0 1) 的形式去存储的

可以根据⽂件中的⼆进制内容,能否使⽤记事本软件将其转换为⽂字,将⽂件分为两种: ⽂本⽂件⼆进制⽂件

⽂本⽂件:

  • 能够使⽤记事本软件打开(能够使⽤记事本转换为⽂字)

  • txt, md, py , html, css, js , json

⼆进制⽂件:

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

2. 文件操作

打开⽂件,读或者写⽂件,关闭⽂件

  1. 打开⽂件

    将⽂件从磁盘(硬盘) 中 读取到内存中

    语法:

    open(file, mode=‘r’, encoding=None)
    • 参数 file:是要打开的⽂件,类型是字符串,⽂件的路径可以是相对路径,也可以是绝对路径(从根⽬录开始书写的路径),建议使⽤相对路径(相对于当前代码⽂件所在的路径,./ ./ )
    • 参数 mode:默认参数(缺省参数),表示的是打开⽂件的⽅式
      1. r(read) 只读打开(如果⽂件不存在,代码会报错)
      2. w:(write) 只写打开
      3. a:(append) 追加打开,在⽂件的末尾写⼊内容(⽂件不存在会创建⽂件,⽂件存在,在⽂件的末尾写⼊内容)
    • 参数 encoding: 编码⽅式,(⽂字和⼆进制如何进⾏转换的)
      . gbk:将⼀个汉字转换为 2 个字节⼆进制
      1. utf-8:常⽤,将⼀个汉字转换为 3 个字节的⼆进制
    • 返回值:返回的是⽂件对象, 后续对⽂件的操作,都需要这个对象
  2. 读或者写⽂件

    写文件:

    向⽂件中写⼊指定的内容。前提:⽂件的打开⽅式是 w 或者 a

    ⽂件对象.write(‘写⼊⽂件的内容’)

    返回值: 写⼊⽂件的字符数,⼀般不关注

    注意 w ⽅式打开⽂件:

    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()
    
    
  3. 关闭⽂件

    关闭⽂件: 将⽂件占⽤的资源进⾏清理,同时会保存⽂件,⽂件关闭之后,这个⽂件对象就不能使⽤了

    ⽂件对象.close()

3. 使⽤ with open 打开⽂件

with open() 打开⽂件的好处:不⽤⾃⼰去书写关闭⽂件的代码,会⾃动进⾏关闭

with open(file, mode, encoding='utf-8') as 变量:
  #	在缩进中去读取或者写⼊⽂件

#	缩进中的代码执⾏结束, 出缩进之后, ⽂件会⾃动关闭
with open('a.txt', 'a', encoding='utf-8') as f:
    f.write('good good study\n')

4. 按行读取文件内容

按⾏读取⽂件:⼀次读取⼀⾏内容

⽂件对象.readline()

# with open('b.txt', encoding='utf-8') as f:
#     buf = f.readline()  # 111
#     print(buf)
#     print(f.readline())  # 222


# with open('b.txt', encoding='utf-8') as f:
#     for i in f:  # 按⾏读取, 读到⽂件末尾结束
#         print(i, end='')

# read() 和 readline() 读到⽂件末尾, 返回⼀个空字符串,即⻓度为 0
# with open('b.txt', encoding='utf-8') as f:
#     while True:
#         buf = f.readline()
#         if len(buf) == 0:
#             break
#         else:
#             print(buf, end='')

# 在容器中 , 容器为空,即容器中的数据的个数为 0 ,表示False, 其余情况都是 True
with open('b.txt', encoding='utf-8') as f:
    while True:
        buf = f.readline()
        if buf: # if len(buf) != 0
            print(buf)
        else:
            break

5. json 文件的处理

json ⽂件 也是⼀个⽂本⽂件,就可以直接使⽤read()和write() ⽅法去操作⽂件,只是使⽤这两个⽅法不⽅便;所以对 json ⽂件有⾃⼰独特的读取和写⼊的⽅法。

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

  1. json 的介绍

    json 基于⽂本,独⽴于语⾔的轻量级的数据交换格式

    • 基于⽂本;是⼀个文本文件;不能包含图⽚、⾳视频等

    • 独⽴于语⾔;不是某个语⾔特有的,每种编程语⾔都可以使⽤的

    • 轻量级;相同的数据,和其他格式相⽐,占⽤的⼤⼩⽐较⼩

    • 数据交换格式;后端程序员给前端的数据 (json、html、xml)

  2. 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
  3. json ⽂件的书写

    我叫⼩明,我今年 18 岁,性别男, 爱好 听歌, 游戏,购物,吃饭,睡觉,打⾖⾖;我的居住地址为 国家中国, 城市上海

    {
      "name": "小明",
      "age": 18,
      "isMen": true,
      "like": [
        "听歌",
        "游戏",
        "购物",
        "吃饭",
        "睡觉",
        "打⾖⾖"
      ],
      "address": {
        "country": "中国",
        "city": "上海"
      }
    }
    
  4. 读取 json ⽂件

    1. 导包 import json

    2. 读打开⽂件

    3. 读⽂件 json.load(⽂件对象)

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

    # 1. 导包 import json
    import json
    
    # 2. 读打开⽂件
    with open('info.json', encoding='utf-8') as f:
        # 3. 读⽂件 json.load(⽂件对象)
        # buf = f.read()
        # print(type(buf), buf)  # 
        result = json.load(f)
        print(type(result))  # 
        # 姓名
        print(result.get("name"))
        # 年龄
        print(result["age"])
        # 城市
        print(result.get("address").get("city"))
    
  5. 练习1

    我叫⼩明,我今年 18 岁,性别男, 爱好 听歌, 游戏,吃饭,睡觉,打⾖⾖,我的居住地址为 国家中国, 城市上海.
    我叫⼩红,我今年 17 岁,性别⼥, 爱好 听歌, 学习,购物我的居住地址为 国家 中国, 城市北京

    • Info.json
    [
      {
        "name": "⼩明",
        "age": 18,
        "isMen": true,
        "like": [
          "听歌",
          "游戏",
          "购物",
          "吃饭",
          "睡觉",
          "打⾖⾖"
        ],
        "address": {
          "country": "中国",
          "city": "上海"
        }
      },
      {
        "name": "⼩红",
        "age": 17,
        "isMen": false,
        "like": [
          "听歌",
          "购物",
          "学习"
        ],
        "address": {
          "country": "中国",
          "city": "北京"
        }
      }
    ]
    
    • 代码
    import json
    
    with open('Info2.json', encoding='utf-8') as f:
        info_list = json.load(f)
        for info in info_list:
            print(info.get('name'), info.get('age'), info.get('address').get('city'))
    
  6. 练习2

    某⽹站的测试数据如下 data.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('info3.json', encoding='utf-8') as f:
            data = json.load(f)  # 列表
            new_list = []
            for i in data:  # i字典
                # print((i.get('username'), i.get("password"), i.get("expect")))
                new_list.append((i.get('username'), i.get("password"), i.get("expect")))
    
            # print(new_list)
    
        return new_list
    
    
    print(read_data())
    
  7. 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('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 = 2)
        json.dump(my_list, f, ensure_ascii=False, indent=4)
    

十、异常

程序在运⾏时,如果 Python 解释器遇到到⼀个错误,会停⽌程序的执⾏,并且提示⼀些错误信息,这就是异常

程序停⽌执⾏并且提示错误信息这个动作,抛出异常(raise 关键字)

捕获异常:程序遇到异常,默认动作是终⽌代码程序的执⾏,遇⻅异常之后,可以使⽤异常捕获,让程序代码继续运⾏,不会终⽌运⾏(重点)

1.异常捕获[重点]

  1. 基本语法

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

    案例1:

    try:
        # 1. 获取用户键盘盘输入的类型
        num = input('请输入一个整数数字:')
        # 2. 转换数据类型
        num = int(num)
        # 3. 输出转换后的数据内容
        print(num)
    
    except:
        print('请输入正确的数字')
    
    print('后续其他的代码,可以继续执⾏')
    
    

    案例2:

    try:
        # 1. 获取用户键盘盘输入的类型
        num = input('请输入一个整数数字:')
        # 2. 转换数据类型
        num = int(num)
        # 3. 输出转换后的数据内容
        print(num)
        a=10/num
        print(f'a:{a}')
    
    
    except ValueError:  # 只能捕获 ValueError 类型及其⼦类的异常
    
        print('发⽣了异常, 请输⼊正确的数字..')
    
  2. 捕获多个指定类型的异常

    好处:可以针对不同的异常错误,进⾏单独的代码处理

    try:
      书写可能发⽣异常的代码
    except 异常类型1: 		# 只能捕获指定类型的异常, 如果不是这个异常,还是会报错
      发⽣了异常1执⾏的代码
      
    except 异常类型2:
      发⽣了异常2执⾏的代码
    except 异常类型..:
      发⽣了异常..执⾏的代码
    

    案例:

    try:
        # 1. 获取用户键盘盘输入的类型
        num = input('请输入一个整数数字:')
        # 2. 转换数据类型
        num = int(num)
        # 3. 输出转换后的数据内容
        print(num)
        a = 10 / num
        print(f'a:{a}')
    
    
    except ValueError:  # 只能捕获 ValueError 类型及其⼦类的异常
    
        print('发⽣了异常, 请输⼊正确的数字..')
    except ZeroDivisionError:
        print('除数不能为 0')
    
  3. 异常捕获的完整版本

    完整版本中的内容,不是说每⼀次都要全部书写,根据⾃⼰的需要,去选择其中的进⾏使⽤

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

    常用的格式:

    try:
      可能发⽣异常的代码
      
    except Exception as e:
      发⽣异常执⾏的代码
    

    案例:

    try:
        # 1. 获取用户键盘盘输入的类型
        num = input('请输入一个整数数字:')
        # 2. 转换数据类型
        num = int(num)
        # 3. 输出转换后的数据内容
        print(num)
        a = 10 / num
        print(f'a:{a}')
    
    
    except Exception as e:
        print(f'错误信息为{e}')
    
    else:
        print('没有发⽣异常我会执⾏')
    finally:
        print('不管有没有发⽣异常,我都会执⾏')
    

2. 异常传递[了解]

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

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

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


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


try:
    func2()

except Exception as e:
    print(f'错误信息为{e}')

十一、模块和包

  • Python 源代码⽂件就是⼀个模块
  • 模块中定义的变量函数类,都可以让别⼈使⽤;同样,可以使⽤别⼈定义的(好处:别⼈定义好的不需要我们再次书写,直接使⽤即可)
  • 想要使⽤别⼈的模块中的内容⼯具(变量,类,函数),必须先导⼊模块才可以
  • 我们⾃⼰写的代码,想要作为模块使⽤,代码的名字需要满⾜标识符的规则(由数字,字⺟下划线组成,不能以数字开头)

1. 导入模块的语法

  1. 方法一

    import 模块名
    
    # 使⽤模块中的内容
    模块名.⼯具名
    
    # 举例
    import random
    import json
    
    random.randint(a, b)
    json.load()
    json.dump()
    
  2. 方法二

    from 模块名 import ⼯具名
    
    # 使⽤
    ⼯具名
    # 如果是函数和类需要加括号
    
    # 举例
    from random import randint
    from json import load, dump
    
    
    randint(a, b)
    load()
    dump()
    
  3. 方法三[了解,基本不用]

    from 模块名 import 		*# 将模块中所有的内容都导⼊
    
    
    from random import *
    from json import *
    
    
    randint(a, b)
    load()
    dump()
    

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

```python
# 方式 1 重点记忆
import random

print(random.randint(1, 20))

# 方式 2 重要快捷⽅式导包
from random import randint

print(randint(1, 20))

# 方式 3 问题: 可能存在多个模块中有相同的名字的⼯具, 会产⽣冲突
from random import *

print(randint(1, 20))
```

2. 模块的查找顺序

在导⼊模块的时候,会先在当前⽬录中找模块,找到就直接使⽤;没有找到回去系统的⽬录中进⾏查找,找到直接使⽤;没有找到就报错

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

3. __name__ 的作用

1. 	每个代码⽂件都是⼀个模块
2. 	在导⼊模块的时候, 会执⾏模块中的代码(三种⽅法都会)
3.	__name__ 变量
	3.1	__name__ 变量 是 python 解释器⾃动维护的变量
	3.2	__name__ 变量,如果代码是直接运⾏, 值是 "__main__"
	3.3	__name__ 变量, 如果代码是被导⼊执⾏, 值是 模块名(即代码⽂件名)
在代码⽂件中, 在被导⼊时不想被执⾏的代码,可以写在 if __name__ == "__main__": 代码的缩进中

【python】python基础与unittest基础_第10张图片

【python】python基础与unittest基础_第11张图片

4. 包(package)

在 Python 中,包是⼀个⽬录,只不过在这个⽬录存在⼀个⽂件__init__.py(可以是空的)

将功能相近或者相似的代码放在⼀起的.

在 Python 中使⽤的时候,不需要可以是区分是包还是模块,使⽤⽅式是⼀样的

random 模块 (单个代码⽂件)

json 包(⽬录)

unittest 包(⽬录)

  1. import 包名
  2. alt 回车 快捷导⼊

十二、UnitTest框架

1. 介绍

  1. 框架

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

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

  2. 什么是UnitTest框架?

    概念:UnitTest是Python⾃带的⼀个单元测试框架,⽤它来做单元测试

    ⾃带的框架(官⽅):不需要单外安装, 只要安装了 Python,就可以使⽤ random, json, os, time
    第三⽅框架:想要使⽤ 需要先安装后使⽤(pytest), selenium, appium, requests

    单元测试框架:主要⽤来做单元测试,⼀般单元测试是开发做的
    对于测试来说,unittest 框架的作⽤是⾃动化脚本(⽤例代码)执⾏框架(使⽤unittest框架来管理运⾏多个测试⽤例的)

  3. 为什么使⽤UnitTest框架?

    • 能够组织多个⽤例去执⾏
    • 提供丰富的断⾔⽅法(让程序代码代替⼈⼯⾃动的判断预期结果和实际结果是否相符)
    • 能够⽣成测试报告

2. UnitTest的组成

  1. TestCase(最核⼼的模块)

    TestCase(测试⽤例),注意这个测试⽤例是 unittest 框架的组成部分,不是⼿⼯和⾃动化中我们所说的⽤例(TestCase)
    主要作⽤:每个 TestCase(测试⽤例) 都是⼀个代码⽂件,在这个代码⽂件中来书写 真正的⽤例代码

  2. TestSuite

    TestSuite(测试套件),⽤来管理、组装(打包)多个TestCase(测试⽤例)的

  3. TestRunner

    TestRunner(测试运行),TestSuite(测试套件)的

  4. TestLoader

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

  5. Fixture

    Fixture(测试夹具),书写在 TestCase(测试⽤例)代码中;是⼀个代码结构,可以在每个⽅法执⾏前后都会执⾏的内容

    举例:
    登录的测试⽤例, 每个⽤例中重复的代码就可以写在Fixture 代码结构中, 只写⼀遍, 但每次⽤例⽅法的执⾏,都会执⾏ Fixture 中的代码
    
    	1. 打开浏览器
    	2. 输⼊⽹址
    

3. TestCase(测试用例)

  • 是⼀个代码⽂件,在代码⽂件中来书写真正的⽤例代码

  • 代码⽂件的名字必须按照标识符的规则来书写(可以将代码的作⽤在⽂件的开头使⽤注释说明)

  1. 步骤

    1. 导包 (unittest)
    2. ⾃定义测试类
    3. 在测试类中书写测试⽅法
    4. 执⾏⽤例
    
  2. 代码

    """
    代码的⽬的: 学习 TestCase(测试⽤例)模块的书写⽅法
    """
    
    # 1. 导包 (unittest)
    import unittest
    
    
    # 2. ⾃定义测试类,需要继承unittest 模块中的 TestCase 类即可
    class TestDemo(unittest.TestCase):
    
        # 3. 在测试类中书写测试⽅法,即 用例代码,⽬前没有真正的⽤例代码, 使⽤ print 代替
        # 书写要求, 测试⽅法 必须以 test_ 开头(本质是以test 开头)
        def test_method1(self):
            print('测试方法1')
    
        def test_method2(self):
            print('测试方法2')
    
    # 4, 执⾏⽤例(⽅法)
    # 4.1 将光标放在 类名的后边 运⾏, 会执⾏类中的所有的测试⽅法
    # 4.2 将光标放在 ⽅法名的后边 运⾏, 只执⾏当前的⽅法
    

    问题1:代码⽂件的命名不规范

    1. 代码⽂件的名字以数字开头

    2. 代码⽂件名字中有空格

    3. 代码⽂件名字有中⽂

    4. 其他的特殊符号(数字、字⺟、下划线组成,不能以数字开头)

    问题2:代码运⾏没有结果

    右键运⾏没有 unittests for 的提示,出现的问题
    解决⽅案:1. 重新新建⼀个代码⽂件,将写好的代码复制进去 2. 删除已有的运⾏⽅式

    问题3:没有找到⽤例

    测试⽅法中不是以 test开头的,或者单词写错了

4. TestSuite & TestRunner

  • TestSuite(测试套件): 管理、打包、组装TestCase(测试⽤例)⽂件的

  • TestRunner(测试执⾏): 执⾏TestSuite(套件)

  1. 步骤

    1. 导包(unittest)
    2. 实例化(创建对象)套件对象
    3. 使⽤套件对象添加⽤例⽅法
    4. 实例化运⾏对象
    5. 使⽤运⾏对象去执⾏套件对象
    
  2. 代码

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

    • 方法1:
    """
    学习 TestSuite 和 TestRunner 的使⽤
    """
    
    # 1. 导包(unittest)
    import unittest
    
    # 2. 实例化(创建对象)套件对象
    from day_09.hm_07_testcase1 import TestDemo1
    from day_09.hm_07_testcase2 import TestDemo2
    
    suite = unittest.TestSuite()
    
    # 3. 使⽤套件对象添加⽤例⽅法
    # ⽅式⼀, 套件对象.addTest(测试类名('⽅法名')) #建议测试类名和⽅法名直接去复制,不要⼿写
    suite.addTest(TestDemo1('test_method1'))
    suite.addTest(TestDemo1('test_method2'))
    suite.addTest(TestDemo2('test_method1'))
    suite.addTest(TestDemo2('test_method2'))
    
    # 4. 实例化运⾏对象
    runner = unittest.TextTestRunner()
    
    # 5. 使⽤运⾏对象去执⾏套件对象
    # 运⾏对象.run(套件对象)
    runner.run(suite)
    
    • 方法2:
    """
    学习 TestSuite 和 TestRunner 的使⽤
    """
    
    # 1. 导包(unittest)
    import unittest
    
    # 2. 实例化(创建对象)套件对象
    from day_09.hm_07_testcase1 import TestDemo1
    from day_09.hm_07_testcase2 import TestDemo2
    
    suite = unittest.TestSuite()
    
    # 3. 使⽤套件对象添加⽤例⽅法
    # ⽅式二, 将⼀个测试类中的所有⽅法进⾏添加 套件对象.addTest(unittest.makeSuite(测试类名))
    suite.addTest(unittest.makeSuite(TestDemo1))
    suite.addTest(unittest.makeSuite(TestDemo2))
    
    # 4. 实例化运⾏对象
    runner = unittest.TextTestRunner()
    
    # 5. 使⽤运⾏对象去执⾏套件对象
    # 运⾏对象.run(套件对象)
    runner.run(suite)
    
  3. 练习

    1. 在 tools 模块中定义 add 函数, 对两个数字进⾏求和计算
    2. 书写 TestCase 代码对 add() 进⾏测试
    ⽤例 1:	1,	2,	3
    ⽤例 2:	10, 	20,	30
    ⽤例 3:	2,	3,	5
    

    ⽤例代码

    """
    案例练习
    """
    # 1. 导包
    import unittest
    
    from day_09.tools import add
    
    
    # 2. 自定义测试类
    class TestAdd(unittest.TestCase):
        # 写测试方法,就是测试用例的代码
        def test_method1(self):
            # 1,2,3 判断实际结果和预期结果是否相符
            if add(1, 2) == 3:
                print('测试通过')
            else:
                print('测试不通过')
    
        def test_method2(self):
            # 10,20,30 判断实际结果和预期结果是否相符
            if add(10, 20) == 30:
                print('测试通过')
            else:
                print('测试不通过')
    
        def test_method3(self):
            # 2,3,5 判断实际结果和预期结果是否相符
            if add(2, 3) == 5:
                print('测试通过')
            else:
                print('测试不通过')
    
    import unittest
    
    # 实例化套件对象
    from day_09.hm_08_test import TestAdd
    
    suite = unittest.TestSuite()
    
    # 添加测试⽅法
    suite.addTest(unittest.makeSuite(TestAdd))
    
    # 实例化运行对象
    runner = unittest.TextTestRunner()
    
    # 运行
    runner.run(suite)
    

5. TestLoader (测试加载)

TestLoader (测试加载),作用和 TestSuite 的作用是一样的, 对 TestSuite 功能的补充,用来组装测试用例的

比如: 如果 TestCase 的代码文件有很多, (10 20, 30 )

  1. 使用步骤

    1. 导包
    2. 实例化测试加载对象并添加用例 —> 得到的是 suite 对象
    3. 实例化 运行对象
    4. 运行对象执行套件对象
  2. 代码实现

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

    """
    TestLoader 的使用
    """
    
    # 1. 导包
    import unittest
    
    # 2.实例化加载对象病添加用例
    # unittest.TestLoader().discover('用例所在的路径', '用例的代码文件名')
    # 用例所在的路径,建议使用相对路径, 用例的代码文件名可以使用 *(任意多个任意字符) 通配符
    # suite = unittest.TestLoader().discover('./case', 'hm*.py')
    # suite = unittest.TestLoader().discover('./case', '*test*.py')
    # suite = unittest.TestLoader().discover('./case', '*test*')
    suite = unittest.TestLoader().discover('./case', '*case1.py')
    
    
    # # 3. 实例化运行对象
    # runner= unittest.TextTestRunner()
    # # 4. 执行
    # runner.run(suite)
    # 可以将 3 4 步 变为一步
    unittest.TextTestRunner().run(suite)
    
    # 1. 导包
    # 2. 使用默认的加载对象并加载用例
    # 3. 实例化运行对象并运行
    """
    TestLoader 的使用"""
    # 1,导包
    import unittest
    # 2,使用默认的加载对象并加载用例
    suite = unittest.defaultTestLoader.discover('case', 'hm_*.py')
    # 可以将 3 4 步 变为一步
    unittest.TextTestRunner().run(suite)
    

6. Fixture(测试夹具)

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

  1. 方法级别

    在每个测试方法(用例代码) 执行前后都会自动调用的结构

    # 方法执行之前
    def setUp(self):
      每个测试方法执行之前都会执行
      pass
    
    # 方法执行之后
    def tearDown(self):
      每个测试方法执行之后都会执行
      pass
    
  2. 类级别

    在每个测试类中所有方法执行前后 都会自动调用的结构(在整个类中 执行之前执行之后个一次)

    # 类级别的Fixture 方法, 是一个 类方法
    # 类中所有方法之前
    @classmethod
    def setUpClass(cls):
      pass
    
    # 类中所有方法之后
    @classmethod
    def tearDownClass(cls):
      pass
    
  3. 模块级别[了解]

    模块:代码文件在每个代码文件执行前后执行的代码结构

    # 模块级别的需要写在类的外边直接定义函数即可
    # 代码文件之前
    def setUpModule():
      pass
    
    # 代码文件之后
    def tearDownModule():pass
    
  4. 案例

    """
    1. 打开浏览器(整个测试过程中就打开一次浏览器) 类级别
    2. 输入网址(每个测试方法都需要一次) 方法级别
    3. 输入用户名密码验证码点击登录(不同的测试数据) 测试方法
    4. 关闭当前页面(每个测试方法都需要一次) 方法级别
    5. 关闭浏览器(整个测试过程中就关闭一次浏览器) 类级别
    """
    
    # 1. 打开浏览器(整个测试过程中就打开一次浏览器) 类级别
    # 2. 输入网址(每个测试方法都需要一次) 方法级别
    # 3. 输入用户名密码验证码点击登录(不同的测试数据) 测试方法
    # 4. 关闭当前页面(每个测试方法都需要一次) 方法级别
    # 2. 输入网址(每个测试方法都需要一次) 方法级别
    # 3. 输入用户名密码验证码点击登录(不同的测试数据) 测试方法
    # 4. 关闭当前页面(每个测试方法都需要一次) 方法级别
    # 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('..5.关闭浏览器')
    
        def test_1(self):
            print('输入用户名密码验证码,点击登录 1')
    
        def test_2(self):
            print('输入用户名密码验证码,点击登录 2')
    

7. 断言

让程序代替人工自动的判断预期结果和实际结果是否相符

断言的结果有两种: (在 unittest 中使用断言, 都需要通过 self.断言方法 来试验)

  • True, 用例通过
  • False, 代码抛出异常, 用例不通过
  1. assertEqual

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

    self.assertIn(预期结果, 实际结果) # 判断预期结果是否包含在实际结果中
    • 包含,用例通过

    • 不包含,用例不通过,抛出异常

import unittest

from tools import login


class TestLogin(unittest.TestCase):
    def test_username_password_ok(self):
        """正确的用户名和密码: admin, 123456, 登录成功"""
        self.assertEqual('登录成功', login('admin', '123456'))

    def test_username_error(self):
        """错误的用户名: root, 123456, 登录失败"""
        self.assertEqual('登录失败', login('root', '123456'))

    def test_password_error(self):
        """错误的密码: admin, 123123, 登录失败"""
        self.assertEqual('登录失败', login('admin', '123123'))

    def test_username_password_error(self):
        """错误的用户名和错误的密码: aaa, 123123, 登录失败"""
        # self.assertEqual('登录失败', login('aaa', '123123'))
        self.assertIn('失败', login('aaa', '123123'))

8. 参数化

在测试方法中,使用 变量 来代替具体的测试数据,然后使用传参的方法将测试数据传递给方法的变量

好处:相似的代码不需要多次书

工作中场景:

  • 测试数据一般放在 json 文件中
  • 使用代码读取 json 文件,提取我们想要的数据 —> [(), ()] or [[], []]
  1. 安装插件

    unittest 框架本身是不支持参数化,想要使用参数化,需要安装插件来完成
    联网安装(在 cmd 窗口安装 或者 ) pip install parameterized

  2. 参数化代码

    1. 导包 unittest/ pa
    2. 定义测试类
    3. 书写测试方法(用到的测试数据使用变量代替)
    4. 组织测试数据并传参
    
    # 1. 导包 unittest/ pa
    import unittest
    
    from parameterized import parameterized
    from day_10_unitTest.tools import login
    
    # 组织测试数据  格式 [(),(),()]
    data = [('admin', '123456', '登录成功'), ('root', '123456', '登录失败'), ('admin', '123123', '登录失败')]
    
    
    # 2. 定义测试类
    class TestLogin(unittest.TestCase):
    
        # 3. 书写测试方法(用到的测试数据使用变量代替)
        # 4. 组织测试数据并传参(装饰器@)
        @parameterized.expand(data)
        def test_login(self, username, password, expect):
            self.assertEqual(expect, login(username, password))
    

【python】python基础与unittest基础_第12张图片

  1. 参数化代码

    [
      {
        "desc": "正确的⽤户名密码",
        "username": "admin",
        "password": "123456",
        "expect": "登录成功"
      },
      {
        "desc": "错误的⽤户名",
        "username": "root",
        "password": "123456",
        "expect": "登录失败"
      },
      {
        "desc": "错误的密码",
        "username": "admin",
        "password": "123123",
        "expect": "登录失败"
      }
    ]
    
    # 1. 导包 unittest/ pa
    import json
    import unittest
    
    from parameterized import parameterized
    from day_10_unitTest.tools import login
    
    
    # 组织测试数据  格式 [(),(),()]
    def build_data():
        with open('data.json', encoding='utf-8') as f:
            result = json.load(f)  # [{},{},{}]
            data = []
            for i in result:  # i {}
                data.append((i.get('username'), i.get('password'), i.get('expect')))
    
        return data
    
    
    # 2. 定义测试类
    class TestLogin(unittest.TestCase):
    
        # 3. 书写测试方法(用到的测试数据使用变量代替)
        # 4. 组织测试数据并传参(装饰器@)
        @parameterized.expand(build_data())
        def test_login(self, username, password, expect):
            self.assertEqual(expect, login(username, password))
    

9. 跳过

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

直接将测试函数标记成跳过:

@unittest.skip(‘跳过的原因’)

根据条件判断测试函数是否跳过,判断条件成立,跳过:

@unittest.skipIf(判断条件, ‘跳过原因’)

import unittest

# version = 30
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')

10. 测试报告

  1. 自带的测试报告

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

  2. 第三方的测试报告

    1. 获取第三方的 测试运行类模块 , 将其放在代码的目录中
    2. 导包 unittest
    3. 使用 套件对象, 加载对象 去添加用例方法
    4. 实例化 第三方的运行对象 并运行 套件对象
    
    # 1. 获取第三方的 测试运行类模块 , 将其放在代码的目录中
    # 2. 导包 unittest
    import unittest
    from HTMLTestRunner import HTMLTestRunner
    
    # 3. 使用 套件对象, 加载对象 去添加用例方法
    suite = unittest.defaultTestLoader.discover('.', 'hm_05_pa1.py')
    
    # 4. 实例化 第三方的运行对象 并运行 套件对象
    # HTMLTestRunner()的参数
    # stream=sys.stdout, 必填,测试报告的文件对象(open ), 注意点,要使用 wb 打开
    # verbosity=1, 可选, 报告的详细程度,默认 1 简略, 2 详细
    # title=None, 可选, 测试报告的标题
    # description=None 可选, 描述信息, Python 的版本, pycharm 版本
    file = 'report1.html'  # 报告的后缀是.html
    with open(file, 'wb') as f:
        runner = HTMLTestRunner(f)  # 运行对象
        runner = HTMLTestRunner(f, 2, '测试报告', 'python 3.6.8 ') # 运行对象
        # 运行对象执行套件, 要写在 with 的缩进中
        runner.run(suite)
    
    1. 组织用例文件(TestCase 里边),书写参数化,书写断言,书写 Fixture,书写 跳过;如果单个测试测试文件,直接运行,得到测试报告;如果有多个测试文件, 需要组装运行生成测试报告
    2. 使用 套件对象组装,或者使用 加载对象组装
    3. 运行对象 运行
    		3.1 运行对象 = 第三方的运行类(文件对象(打开文件需要使用 wb 方式))
    		3.2 运行对象.run(套件对象)
    

你可能感兴趣的:(python,pytest)