学习掌握 python 的基本语法
在代码中遇到常见的错误,自己能够动手解决问题
Python 只是⼀个编程语⾔,在⼯作中需要结合其他的⼯具使⽤
Python + selenium web ⾃动化(功能测试转换为代码)
Python + appium 移动端(⼿机端 APP)⾃动化
Python + requests 接⼝
作者: 吉多·范罗苏姆(Guido van Rossum) 龟叔;1989 年开始书写, 1991年诞生
问什么学习 Python?
Python 的版本
Python2 (2.x 2.7)
Python3(主流使用的版本, 3.6 之后的版本(即大于等于3.6))
计算机只认识二进制(0 和 1)
编程语言是人和计算机沟通的语言
编程语言分类: 编译型语言, 解释型语言
执行效率:
机器语言>汇编语言>高级语言(编译型>解释器)
开发效率:
机器语言<汇编语言<高级语言(编译型<解释器)
跨平台性:
解释器语言跨平台性极强
print
函数的简单使用print("hello world!")
print() 是 Python 中自带的函数,作用在控制台中输出括号中的内容;后续看到这个函数就是输出打印 数据的, 或者想要在控制台中显示某个内容,就要使用 print() 函数
print() 主要在学习阶段使用, 便于我们确认结果的正确性;在实际工作的代码中,基本不会使用 print,会使用其他的内容代替(日志模块)
print() 函数中是什么内容,就会显示什么内容, 里边的文字信息可以使用单引号,也可以使用双引号
注释是对代码解释说明的文字, 不会执行, 可以增加代码的可读性
Python
中的注释分为两种, 单行注释和多行注释
单行注释
使⽤ 井号空格进行注释(单独⼀个# 也可以)
快捷键 : Ctrl(cmd) /
可以选中多行,使用快捷键
如果代码已经添加注释, 再次使用快捷键,会取消注释
多⾏注释
多行注释中的内容 可以换行书写
多行注释可以使用 3 对 双引号或者 3 对 单引号 , 被三对引号包括的内容就是注释的内容
三对引号的注释,⼀般写在文件的最开始部分,或者文档注释处(函数)
# 这是单行注释,代码不会执行
# 以井号键开始的注释
print("helloworld!!")
"""
使用三对双引号包括起来的内容也是注释,
可以换行,不会执行
"""
'''
使用三对单引号包括起来的内容也是注释,
可以换行,不会执行
'''
print("end")
红色
红色波浪线是代码的错误, 必须处理,代码才能执行
# 注意 :在后续课程中,某些代码没有写完,也会出现红色波浪线
灰色
灰色波浪线, 不会影响代码的正常执行, 基本上所有的灰色波浪线都是 PEP8 造成的
# PEP8: 是 Python 代码的书写规范, 如果不按照这个规范书写,会给灰色波浪线提示,建议代码的书写按照 PEP8 的规范书写
1. 可以书写代码的时候注意 PEP8 的代码规范
2. 可以在书写完成之后,使用快捷键 Ctrl + Alt + L 来按照PEP8 的规范自动格式化代码
绿色
绿色波浪线, 不影响代码的正常执行, 在引号中, 认为你书写的内容不是⼀个单词,就会给你绿色提示
作用
用来存储数据的(在程序代码中出现的数据,想要保存下来使用, 就必须使用变量), 如: 测试数据, 用户名, 密码, 验证码
变量注意事项: 变量必须先定义(保存数据)后使用(取出数据)
定义变量
变量名 = 数据值 # 理解为将数据值保存到变量中
# 比如:name = '张三' # 定义⼀个变量 name, 存储的数据值是 张三
使用变量
变量定义之后, 想要是使用变量中的数据, 直接使用变量名即可
# 使用变量获取数据, 打印
print(name)
# 定义⼀个变量,存储你的名字
name = '张三'
# 使用变量打印名字, 不需要加引号
print(name) # 张三
# 如果给 name 添加引号, 添加引号之后,输出的就是引号中的内容
print('name') # name
变量的命名规范
必须由字母、数字和下划线组成, 并且不能以数字开头
不能使用 Python 中的关键字作为变量名
# 关键字 :Python 自带的已经使用的标识符,具有特殊的作用
区分大小写
建议性的命名
驼峰命名法
# 大驼峰: 每个单词的首字母大写MyName
# 小驼峰: 第⼀个单词的首字母小写,其余单词的首字母大写 myName
下划线连接法
# Python 中的变量的定义使用的是下划线连接
# 每个单词之间使用下划线连接 my_name
见名知意
# name 姓名 age 年龄 height 身高
数据类型
整型(int),就是整数,即不带小数点的数
浮点型(float),就是小数
布尔类型(bool),只有两个值真True , 1;假 False0, 非 0 即真
复数类型 3 + 4i,不会用的
非数据类型
字符串(str): 使用引号引起来的就是字符串
列表(list) :[1, 2, 3, 4]
元组(tuple): (1, 2, 4, 4)
字典(dict) :{‘name’: ‘小明’, ‘age’: 18}
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
根据代码的需要, 将⼀种数据类型转换另⼀种数据类型
语法:变量 = 要转换为的类型(原数据)
注意点: 数据类型转换,不会改变原来的数据的类型, 会生成⼀个新的数据类型
int():将其他类型转换为int类型
float类型的数字转换为整型
整数类型的字符串转换为整型
float():将其他类型转换为浮点型
int类型转换为浮点型float(3) —> 3.0
**数字类型的字符串(整数类型和⼩数类型)**转换为浮点型
str():将其他类型转换为字符串类型
获取用户键盘输入的内容;使用函数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的类型
'''
输出使用的函数是 print() 函数
作用:将程序中的数据或者结果打印到控制台(屏幕)
print('hello world')
name ='⼩明'
print(name)
age = 18
print(name, age) # 可以使⽤逗号输出多个内容
格式化输出
# 在字符串中指定的位置,输出变量中存储的值
1. 在需要使用变量的地方,使用特殊符号去占位
2. 使用变量填充占位的数据
% 格式化输出占位符号
# 定义变量 姓名 年龄 身高
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)
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}%')
字符串格式化
字符串.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))
算数运算符
优先级: 先算谁,再算谁;不确定优先级,就使⽤ () () > ** > * / // % > + -
运算符 | 描述 | 实例(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 |
比较运算符
⽐较运算符得到都是 bool 类型
# > 、< 、 >= 、<=
== 判断两个数是否相等, 相等为 True, 不相等为 False
!= 判断两个数是否不相等, 不相等为 True, 相等为 False
逻辑运算符
逻辑运算符可以连接多个条件,在判断和循环中使用
and 逻辑与 和,并且 and 连接两个条件 , 都必须为 True , 整体结果才为 True , 即一假为假 (当第一个条件为False 的时候,第二个条件就不再判断)
or 逻辑或 或者,or 连接的两个条件 , 只要有一个条件为 True , 整体结果就为 True , 即 一真为真 (当第一个条件为 True的时候,第二个条件就不再判断)
not 逻辑非 取反 , not 后边的条件 , 如果本来是 True , 变为 False , 本来是 False , 变为 True
赋值运算符
赋值运算符 =, 作用就是将等号右边的值保存到等号左边的变量中
复合赋值运算符(将算术运算符和赋值运算符进行结合)
+= -= *= /= //= %=
a += b ===> a = a + b
运算符优先级
不需要刻意去记忆优先级,因为可以使用 () 改变优先级
在日常生活中说的 如果… ,否则… 这就是判断,在程序代码中需要使用if(如果) elif(如果) else(否则) 三个关键字来实现
在代码中有判断语句,代码不会全部执行,有一部分不会执行
只有如果的情况,如果条件成立,会执行的代码
基本语法
if 判断条件:
书写条件成立(为真),会执行的代码
书写条件成立(为真),会执行的代码
# 1. if 是一个关键字, 和后续的判断条件之间需要一个空格
# 2. 判断条件后边需要一个冒号,不要少了
# 3. 冒号之后,回车,代码需要缩进, 在 pycharm 中会自动进行缩进, 一般是 4 个空格 或者 一个 tab键
# 4. 所有在 if 代码下方的缩进中书写的代码,属于 if 语句的代码块, 判断条件为 True 的时候会执行
# 5. if 代码块中的代码,要么都执行,要么都不执行
# 6. if 代码块结束之后, 代码要顶格书写(不再有缩进), 表示是和 if 无关的代码
代码案例
# 1. 使用 input 获取用户的年龄
age = input('请输入你的年龄:')
# 2. 判断年龄是否满足 18 岁
if int(age) >= 18: # 字符串和 int 类型不能比大小, 先类型转换,再比大小
# 3. 如果年龄大于等于(满足)18 岁, 输出 '满 18 岁了,可以进入网吧为所欲为了'
print('满 18 岁了,可以进入网吧为所欲为了')
print('我和 if 判断没有关系,不管怎样,都会执行')
如果条件成立,做什么事;否则(条件不成立),做另一件事
基本语法
if 判断条件:
书写条件成立(为真),会执行的代码
书写条件成立(为真),会执行的代码
else:
书写条件不成立(为假),执行的代码
书写条件不成立(为假),执行的代码
# 1. else 是关键字, 后边需要冒号
# 2. 冒号之后回车,同样需要缩进
# 3. 处于 else 代码下方缩进中的内容,属于 else 的代码块
# 4. if 和 else 的代码块, 只会执行其中的一个
# 5. else 需要结合 if 使用
# 6. if else 之间不能有其他顶格书写的内容(不提 elif)
代码案例
# 1.使用 input 获取用户的年龄
age = input('请输入你的年龄:')
if int(age) >= 18: # 字符串和 int 类型不能比大小, 先类型转换,再比大小
# 3. 如果年龄大于等于(满足)18 岁, 输出 '满 18 岁了,可以进入网吧为所欲为了'
print('满 18 岁了,可以进入网吧为所欲为了')
# 4. 如果不满足, 输出 '不满 18 岁,回去写作业吧'
else:
print('不满 18 岁,回去写作业吧')
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('查无此人!')
如果某个判断条件有多个时,建议使用if elif else 结构
基本语法
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 都会进行判断,之间没有关联系
代码案例
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('不及格')
if 嵌套, 是指在一个 if(elif else) 中嵌套另一个 if
使用场景: 判断条件存在递进关系(只有第一个条件满足了,才会判断第二个条件)
基本语法
if 判断条件1:
判断条件1成立,执行的代码
if 判断条件2:
判断条件2成立,执行的代码
else:
判断条件2不成立,执行的代码
else:
判断条件1不成立,执行的代码
代码案例
案例一:
# 取款机取钱的过程, 假定 你的密码是: 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('验证码不正确,请重新输入')
案例:猜拳游戏
随机出拳
# 案例中需要电脑随机出拳,即随机出 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. 书写循环的判断条件
while 判断条件:
# 3. 需要重复执行的代码
# 4. 改变循环的初始条件(计数器)
# 1. while 是关键字
案例
案例一:
# 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)
无限循环的使用场景: 在书写循环的时候,不确定循环要执行多少次
无限循环的使用一般会在循环中添加一个 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('输了,不要放弃,再来一局')
for循环也可以让指定的代码重复执行(循环)
for循环也可以遍历容器中的数据
for 循环 也可以称为 for 遍历
基本的 for 循环语法
for 变量名 in 容器:
重复执行的代码
#1. for 和 in 都是关键字
#2. 容器中有多少个数据,循环会执⾏多少次(0 个数据,执⾏0 次, ..)
#3. 每次循环,会将容器中数据取出⼀个保存到 in 关键字前边的变量中
案例:
# 定义字符串
my_str = 'hello'
# 遍历字符串 字符串有5个字符,循环就会执行5次
for i in my_str: # 每次循环i的值为字符串的字符
print('我错了', i)
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)
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.使用单引号定义
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)
下标
下标(索引):就是指字符在字符串中的位置编号, 这个编号就是下标
这个编号⼀般来说都是从左到右进⾏编号的, 从 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
切片
切⽚: 可以获取字符串中多个字符(多个字符的下标是有规律的,等差数列)
# 切片会得到一个字符串,即可以获取字符串中的多个字符串
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
字符串查找方法 find
作⽤: 在字符串中查找是否存在 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
字符串替换方法 replace
作⽤: 将字符串中old_str 替换为 new_str
new_str: 替换为的内容
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
字符串的拆分 split
作⽤:将字符串按照 sep 进⾏分割(拆分)
sep: 字符串按照什么进⾏拆分, 默认是空⽩字符(空格, 换⾏\n, tab键\t)
max_split: 分割次数,⼀般不写, 全部分割
返回: 将⼀个字符串拆分为多个,存到列表中
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']
字符串的链接 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
列表 list, 是使⽤最多的⼀种容器(数据类型)
列表中可以存储多个数据, 每个数据之间使⽤逗号隔开
列表中可以存放任意类型的数据
定义
# 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]
下标和切片
列表⽀持下标和切⽚操作, 使⽤⽅法和字符串中的使⽤⽅法⼀致
区别: 列表的切⽚得到的是列表
list1 = ['小明', 18, 1.71, True]
# 获取第一个数据,名字
print(list1[0]) # 小明
# 获取最后一个数据,名字
print(list1[-1]) # True
# 获取第一第二个数据
print(list1[0:2]) # ['小明', 18]
# 列表支持len()求数据元素的个数
print(len(list1)) # 4
查找
查找:列表中数据下标的方法
在字符串中使⽤的 find ⽅法查找下标的,不存在返回的是 -1
在列表中没有 find ⽅法, 想要查找数据的下标,使⽤的 index() ⽅法
使⽤和 find ⽅法⼀样, 同时在字符串中也有 index ⽅法
区别: 返回, index() ⽅法,找到返回第⼀次出现的下标, 没有找到代码直接报错
查找:判断是否存在
判断容器中某个数据是否存在可以使⽤ in 关键字;如果存在返回 True ,如果不存在,返回False
查找:统计出现的次数
统计出现的次数,使⽤的是 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')
添加
尾部添加(最常⽤)
将数据添加到列表的尾部
返回: 返回的 None(关键字,空), ⼀般就不再使⽤ 变量 来保存返回的内容;想要查看添加后的列表,需要打印的是列表
指定下标位置添加
在指定的下标位置添加数据,如果指定的下标位置本来有数据, 原数据会后移
返回: 返回的 None(关键字,空), ⼀般就不再使⽤ 变量 来保存返回的内容,想要查看添加后的列表,需要打印的是列表
列表合并
将列表 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) # ['郭德纲', '于谦', '岳岳', '郭麒麟', '孙越', '烧饼', ['孙越', '烧饼']]
修改
修改列中的指定下标位置的数据
字符串中字符不能使⽤下标修改
# 定义列表
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 # 代码会报错
删除
在列表中删除中间的数据, 那么后⾯的数据会向前移动
根据下标删除
删除指定下标位置对应的数据
根据数据值删除
根据数据值删除
返回: None
注意: 如果要删除的数据不存在, 会报错
清空数据(⼀般不⽤)
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) # []
反转(倒置)
字符串中 反转倒置:字符串[::-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]
复制
将列表中的数据复制⼀份,给到⼀个新的列表
使⽤场景: 有⼀个列表, 需要修改操作列表中的数据, 修改之后, 需要和原数据进⾏对⽐,即原数据不能改
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)
排序
列表的排序, ⼀般来说都是对数字进⾏排序的
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]
列表嵌套
列表嵌套,列表中的内容还是列表;使⽤下标来确定获取的是什么类型的数据,然后确定可以继续进⾏什么操作
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', '⾃动化测试', '男']]
列表去重
列表去重:列表中存在多个数据, 需求, 去除列表中重复的数据
⽅式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)
元组: tuple, 元组的特点和列表⾮常相似
应用:在函数的传参或者返回值中使⽤, 保证数据不会被修改
元组中可以存放任意类型的数据
元组中可以存放任意多个数据
区别:
元组中的数据内容不能改变, 列表中的可以改变的
元组使⽤ (), 列表 使⽤ []
定义
常用方法
由于元组中的数据不能修改,所以只有查看的⽅法(以下⽅法的使⽤ 和列表中⼀样的)
# 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]) # ⼩王
# 1. 字典 dict, 字典中的数据是由键(key)值(value)对组成的(键表示数据的名字, 值就是具体的数据)
# 2. 在字典中⼀组键值对是⼀个数据, 多个键值对之间使⽤ 逗号隔开变量 = {key: value, key:value, ..}
# 3. ⼀个字典中的键是唯⼀的,不能重复的, 值可以是任意数据
# 4. 字典中的键 ⼀般都是 字符串,可以是数字, 不能是列表
定义
# 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
增加和修改
如果键已经存在,就是修改数据值
如果键不存在,就是添加数据(即添加键值对)
# 定义字典⼩明 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': '男'}
删除
删除指定键值对
清空
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) # {}
查询
根据键获取对应的值;字典中没有下标的概念,想要获取数据值,要使⽤ key(键)来获取使⽤ 字典[键]
使用 字典[键]
# 1. 如果键存在 返回键对应的数据值,
# 2.如果键不存在, 会报错
使⽤ 字典.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]) # 喝酒
字典的遍历
对 字典的键 进⾏遍历
for 变量 in 字典:
print(变量) # 变量就是字典的 key 键
for 变量 in 字典.keys(): # 字典.keys() 可以获取字典中所有的键
print(变量)
对 字典的值 进⾏遍历
for 变量 in 字典.values(): # 字典.values() 可以获取字典中所有的值
print(变量)
对 字典的键值对 进⾏遍历
# 变量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)
字符串,列表,元组 ⽀持加法运算
str1 = 'hello' + ' world' # 'hello world'
list1 = [1, 2] + [3, 4] # [1, 2, 3, 4]
tuple1 = (1, 2) + (3, 4) # (1, 2, 3, 4)
字符串,列表,元组, ⽀持 乘⼀个数字
'hello ' * 3 # ===> 'hello hello hello '
[1, 2] * 3 # ===> [1, 2, 1, 2, 1, 2]
(1, 2) * 3 # ===> (1, 2, 1, 2, 1, 2)
len() 在 容器中都可以使⽤
in 关键字在容器中都可以使⽤, 注意, 在字典中判断的是字典的键是否存在
函数就是把具有独立功能的代码块组织成一个小模块,在需要的时候调用
函数,通俗理解, 将多⾏代码写在⼀块,起个名字,在需要这多⾏的时候,可以直接使⽤这个名字来代替
函数好处: 减少代码的冗余(重复的代码不⽤多写), 提⾼程序的编写效率
语法
def 函数名():
函数中的代码
函数中的代码
# 1. def 是关键字, ⽤来定义函数的 define 的缩写
# 2. 函数名需要遵守标识符的规则
# 3. 处于 def 缩进中的代码,称为函数体
# 4. 函数定义的时候, 函数体中的代码不会执⾏, 在调⽤的时候才会执⾏
使⽤多⾏代码的时候, 称为函数调⽤
语法
函数名()
# 1. 函数调⽤的时候会执⾏函数体中代码
# 2. 函数调⽤的代码,要写在 函数体外边
def say_hello():
print('hello 1')
print('hello 2')
print('hello 3')
# 调⽤
say_hello()
say_hello()
say_hello()
⽂档注释的本质,还是注释, 只不过书写的位置和作⽤⽐较特殊.
在⼀个函数定义中调⽤另⼀个函数
def func1():
print(1)
print('func1')
print(2)
def func2():
print(3)
func1()
print(4)
print(5)
func2()
print(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)
# 目前,书写的函数正在定义的时候,如果有形参;那么,在调用的时候,必须传递实参值,个数要对应,否则会报错
函数的返回值,可以理解为是 函数整体执⾏的结果是什么
什么时候需要书写返回值: 函数中得到的数据在后续的代码中还要使⽤,这个时候就应该将这个数据作为返回值返回,以供后续使⽤
print() --->None
input() --->键盘输入的内容
type() --->类型
len() --->数据的长度(元素的个数)
在函数中想要将⼀个数据作为返回值 返回, 需要使⽤ 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 底层是如何处理数据的
在定义变量的时候 变量 = 数据值, Python 解释器会在内存中开辟两块空间
变量和数据都有自己的空间
⽇常简单理解:将数据保存到变量的内存中,本质是将数据的地址保存到变量对应的内存中
变量中存储数据地址的⾏为 就是引⽤ (变量引⽤了数据的地址, 简单说就是变量中存储数据), 存储的地址称为 引⽤地址
可以使⽤ id()来获取变量中的引⽤地址(即数据的地址),如果两个变量的 id() 获取的引⽤地址⼀样, 即代表着, 两个变量引⽤了同⼀个数据,是同⼀个数据
只有 赋值运算符=, 可以改变变量的引⽤(等号左边数据的引⽤)
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))
数据类型: int float bool str list tuple dict set
可变不可变是指: 数据所在的内存是否允许修改, 允许修改就是可变类型, 不允许修改就是不可变类型(不使⽤=, 变量引⽤的数据中的内容是否会变化,会变化是可变的, 不会变化是不可变的)
题目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]
题目2:
def func(list1):
list1 = [2, 1]
my_list = [1, 2]
func(my_list)
print(my_list)
① [1, 2] ②[2, 1]
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]
题⽬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)
# 组包
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)
变量: 根据变量的定义位置, 可以将变量分为局部变量和全局变量
局部变量
局部变量: 在函数内部(函数的缩进中)定义的变量,称为是局部变量
特点:
局部变量只能在当前函数内部使⽤, 不能在其他函数和函数外部使⽤
在不同函数中,可以定义名字相同的局部变量, 两者之间没有影响
⽣存周期(⽣命周期, 作⽤范围)–> 在哪能用 在函数被调⽤的时候,局部变量被创建;函数调⽤结束, 局部变量的值被销毁(删除), 不能使⽤;所以函数中的局部变量的值, 如果想要在函数外部使⽤, 需要使⽤ return 关键字, 将这个值进⾏返回
def func1():
num = 10 # num 就是局部变量
print(f'func1 函数中{num}')
def func2():
num = 100 # 可以在不同函数中定义名字相同的局部变量,没有影响
print(f'func2 函数中{num}')
func1() # 10
func2() # 100
func1() # 10
全局变量
定义位置: 在函数外部定义的变量, 称为是 全局变量
特点:
可以在任何函数中读取(获取) 全局变量的值
如何在函数中存在和全局变量名字相同的局部变量, 在函数中使⽤的是 局部变量的值(就近)
在函数内部想要修改全局变量的引⽤(数据值), 需要添加 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
函数中想要返回⼀个数据值,使⽤ 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)
形参的不同书写⽅法
函数传参的⽅式
位置传参:在函数调⽤的时候, 按照形参的顺序, 将实参值传递给形参
关键字传参:在函数调⽤的时候, 指定数据值给到那个形参
混合使⽤: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
缺省参数
缺省参数,默认参数
列表.pop()不写参数,删除最后⼀个
列表.sort(reverse=True)
定义⽅式:在函数定义的时候,给形参⼀个默认的数据值,这个形参就变为缺省参数;注意,缺省参数的书写要放在普通参数的后边
特点(好处):缺省参数,在函数调⽤的时候,可以传递实参值,也可以不传递实参值;如果传参,使⽤的就是传递的实参值;如果不传参,使⽤的就是默认值
def show_info(name, sex='保密'):
print(name, sex)
show_info('⼩王')
show_info('⼩王', '男')
当我们在书写函数的时候,不确定参数的具体个数时,可以使⽤不定⻓参数
不定⻓位置参数(不定⻓元组参数)
不定⻓关键字参数(不定⻓字典参数)
书写:在普通参数的前边,加上 两个 *,这个参数就变为不定⻓关键字参数
特点:这个形参可以接收 任意多个关键字传参的数据
数据类型:形参的类型是 字典
注意:不定⻓关键字参数,要写在所有参数的最后边
⼀般写法:不定⻓关键字参数的名字为 kwargs,即(**kwargs),keyword arguments
完整的参数顺序
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)
不定⻓参数[函数调⽤时的拆包]
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)
# 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='_*_')
匿名函数: 就是使⽤ lambda 关键字定义的函数;⼀般称为使⽤def 关键字定义的函数为 标准函数
匿名函数只能书写⼀⾏代码
匿名函数的返回值不需要 return,⼀⾏代码(表达式) 的结果就是返回值
使用场景:作为函数的参数,这个函数⽐较简单,值使用⼀次,没有必要使⽤ def 定义
语法
lambda 参数: ⼀⾏代码 # 这⼀⾏代码,称为是表达式
# 匿名函数⼀般不需要我们主动的调⽤, ⼀般作为函数的参数使⽤的
# 我们在学习阶段为了查看匿名函数定义的是否正确,可以调⽤
# 1, 在定义的时候 ,将匿名函数的引⽤保存到⼀个变量中
变量 = lambda 参数: ⼀⾏代码
# 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))
练习
# 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))
匿名函数作为函数的参数[列表中的字典排序]
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)
字符串比大小
字符比大小,是⽐较字符对应的 ASCII 码值
A < Z < a < z
ord(字符):获取字符对应的 ASCII 的值
chr(ASCII 值):获取对应的字符
字符串比大小:对应下标位置字符的大小, 直到比出大小, 如果全部比完了,还没有比出大小,就是相等
面向对象是一种编程思想(写代码的套路)
编程思想: 1. 面向过程 2. 面向对象
以上两种都属于写代码的套路(⽅法),最终⽬的都是为了将代码书写出来,只不过过程和思考⽅法不太⼀样
⾯向对象的核⼼思想是:找⼀个对象去帮我们处理事情。在程序代码中,对象是由 类 创建的
类和对象,是⾯向对象编程思想中⾮常重要的两个概念
类
抽象的概念:对 多个 特征和⾏为相同或者相似事物的统称
泛指的(指代多个,⽽不是具体的⼀个)
对象
苹果---> 类
红苹果----> 类
张三嘴⾥正在吃的那个苹果---> 对象
类的抽象,其实就是找到类的 类名、属性和⽅法
类名:⼈类(Person, People)
属性:名字(name), 年龄(age), 身⾼(height)
⽅法:跑步(run) 吃(eat)
定义类
先定义简单的类,不包含属性,在 python 中定义类需要使⽤关键字 class
⽅法: ⽅法的本质是在类中定义的函数,只不过,第⼀个参数是 self
class 类名:
# 在缩进中书写的内容,都是类中的代码
def ⽅法名(self): # 就是⼀个⽅法
pass
创建对象
创建对象是使⽤ 类名() 进⾏创建
类名() # 创建⼀个对象, 这个对象在后续不能使⽤
# 创建的对象想要在后续的代码中继续使⽤, 需要使⽤⼀个变量,将这个对象保存起来
变量 = 类名() # 这个变量中保存的是对象的地址, ⼀般可以成为这个变量为对象
# ⼀个类可以创建多个对象, 只要出现 类名() 就是创建⼀个对象,每个对象的地址是不⼀样的
调⽤⽅法
对象.方法名()
案例实现
# 需求:⼩猫爱吃⻥,⼩猫要喝⽔
# 类名: 猫类 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() # 是
class Cat:
# 在缩进中书写 ⽅法
def eat(self):
# self 会⾃动出现,暂不管
print('⼩猫爱吃⻥..')
black_cat.eat()
添加属性
类内部添加
在内部⽅法中,self 是对象,在类中添加属性⼀般写在_init__ ⽅法中
类外部添加(一般不使用)
获取属性
类内部
在内部⽅法中,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()
python 中有⼀类⽅法,以两个下划线开头,两个下划线结尾,并且在满⾜某个条件的情况下, 会⾃动调⽤,这类⽅法称为魔法⽅法
学习:
什么情况下⾃动调⽤
有什么⽤, ⽤在哪
书写的注意事项
__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()
__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)
__del__ ⽅法
[了解]
__init__
⽅法,创建对象之后,会⾃动调⽤(构造⽅法)
__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('代码运行结束')
案例
案例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)
计算机的⽂件,就是存储在某种⻓期储存设备上的⼀段数据
作⽤: 将数据⻓期保存下来,在需要的时候使⽤
- 计算机只认识⼆进制(0 1)
- ⽂件中存储的数据都是以⼆进制(0 1) 的形式去存储的
可以根据⽂件中的⼆进制内容,能否使⽤记事本软件将其转换为⽂字,将⽂件分为两种: ⽂本⽂件和⼆进制⽂件
⽂本⽂件:
能够使⽤记事本软件打开(能够使⽤记事本转换为⽂字)
txt, md, py , html, css, js , json
⼆进制⽂件:
打开⽂件,读或者写⽂件,关闭⽂件
打开⽂件
将⽂件从磁盘(硬盘) 中 读取到内存中
语法:
读或者写⽂件
写文件:
向⽂件中写⼊指定的内容。前提:⽂件的打开⽅式是 w 或者 a
返回值: 写⼊⽂件的字符数,⼀般不关注
注意 w ⽅式打开⽂件:
⽂件不存在,会直接创建⽂件
⽂件存在,会覆盖原⽂件(将原⽂件中的内容清空)
# 1. 打开⽂件
f = open('a.txt', 'w', encoding='utf-8')
# 2. 写⽂件
f.write('好好学习\n')
f.write('天天向上')
# 3. 关闭⽂件
f.close()
读文件:
将⽂件中的内容读取出来。前提:⽂件的打开⽅式需要是 r
参数 n 表示读取多少个字符;⼀般不写,表示读取全部内容
返回值: 读取到的⽂件内容,类型 字符串
# 1. 打开⽂件
f = open('a.txt', 'r', encoding='utf-8')
# 2. 读⽂件
buf = f.read() # ⽬前只是打印读取的内容,可以做其它的事
print(buf)
# 3. 关闭⽂件
f.close()
关闭⽂件
关闭⽂件: 将⽂件占⽤的资源进⾏清理,同时会保存⽂件,⽂件关闭之后,这个⽂件对象就不能使⽤了
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')
按⾏读取⽂件:⼀次读取⼀⾏内容
⽂件对象.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
json ⽂件 也是⼀个⽂本⽂件,就可以直接使⽤read()和write() ⽅法去操作⽂件,只是使⽤这两个⽅法不⽅便;所以对 json ⽂件有⾃⼰独特的读取和写⼊的⽅法。
常⽤在在做测试的时候,将测试数据定义为 json ⽂件格式,使⽤代码读取 json ⽂件,即读取测试数据,进⾏传参(参数化)
json 的介绍
json 基于⽂本,独⽴于语⾔的轻量级的数据交换格式
基于⽂本;是⼀个文本文件;不能包含图⽚、⾳视频等
独⽴于语⾔;不是某个语⾔特有的,每种编程语⾔都可以使⽤的
轻量级;相同的数据,和其他格式相⽐,占⽤的⼤⼩⽐较⼩
数据交换格式;后端程序员给前端的数据 (json、html、xml)
json ⽂件的语法
json ⽂件的书写
我叫⼩明,我今年 18 岁,性别男, 爱好 听歌, 游戏,购物,吃饭,睡觉,打⾖⾖;我的居住地址为 国家中国, 城市上海
{
"name": "小明",
"age": 18,
"isMen": true,
"like": [
"听歌",
"游戏",
"购物",
"吃饭",
"睡觉",
"打⾖⾖"
],
"address": {
"country": "中国",
"city": "上海"
}
}
读取 json ⽂件
导包 import json
读打开⽂件
读⽂件 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"))
练习1
我叫⼩明,我今年 18 岁,性别男, 爱好 听歌, 游戏,吃饭,睡觉,打⾖⾖,我的居住地址为 国家中国, 城市上海.
我叫⼩红,我今年 17 岁,性别⼥, 爱好 听歌, 学习,购物我的居住地址为 国家 中国, 城市北京
[
{
"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'))
练习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())
json 文件的写入
**⽂件对象.write(字符串)**不能直接将 Python 的列表和字典作为参数传递;想要将Python中的数据类型存为json⽂件,需要使⽤ json
提供的⽅法,不再使⽤ write
步骤:
导包:import json
写(w):⽅式打开⽂件
写⼊: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 关键字)
捕获异常:程序遇到异常,默认动作是终⽌代码程序的执⾏,遇⻅异常之后,可以使⽤异常捕获,让程序代码继续运⾏,不会终⽌运⾏(重点)
基本语法
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('发⽣了异常, 请输⼊正确的数字..')
捕获多个指定类型的异常
好处:可以针对不同的异常错误,进⾏单独的代码处理
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')
异常捕获的完整版本
完整版本中的内容,不是说每⼀次都要全部书写,根据⾃⼰的需要,去选择其中的进⾏使⽤
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('不管有没有发⽣异常,我都会执⾏')
异常传递是 Python 中已经实现好了,我们不需要操作,我们知道异常会进行传递
异常传递:在函数嵌套调⽤的过程中,被调⽤的函数,发⽣了异常,如果没有捕获,会将这个异常向外层传递,如果传到最外层还没有捕获,才报错
def func1():
num = 10 / 0
print(num)
def func2():
print('1111')
func1()
try:
func2()
except Exception as e:
print(f'错误信息为{e}')
方法一
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()
方法三[了解,基本不用]
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))
```
在导⼊模块的时候,会先在当前⽬录中找模块,找到就直接使⽤;没有找到回去系统的⽬录中进⾏查找,找到直接使⽤;没有找到就报错
注意点:定义代码⽂件的时候,你的代码名字不能和你要导⼊的模块名字相同
__name__
的作用1. 每个代码⽂件都是⼀个模块
2. 在导⼊模块的时候, 会执⾏模块中的代码(三种⽅法都会)
3. __name__ 变量
3.1 __name__ 变量 是 python 解释器⾃动维护的变量
3.2 __name__ 变量,如果代码是直接运⾏, 值是 "__main__"
3.3 __name__ 变量, 如果代码是被导⼊执⾏, 值是 模块名(即代码⽂件名)
在代码⽂件中, 在被导⼊时不想被执⾏的代码,可以写在 if __name__ == "__main__": 代码的缩进中
在 Python 中,包是⼀个⽬录,只不过在这个⽬录存在⼀个⽂件__init__.py
(可以是空的)
将功能相近或者相似的代码放在⼀起的.
在 Python 中使⽤的时候,不需要可以是区分是包还是模块,使⽤⽅式是⼀样的
random 模块 (单个代码⽂件)
json 包(⽬录)
unittest 包(⽬录)
框架
说明:1.框架英⽂单词framework 2. 为解决⼀类事情的功能集合
需要按照框架的规定(套路)去书写代码
什么是UnitTest框架?
概念:UnitTest是Python⾃带的⼀个单元测试框架,⽤它来做单元测试
⾃带的框架(官⽅):不需要单外安装, 只要安装了 Python,就可以使⽤ random, json, os, time
第三⽅框架:想要使⽤ 需要先安装后使⽤(pytest), selenium, appium, requests
单元测试框架:主要⽤来做单元测试,⼀般单元测试是开发做的
对于测试来说,unittest 框架的作⽤是⾃动化脚本(⽤例代码)执⾏框架(使⽤unittest框架来管理运⾏多个测试⽤例的)
为什么使⽤UnitTest框架?
TestCase(最核⼼的模块)
TestCase(测试⽤例),注意这个测试⽤例是 unittest 框架的组成部分,不是⼿⼯和⾃动化中我们所说的⽤例(TestCase)
主要作⽤:每个 TestCase(测试⽤例) 都是⼀个代码⽂件,在这个代码⽂件中来书写 真正的⽤例代码
TestSuite
TestSuite(测试套件),⽤来管理、组装(打包)多个TestCase(测试⽤例)的
TestRunner
TestRunner(测试运行),TestSuite(测试套件)的
TestLoader
TestLoader(测试加载),功能是对 TestSuite(测试套件) 功能的补充,管理组装(打包)多个 TestCase(测试⽤例) 的
Fixture
Fixture(测试夹具),书写在 TestCase(测试⽤例)代码中;是⼀个代码结构,可以在每个⽅法执⾏前后都会执⾏的内容
举例:
登录的测试⽤例, 每个⽤例中重复的代码就可以写在Fixture 代码结构中, 只写⼀遍, 但每次⽤例⽅法的执⾏,都会执⾏ Fixture 中的代码
1. 打开浏览器
2. 输⼊⽹址
是⼀个代码⽂件,在代码⽂件中来书写真正的⽤例代码
代码⽂件的名字必须按照标识符的规则来书写(可以将代码的作⽤在⽂件的开头使⽤注释说明)
步骤
1. 导包 (unittest)
2. ⾃定义测试类
3. 在测试类中书写测试⽅法
4. 执⾏⽤例
代码
"""
代码的⽬的: 学习 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:代码⽂件的命名不规范
代码⽂件的名字以数字开头
代码⽂件名字中有空格
代码⽂件名字有中⽂
其他的特殊符号(数字、字⺟、下划线组成,不能以数字开头)
问题2:代码运⾏没有结果
右键运⾏没有 unittests for 的提示,出现的问题
解决⽅案:1. 重新新建⼀个代码⽂件,将写好的代码复制进去 2. 删除已有的运⾏⽅式
问题3:没有找到⽤例
测试⽅法中不是以 test开头的,或者单词写错了
TestSuite(测试套件): 管理、打包、组装TestCase(测试⽤例)⽂件的
TestRunner(测试执⾏): 执⾏TestSuite(套件)
步骤
1. 导包(unittest)
2. 实例化(创建对象)套件对象
3. 使⽤套件对象添加⽤例⽅法
4. 实例化运⾏对象
5. 使⽤运⾏对象去执⾏套件对象
代码
TestSuite(测试套件):是⽤来管理多个 TestCase(测试⽤例)的,先创建多个TestCase(测试⽤例)⽂件
"""
学习 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)
"""
学习 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)
练习
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)
TestLoader (测试加载),作用和 TestSuite 的作用是一样的, 对 TestSuite 功能的补充,用来组装测试用例的
比如: 如果 TestCase 的代码文件有很多, (10 20, 30 )
使用步骤
代码实现
在一个项目中 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)
Fixture(测试夹具) 是一种代码结构;在某些特定的情况下会自动执行
方法级别
在每个测试方法(用例代码) 执行前后都会自动调用的结构
# 方法执行之前
def setUp(self):
每个测试方法执行之前都会执行
pass
# 方法执行之后
def tearDown(self):
每个测试方法执行之后都会执行
pass
类级别
在每个测试类中所有方法执行前后 都会自动调用的结构(在整个类中 执行之前执行之后个一次)
# 类级别的Fixture 方法, 是一个 类方法
# 类中所有方法之前
@classmethod
def setUpClass(cls):
pass
# 类中所有方法之后
@classmethod
def tearDownClass(cls):
pass
模块级别[了解]
模块:代码文件在每个代码文件执行前后执行的代码结构
# 模块级别的需要写在类的外边直接定义函数即可
# 代码文件之前
def setUpModule():
pass
# 代码文件之后
def tearDownModule():pass
案例
"""
1. 打开浏览器(整个测试过程中就打开一次浏览器) 类级别
2. 输入网址(每个测试方法都需要一次) 方法级别
3. 输入用户名密码验证码点击登录(不同的测试数据) 测试方法
4. 关闭当前页面(每个测试方法都需要一次) 方法级别
5. 关闭浏览器(整个测试过程中就关闭一次浏览器) 类级别
"""
# 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')
让程序代替人工自动的判断预期结果和实际结果是否相符
断言的结果有两种: (在 unittest 中使用断言, 都需要通过 self.断言方法 来试验)
assertEqual
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'))
在测试方法中,使用 变量 来代替具体的测试数据,然后使用传参的方法将测试数据传递给方法的变量
好处:相似的代码不需要多次书
工作中场景:
安装插件
unittest 框架本身是不支持参数化,想要使用参数化,需要安装插件来完成
联网安装(在 cmd 窗口安装 或者 ) pip install parameterized
参数化代码
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))
参数化代码
[
{
"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))
对于一些未完成的或者不满足测试条件的测试函数和测试类,不想执行,可以使用跳过使用方法,装饰器完成,代码书写在 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')
自带的测试报告
只有单独运行 TestCase 的代码,才会生成测试报告
第三方的测试报告
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(套件对象)