- 以下是软件测试小白关于python基础知识的学习记录。
一、Python介绍
- python 主要版本:python 2、python 3(主流)。
- 语言分类:
- 编译型语言(c、c++)
- 需要编译器,对源代码进行编译最终生成可执行文件。
- 先编译再执行。
- 解释型语言(python)
- 需要解释器,对源代码逐行解释。
- 边解释边执行。
二、基础语法
2.1 注释
- 【说明】注释是对代码进行解释说明的文字,不会被执行,便于理解代码。
- 【分类】
- 单行注释:只对单行内容起作用,以
#开头,快捷键ctrl+/。 - 多行注释:注释的内容可以换行书写,格式为
'''注释内容'''或"""注释内容"""。
- 单行注释:只对单行内容起作用,以
2.2 标识符
- 【说明】标识符是用户编程时使用的名字,用于给变量、函数、类命名。
- 【规则】
- 由字母、数字和下划线组成。
- 不能使用数字开头。
- 不能使用python内置关键字。
- 严格区分大小写。
- 不建议使用中文。
2.3 变量
- 【说明】变量是用来保存数据的,变量必须先定义再使用。
- 【语法】
变量名=数据值 - 【使用】直接使用变量名即可。
# 定义变量保存名字和年龄
name = "张三"
age = 18
print(name,age)
- 变量命名规范
- 要遵循标识的规则。
- 命名习惯
- 驼峰命名法:
- 大驼峰:每个单词的首字母大写,例如:MyName;
- 小驼峰:第一个单词的首字母小写,其余单词首字母大写,例如:myName;
- 下划线连接:单词与单词之间使用下划线连接。
- 驼峰命名法:
2.4 数据类型
- 数字型
- 整型(int)
- 浮点型(float)
- 布尔型(bool)
- 非数字型
- 字符串(string)
- 列表(list[])
- 元组(tuple())
- 集合(set{})
- 字典(dict{键值对})
# int 整型,整数
age = 18
# float 浮点型,小数
num = 2.345
# bool 布尔型,关键字True(真)、False(假)
isRight = True
print(type(age),type(num),type(isRight))
- 数据类型转换
- 【语法】
变量 = 要转换的数据类型(原数据),例如nums = int(num) - 数据类型转换不会改变原数据的类型,是生成一个新数据
- 【语法】
num = 2.456
print(type(num))
nums = int(num)
print(nums,type(nums))
int(2.45) # 浮点型转整型,去尾。
int('134') # 字符型(只能是整数数字类型)转整型
float(12) # 整型转浮点型
float('12') # 字符型(只能是数字类型)转浮点型
float('1.234')
str(12) # 整型转字符型
str(1.234) # 浮点型转字符型
2.5 输入
- 使用函数
input(),获取键盘的输入信息。 - 【语法】
变量 = input('提示信息')- 代码从上至下执行,当代码执行遇到 input 时会中断执行,等待键盘输入,直到输入完成再次执行。
- 在输入过程中,使用回车键表示此次输入结束。
- 使用 input 函数获取的内容,都是字符串。
name = input('请输入您的名字:')
age = input('请输入您的年龄:')
print(name,age)
2.6 输出
- 格式化输出
- 字符串.format()
- 字符串中需要使用变量的地方,用
{}进行占位。 - 在format()括号内,按占位顺序,将变量填写。
- 字符串中需要使用变量的地方,用
name = '张三'
age = 18
sex = '男'
print('姓名:{},年龄:{},性别:{}'.format(name,age,sex))
- F-string
- python 3.6版本以后才可以使用。
- 在字符串前面加上
f或F。 - 字符串中需要使用变量的地方,用
{}进行占位。 - 将变量直接写在
{}占位符中。
name = '张三'
age = 18
sex = '男'
print(f'姓名:{name},年龄:{age},性别:{sex}')
2.7 转义字符
\n:表示换行\t:表示制表符- print 函数中默认有一个 end=‘\n’ ,所有每个print结束后会输出一个换行。
print('张三18')
print('张三18',end=' ')
print('\n张三\n18')
print('张三\t18')
2.8 运算符
- 算术运算符:
- 优先级(由高到低):
() 高于 **,* 高于 /,//,% 高于 +,- - 加、减、乘、除:
+ - * / - 求商:
// - 取余:
%
- 优先级(由高到低):
- 比较运算符:
- 只能是相同类型之间进⾏⽐较 (数字和字符串之间不能使⽤)
- 结果返回的值是bool型,要么为True,要么为False。
- 相等、不相等:
== != - 大于、大于等于、小于、小于等于:
> >= < <=
- 赋值运算符:
= - 复合赋值运算符:
- 加后赋值:
+= - 减后赋值:
-= - 乘后赋值:
*= - 除后赋值:
/= - 取余后赋值:
%=
- 加后赋值:
- 逻辑运算符:
- 与:
and,连接两个条件, 只有都为 True, 结果才为 True, ⼀假为假。 - 或:
or,连接两个条件, 只要⼀个条件 为 True, 结果就为 True, ⼀真为真。 - 非:
not,取反,本来是 True, 加上 not 变为False。
- 与:
2.9 练习
- 编写一个Python程序,完成以下任务:
- 输入:
- 从用户处获取姓名(name)。
- 从用户处获取年龄(age),使用input()函数,并转换为整型。
- 从用户处获取身高(height),使用input()函数,并转换为浮点型。
- 从用户处获取体重(weight),使用input()函数,并转换为浮点型。
- 计算:
- 计算用户的BMI(Body Mass Index,身体质量指数),公式为:BMI = weight / (height ** 2)。
- 根据BMI值判断用户的健康状态:
- BMI < 18.5: 体重过轻
- 18.5 <= BMI < 24.9: 体重正常
- 25 <= BMI < 29.9: 体重超重
- BMI >= 30: 肥胖
- 输出:
- 使用format()方法格式化输出用户的姓名、年龄、身高、体重、BMI值、健康状态。
- 使用F-string方法再次输出上述信息。
- 答:
# 输入
name = input('请输入你的姓名:')
age = int(input('请输入你的年龄:'))
height = float(input('请输入你的身高/米:'))
weight = float(input('请输入你的体重/kg:'))
# 计算
BMI = weight / (height ** 2)
if BMI < 18.5:
health_status = '体重过轻'
elif 18.5 <= BMI < 24.9:
health_status = '体重正常'
elif 25 <= BMI < 29.9:
health_status = '体重超重'
else:
health_status = '肥胖'
# 输出
print('你的信息如下:\n姓名:{}\n年龄:{}\n身高:{}米\n体重:{}kg\nBMI值:{}\n健康状态:{}'.format(name,age,height,weight,BMI,health_status))
print(f'你的信息如下:\n姓名:{name}\n年龄:{age}\n身高:{height}米\n体重:{weight}kg\nBMI值:{BMI:.2f}\n健康状态:{health_status}')
三、逻辑控制语句
3.1 条件分支语句
- if…else 结构
if 判断条件:
判断条件成⽴,执⾏的代码
else:
判断条件不成⽴,执⾏的代码
- 每个条件后面要使用冒号 :,表示接下来是满足条件后要执行的语句块。
- 使用缩进来划分语句块,相同缩进数的语句在一起组成一个语句块。
- else 不能单独使⽤ 必须配合 if 使⽤, 并且 else 要和 if 对齐。
- if…elif…else 结构
if 判断条件1:
判断条件成⽴,执⾏的代码
elif 判断条件2: # 判断条件1不成立,执行判断条件2,依次往下执行
判断条件成立,执行的代码
......
else:
判断条件不成⽴,执⾏的代码
- if 嵌套
- 把 if…elif…else 结构放在另外一个 if…elif…else 结构中。
if 条件1:
判断条件成⽴,执⾏的代码
if 条件2:
判断条件成⽴,执⾏的代码
elif 条件3:
判断条件成⽴,执⾏的代码
else:
判断条件不成⽴,执⾏的代码
elif 条件4:
判断条件成⽴,执⾏的代码
else:
判断条件不成⽴,执⾏的代码
- 【练习】
- 1.定义两个整数变量python_score、c_score,使⽤ input 获取成绩 编写代码判断成绩
- 2.要求只要有⼀⻔成绩 > 60 分就输出合格
python_score = int(input('请输入你的python成绩:'))
c_score = int(input('请输入你的c语言成绩:'))
if python_score > 60 or c_score > 60:
print('合格')
else:
print('不合格')
- 1.定义 score 变量记录考试分数
- 2.如果分数是 ⼤于等于 90分 显示 优
- 3.如果分数是 ⼤于等于 80分 并且 ⼩于 90分 显示 良
- 4.如果分数是 ⼤于等于 70分 并且 ⼩于 80分 显示 中
- 5.如果分数是 ⼤于等于 60分 并且 ⼩于 70分 显示 差
- 6.其它分数显示 不及格
score = int(input('请输入考试成绩:'))
if score>=90:
print('优')
elif 90 > score >=80:
print('良')
elif 80 > score >=70:
print('中')
elif 70 > score >= 60:
print('差')
else:
print('不及格')
- 假定某⽹站⽤户名固定为 ‘admin’, 密码固定为’123456’, 验证码 固定为 ‘8888’
- 1.获取⽤户输⼊的⽤户名,密码和验证码
- 2.先判断验证码是否正确,如果正确打印输出验证码正确,再判断⽤户名和密码是否正确
- 3.如果验证吗不正确,直接输出 验证码不正确,请重新输⼊
user_name = input('请输入用户名:')
password = input('请输入密码:')
check_number = input('请输入验证码:')
if check_number == '8888':
if user_name == 'admin' and password == '123456':
print(f'验证通过,用户{user_name}')
else:
print('用户名错误或密码错误')
else:
print('验证码不正确,请重新输⼊')
- 石头剪刀布游戏,玩家从控制台输入石头、剪刀、布,程序随机出拳,判断胜负。
import random
player = int(input('请出拳,石头:1\t剪刀:2\t布:3'))
computer = random.randint(1,3)
# 玩家胜利
if (player == 1 and computer == 2) or (player == 2 and computer == 3) or (player ==3 and computer == 1) :
print('玩家胜利')
# 平局
elif player == computer:
print('平局')
else:
print('电脑胜利')
3.2 循环语句 while、for
- while 循环
- 处于 while 缩进中的代码,称为是 while 的循环体
while 判断条件:
判断条件成立执行的代码
......
- 例:
i = 0 # 计数器
while i<5:
print(i)
i = i+1
# 打印5次结果,0,1,2,3,4
- 死循环和无限循环
- 死循环和⽆限循环,在程序执⾏层⾯上看起来是⼀样的, 都是代码⼀直执⾏不能停⽌。
- ⽆限循环中,⼀般会存在⼀个 if 判断语句, 当这个判断语句的条件成⽴, 执⾏ break 语句,来终⽌循环。
- 关键字 break: 当程序代码执⾏遇到 break, break 所在的循环就会被终⽌执⾏。(终⽌循环)
- 关键字 continue: 当程序代码执⾏遇到 continue, continue 后续的代码不执⾏,但是会继续下⼀次的循环(结束本次循环,继续下⼀次循环)。
- break 和 continue 只能⽤在循环中
# 死循环
i = 0
while True:
print(i,'这是一个死循环')
i = i+1
# 无限循环版石头剪刀布游戏
import random
while True:
player = int(input('请出拳,石头:1\t剪刀:2\t布:3'))
computer = random.randint(1,3)
# 玩家胜利
if (player == 1 and computer == 2) or (player == 2 and computer == 3) or (player ==3 and computer == 1) :
print('玩家胜利')
elif player == computer:
print('平局')
else:
print('电脑胜利')
is_again = input('是否继续:yes/no')
# 如果玩家输入为no退出游戏,否则继续
if is_again == 'no':
break
- 【练习】求 1- 100 之间的累加和
i = 1
sum = 0
while i<=100:
sum += i # 把每次i值加
i = i+1 # 每执行一次i值加1
print(sum)
- for 循环
- for 循环也称为是 for 遍历, 也可以做指定次数的循环。
- 遍历: 是从容器中将数据逐个取出的过程。
- 容器: 字符串/列表/元组/字典。
# for循环遍历字符串
str = 'python_for_循环'
for i in str:
print(i)
# for循环遍历列表
num = [0,1,2,3,4,5]
for i in num:
print(i)
# for循环指定次数的循环
# range(n) 可以⽣成 [0, n) 的整数的序列, 不包含 n
# 指定循环5次
for i in range(5):
print(f'第{i+1}次循环')
# 使用for循环实现1-100的累加和
sum = 0
for i in range(101):
sum += i
print(sum)
3.3 练习
- 按以下需求设计一个程序:
- 提示⽤户输⼊登录系统的⽤户名和密码。
- 校验⽤户名和密码是否正确(正确的⽤户名:admin、密码:123456)。
- 如果⽤户名和密码都正确,打印“登录成功!”,并结束程序。
- 如果⽤户名或密码错误,打印“⽤户名或密码错误!”,提示⽤户继续输⼊⽤户名和密码登录
- 如果⽤户输⼊的⽤户名为“exit”,则退出程序。
while True:
user_name = input('请输入用户名,exit退出:')
if user_name == 'exit':
break
password = input('请输入密码:')
if user_name == 'admin' and password == '123456':
print('登录成功')
break
else:
print('用户名或密码错误,请重新输入!')
四、容器
4.1 字符串
- 在Python中使用单引号、双引号或三引号标识的内容,就是字符串。Python 不支持单字符类型,单字符在 Python 中也是作为一个字符串使用。
- 创建字符串
str1 = '123'
# 如果字符串包含单引号,就不能使用单引号标识
str2 = "'python'"
print(str2)
# 如果字符串包含双引号,就不能使用双引号标识
str3 = '"python"'
print(str3)
- 转义字符
- 在需要在字符中使用特殊字符时,python 用反斜杠 \ 转义字符。
- 续行符:
行尾\ - 反斜杠符:
\\ - 单引号:
\' - 双引号:
\" - 换行:
\n - 横向制表符:
\t - 取消转义:在字符串的前边加上 r"", 字符串中的 \ 就不会进行转义。
- 下标(索引)
- 下标用来标识容器中元素的位置,一般使用的正数标,从0开始。
- 通过下标来获取容器中具体位置的元素:
变量[下标]。 - python 中是支持负数下标, -1 表示最后一个位置的数据。
str = 'python'
# P:0 y:1 t:2 h:3 o:4 n:5
# P:-6 y:-5 t:-4 h:-3 o:-2 n:-1
print(str[0])
print(str[-6])
- 截取
- 使用截取操作, 可以一次性获取容器中的多个数据(多个数据之间存在一定的规律,数据的下标是等差数列)。
- 语法:
变量[start:end:step]- start:表示开始元素的下标。
- end:表示结束元素的下标,不包含结束元素。
- step: 表示相邻元素的间隔长度。
str = 'python'
# P:0 y:1 t:2 h:3 o:4 n:5
# P:-6 y:-5 t:-4 h:-3 o:-2 n:-1
# 1.获取tho字母,start=2,end=5,step=1
print(str[2:5])
print(str[-4:-1])
# 2.获取'pto'字母,start=0,end=5,step=2
print(str[0:5:2])
print(str[-6:-1:2])
# 3.获取thon字母
print(str[2:])
print(str[-4:])
# 逆序输出字符串
print(str[::-1])
- 字符串查找方法 find()
- 语法:
变量a.find(变量b) - 在变量a中查找是否具有匹配变量b的字符串,如果存在,返回第一次出现的下标,不存在则返回-1。
- 语法:
str = 'python'
str1 = 'th'
str_index = str.find(str1)
if str_index == -1:
print(f'{str1}字符串不存在')
else:
print(f'{str1}存在,第一次出现的位置{str_index}')
- 字符串替换 replace()
- 语法:
变量.replace(old,new,count) - old:表示要替换的字符串
- new:表示替换的字符串
- count:表示替换的次数,不写默认全部替换。
- 替换并不会改变原来的字符串。
- 语法:
str = '张三今年18,李四今年18'
str1 = '20'
str_replace = str.replace('18',str1)
print(str_replace)
str_replace = str.replace('18',str1,1)
print(str_replace)
- 字符串拆分 split()
- 语法:
变量.split('分隔字符') - 分隔字符:按指定的分隔字符将字符串分隔。
- 返回结果为列表,列表中的元素就是分隔后的字符串。
- 语法:
str = 'python is\tnot easy to learn at all'
# 默认按空白字符分隔
str_list = str.split()
print(str_list)
# 空格分隔
str_list = str.split(' ')
print(str_list)
# 指定字符分隔
str_list = str.split('easy')
print(str_list)
- 字符串连接 join()
- 语法:
字符串.join(容器) - 容器一般是列表 , 将字符串插入到列表相邻的两个数据之间,组成新的字符串。
- 注意点: 列表中的数据必须都是字符串才可以。
- 语法:
str_list = ['python', 'is', 'not', 'easy', 'to', 'learn', 'at', 'all']
# 使用空格连接列表元素组成字符串
str = ' '.join(str_list)
print(str)
4.2 列表
- 列表中的元素类型可以不同,可以是数字、字符串、嵌套列表。
- 列表写在方括号
[]内,元素之间使用逗号隔开。 - 和字符串一样,列表也可以被索引和截取,列表被截取后返回一个包含所需元素的新列表。
- 定义列表
变量 = list()变量 = []
- 列表查询
- index()方法
- 索引查找,找到匹配元素,返回其索引。
- 和find()一样只返回第一次查找到的位置。
- count()方法
- 统计指定元素在列表中出现的次数。
- index()方法
str_list1 = ['python',1,2,2,4,2]
# 使用index()查找2的位置
print(str_list1.index(2))
# count()统计2出现的次数
print(str_list1.count(2))
- 添加数据append()
- 语法:
list.append(数据) - 向列表的末尾添加一个新元素。
- 无返回值。
- 语法:
- 删除数据方法pop()
- 语法:
list.pop(index) - 根据下标删除列表中的数据。
- 返回删除元素的值。
- 语法:
# 定义空列表
list1 = []
# 添加元素ABC
list1.append('A')
list1.append('B')
list1.append('c')
print(list1)
# 删除元素ABC
print(list1.pop(0))
print(list1.pop(0))
print(list1.pop(0))
- 列表的反转reverse()
list[::-1]:得到一个新的列表, 原列表不会改动。list.reverse():直接修改原列表的数据。
str = 'python'
list = []
for i in str:
list.append(i)
print(list)
# 截取操作逆置元素
print(list[::-1])
# 反转列表
list.reverse()
print(list)
- 列表排序
list.sort():升序,直接在原列表中排序。list.sort(reverse=True):降序,直接在原列表中排序。
- 列表的嵌套
# 嵌套列表
str_list = [['python','c','c++'],['java','c#','html']]
# 元素python
print(str_list[0][0])
# 输出元素c、c#
for list in str_list:
print(list[1])
4.3 元组
- python 的元组与列表类似,不同之处在于元组的元素不能修改。
- 元组使用小括号 ( ),列表使用方括号 [ ]。
- 元组中的数据不能修改,因此只能查询, 如 index, count 。
# 定义元组
my_tuple = ()
my_tuple1 = (1, 2, 'python', True)
# 类型转换:列表转元组
my_list = ['A', 'B', 1, 2]
print(type(my_list)) # 输出: <class 'list'>
my_list_tuple2 = tuple(my_list)
print(type(my_list_tuple2)) # 输出: <class 'tuple'>
4.4 字典
- 字典
dict,使用花括号{}表示。 - 由键(key)值(value)对组成,
key:value,多个键值对之间使用逗号隔开。 - 字典的键不能重复,主要使用字符串类型,可以是数字。
- 字典中没有索引。
# 定义字典
my_dict = {}
my_dict1 = {'name':'张三','age':18,'sex':'男'}
# 修改键值对
my_dict1['age'] = 22
print(my_dict1)
# 添加键值对
my_dict1['id'] = 101
print(my_dict1)
- 删除数据
dict.pop('key')
- 查询
dict['key']:key存在返回值,不存在会报错。dict.get('key'):key存在返回值,不存在返回None
my_dict1 = {'name':'张三','age':18,'sex':'男','id':101}
# 删除键值对
my_dict1.pop('id')
print(my_dict1)
# 查询
print(my_dict1['name'])
print(my_dict1.get('id'))
- 遍历
my_dict1 = {'name':'张三','age':18,'sex':'男'}
# 遍历
# 遍历字典的键
for i in my_dict1:
print(i)
# kes()可以获取字典中所有的键
for i in my_dict1.keys():
print(i)
# 遍历字典的值,values()可以获取字典中所有的值
for i in my_dict1.values():
print(i)
# 遍历字典的键和值,items() 获取的是字典的键值对
for k,v in my_dict1.items():
print(k,v)
4.5 练习
- 有一个列表,判断列表中的每一个元素是否以s或e结尾,如果是,则将其放入一个新的列表中,最后输出这个新的列表。
- my_list = [“red”, “apples”, “orange”, “pink”, “bananas”, “blue”, “black”, “white”]
my_list = ["red", "apples", "orange", "pink", "bananas", "blue", "black", "white"]
# 定义空列表存储数据
my_new_list = []
# 遍历列表所有元素
for i in my_list:
# 取每个元素最后一个字符
str = i[-1]
# 判断
if str == 's' or str == 'e':
# 匹配则添加到新列表中
my_new_list.append(i)
print(my_new_list)
- 使用 input 输入 5 个学生的名字存入列表,随机的获取一个学生的名字并打印。
import random
my_list = []
for i in range(5):
i = input("请输入名字:")
my_list.append(i)
print(my_list)
# 生成一个0~4之间的随机数,包括0和4
name_index = random.randint(0,4)
name = my_list[name_index]
print(name)
五、函数
- 函数是组织好的,可重复使用的,用来实现单一或相关联功能的代码段。
- python提供了许多内建函数,比如print()、input()、type()、len()等。也可以自己创建函数,这种函数叫做用户自定义函数。
- 定义函数的好处: 减少代码冗余(重复的代码不需要多次书写),提⾼编程效率。
5.1 函数的定义和调用
- 定义函数的规则:
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
- 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号 : 起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None。
def 函数名(参数列表):
函数体(函数中的代码)
......
- 函数调用,就是使用函数代码块的过程。
- 语法:
函数名(参数)
- 语法:
# 比较两个数的大小,并返回较大的数
def max(a,b): # 括号内的是形参,用于传递数值
if a > b:
return a
else:
return b
a = int(input('请输入第一个数:'))
b = int(input('请输入第二个数:'))
print(f'较大数为:{max(a,b)}') # 实参,具有实际值,有多少个形参就要有多少个实参
- 函数的嵌套调用,就是在一个函数中调用另一个函数
# 计算两数之和与另一个的乘积
# 计算两数之和
def add(a,b):
return a+b
# 计算两数之和与另一个数的乘积
def mutiply(x,y,z):
return add(x,y)*z
# 调用函数
print(mutiply(1,2,3))
5.2 函数的返回值
- 返回值:函数执行的结果。
- 在⼀个函数中,想要返回⼀个数据(想要有返回值), 需要使⽤ return 关键字。
- 在函数中可能通过各种代码,得到的数据结果,想要在函数外部使⽤,就需要使⽤返回值。
- 如果函数有返回值, ⼀般在调⽤的时候会使⽤变量来接收(保存)返回值, 以便后续使⽤。
- return 关键字的作⽤:将⼀个数据值返回到调⽤的地⽅; 函数遇到 return 会结束函数的执行;
- return 关键字只能⽤在函数中。
- 如果⼀个函数没有写 return,可以认为其返回值是 None。
# 实现登录小案例
# 获取用户名
def input_username():
return input('请输入用户名:')
# 获取密码
def input_password():
return input('请输入密码:')
# 登录
def login():
username = input_username()
password = input_password()
if username == 'admin' and password == '123456':
return True
else:
return False
# 调用函数
while True:
option = int(input('请输入选择码:1/登录 2/退出'))
if option == 1:
if login():
print('登录成功')
break
else:
print('登录失败,用户名或密码错误')
elif option == 2:
break
else:
print('选项错误,请重新选择!')
5.3 模块和包
- 在Python 中, 每个代码⽂件都可以称为是⼀个模块,在模块中别⼈书写好的功能(变量, 函数, 类),我们可以拿来直接使⽤。
- 我们⾃⼰写的代码⽂件, 想要作为模块让别⼈使⽤, 代码⽂件名(模块名) 需要满⾜标识符的规则。
- 想要使⽤别⼈模块中写好的功能,需要先导⼊别⼈写好的模块。
- as 关键字 , 可以给模块或者功能起别名。
- 模块的导入方法:
import 模块名:该方式多用于导入系统中常用的模块。- 使用模块中的功能:
模块名.功能名
- 使用模块中的功能:
from 模块名 import 功能名:导入指定的功能,多⽤于导⼊⾃⼰书写的或者是第三⽅的模块。
# 导入系统中的模块
import random
num = random.randint(1,10)
print(num)
# 导入自己写的模块
# tools.py:
def sum(a,b)
return a+b
# test1.py
from tools import sum
print(sum(1,2))
- 包(package)
- 将多个模块放在⼀个⽬录中集中管理, 并在这个⽬录中创建⼀个
__init__.py⽂件(可以什么都不写), 就是⼀个包。

- 包的导入
- 将多个模块放在⼀个⽬录中集中管理, 并在这个⽬录中创建⼀个
# 方式一
import 包名.模块名
# 使用
包名.模块名.工具名
# 方式二
from 包名 import 模块名
# 使用
模块名.工具名
# 方式三
from 包名.模块名 import 工具名
# 使用
工具名
5.4 __name__变量
__name__作用: 解决导⼊模块时, 模块中部分代码不想被执⾏的问题。__name__变量,是 python 解释器内置的变量(变量的值是⾃动维护的), 每个代码⽂件中,都有这个变量。- 在模块中直接右键运⾏代码⽂件,
__name__变量的值是'__main__'。 - 如果是被导⼊运⾏代码⽂件,
__name__变量的值是模块名(⽂件名)。
# tools.py
def sum(a,b):
return a+b
# __name__变量下的代码只会在当前文件执行,导入的时候不会执行
if __name__ == 'main':
print(sum(4,5)) # 9
# mytest.py
from tools import sum
print(sum(1,4)) # 5
- 【练习】
- 模拟开发登录功能并测试
- 需求:
- 模拟开发人员实现登录功能,定义一个函数能够接收用户输入的用户名、密码、验证码,根据不同的测试数据返回不同的验证结果。
- 已知正确的登录信息(用户名:admin、密码:123456、验证码:8888)。
- 要求1:创建login_service.py模块开发登录功能代码,并存放到service包中。
- 要求2:创建test_login.py模块开发测试代码,并存放到script包中。
- 要求3:至少测试3种测试场景。
# service/login_service.py
'''登录功能'''
def login(username,password,verification_code):
if username == 'admin':
if password == '123456':
if verification_code == '8888':
print('登录成功')
else:
print('登录失败,验证码错误!')
else:
print('登录失败,密码错误!')
else:
print('登录失败,用户名错误!')
# script/test_login.py
# 导入模块
from service.login_service import login
# 调用登录功能
# 登录成功
login('admin','123456','8888')
# 登录失败
login('张三','123456','8888')
login('admin','123','8888')
login('admin','123456','1234')
- 代码完成后,执行,这时报了一个错:

- 错误原因是:没有名为‘service’的模块。
- 检查我的目录结构,确定我的目录文件都没问题。

- 查看python的搜索路径,发现其中没有study目录的路径。

- 解决:把我的项目路径加入系统运行路径

- 编辑settings.json,添加上下面内容,保存退出。
"terminal.integrated.env.windows": {
"PYTHONPATH": "/path/to/your/project"
}

- 重启虚拟环境(我这里是venv虚拟环境)
- 执行:
.venv\Scripts\activate - 如果遇到PowerShell 的执行策略限制可先执行:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser(允许当前用户运行所有本地 PowerShell 脚本)
- 执行:
- 配置成功,如下图

- 再次运行test_login.py,发现导入系统模块和自定义模块都无问题。

5.5 引用
- 在定义变量时,变量和数据都会在内存中开辟空间,变量是存储数据的容器,但它们并不直接存储数据本身,而是存储对数据的引用(即内存地址)。
- 引用实际上指的是,一个变量指向一个对象在内存中的地址。
- python中所有数据的传递,传递的都是引用。
- 赋值运算符(=),会改变变量的引用,即只有赋值运算符可以修改变量的引用。
- 可以使用
id(变量)函数,查看变量的引用。
# 引用
a = 1 # 本质:将数据1的地址保存到变量a中,通常理解:将1保存到a
b = a # 本质:将变量a中的引用保存到变量b中,通常理解:将a的值赋给b
print(f'a:{a}',{id(a)}) # a:1 {1858864873712}
print(f'b:{b}',{id(b)}) # b:1 {1858864873712}
a = 2 # 本质:将数据2的地址保存到变量a中
# 这里只改变了a的引用(a指向数据2的地址),所以a的值改变,b的引用(b指向数据1的地址)没有改变
print(f'a:{a}',{id(a)})# a:2 {2382150762768}
print(f'b:{b}',{id(b)})# b:1 {1858864873712}
# 列表的引用
my_list = [1,2,3] # 变量my_list引用列表[1,2,3],即变量my_list指向列表在内存中的地址。
my_list1 = my_list # 将变量my_list1也设置为引用列表[1,2,3]
print(f'my_list:{my_list}',{id(my_list)}) # my_list:[1, 2, 3] {1787426965760}
print(f'my_list1:{my_list1}',{id(my_list1)}) # my_list1:[1, 2, 3] {1787426965760}
# 这里只是改变了列表中下标为1的元素的引用,并没有改变列表的引用
my_list[1] = 5
print(f'my_list:{my_list}',{id(my_list)}) # my_list:[1, 5, 3] {1787426965760}
print(f'my_list1:{my_list1}',{id(my_list1)}) # my_list1:[1, 5, 3] {1787426965760}
# 由于 my_list 和 my_list1 引用同一个列表对象,所以通过任何一个变量所做的修改都会反映到另一个变量上。
5.6 数据类型的可变与不可变类型
- 根据内存中的数据是否允许修改,将数据类型分为可变类型与不可变类型。
- 简单理解: 不使用等号,能不能修改数据值
- 可变类型: 可以修改
- 列表(list)
- list.append()
- 字典(dict)
- dict.pop()
- 集合(set)
- 列表(list)
- 不可变类型: 不允许修改
- 数字类型(int , float , bool)
- 字符串(str)
- 元组(tuple)
- 可变类型: 可以修改
5.7 局部变量与全局变量
- 按变量定义的位置将变量分为局部变量和全局变量。
- 局部变量:在函数内部定义的变量,称为局部变量。
- 局部变量只能在当前函数内部使用。
- 可以在不同函数内部定义名字相同的局部变量。
- 生命周期(使用范围)
- 在函数执行(调用)时被创建。
- 函数执行结束时被销毁。
- 形参可看作是局部变量,如果想要在函数外部使用局部变量的值,需要使用 return 返回。
- 全局变量:在函数外部定义的变量。
- 全局变量可以在任意函数内访问(读取)。
- 想要在函数内部修改全局变量的引用,需要使用 global 关键字声明(使用 global 关键字可以声明为全局变量)。
- 如果在函数内部出现和全局变量名字相同的局部变量,在函数内部使用的是局部变量。
- 生命周期
- 代码执行的时候创建, 执行结束销毁。
num = 20 # 全局变量
def sum(a,b):
i = 10 # 局部变量
return (a+b)*i
def sum1(a,b):
return (a+b)*num # 全局变量在函数内部使用
def func1():
global i # 将i声明为全局变量
i = 20
a = 10
return a+i
if __name__ == '__main__':
print(sum(2,3))
print(sum1(1,2))
print(func1())
print(i+11) # 外部可使用变量i
5.8 函数参数
- 形参:是函数定义时指定的变量,用于在函数体内部引用传递给函数的值。在函数定义时,形参被放在圆括号()内,并用逗号,分隔。
- 实参:是调用函数时实际传递给函数的值,可以是常量、变量、表达式的结果等。
- 参数传递:
- 传参方式:指的是如何将实参的值传递给形参。
- 位置传参:在函数调用的时候按照形参的顺序将实参的值传递给形参。
- 关键字传参:在函数调用的时候,指定将实参传递给哪个形参。
- 混合使用:
- 位置参数必须写在关键字参数的前边,关键字参数必须放在位置参数的后边。
- 同一个形参只能接收一个实参值(不能即使用位置传参和关键字传参给同一个形参传参)。
# 参数传递
def func2(x,y,z):
print(x,y,z)
if __name__ == '__main__':
# 位置传参,按形参顺序传递
func2(1,'python',3)
# 关键字传递
func2(y='python',x='java',z='4')
# 混合使用
func2(1,y='python',z=5)
- 缺省参数(默认参数):
- 定义:在函数定义的时候,给形参一个默认的数据值,这个参数就是缺省参数。
- 特点:在函数调用时,缺省参数可以不用传递实参值。
- 如果不传实参值,使用的就是默认值。
- 如果传递实参值,使用的就是传递的实参值。
- 缺省参数必须写在普通参数后面。
# 缺省参数
def func3(a,b=1):
print(a,b)
if __name__ == '__main__':
# 形参b不传递实参值
func3(2)
# 传递实参值
func3(2,4)
- 多值参数(可变参数/不定长参数):
- 使用场景:在函数定义的时候,不确定在调用的时候,实参有多少个,此时可以使用多值参数。
- 方法:在普通的参数前边加上一个
*,这个参数就变为多值参数。 - 这个参数可以接收任意多个位置传参的数据,类型:元组。
- 这个形参一般写作 args(arguments),即 *args。
# 参数顺序 普通参数、缺省参数、可变参数
def func4(普通,缺省,*agrs):
pass
# 定义一个函数,可以对任意多个数字进行求和计算.
def sum(*agrs):
num = 0
# agrs是一个元组
print(type(agrs))
for i in agrs:
num += i
return num
if __name__ == '__main__':
print(sum(10,20,30))
5.9 匿名函数
- 使用 lambda 关键字定义的表达式,称为匿名函数。
- 语法:
lambda 参数,参数:一行代码- 只能实现简单功能,只能写一行代码。
- 匿名函数一般不直接调用,作为函数的参数使用。
# 匿名函数
sum = lambda a,b:a+b
print(sum(2,3))
# 求两个数字的乘积
num = lambda a,b: a*b
print(num(2,3))
user_list = [{'name':'张三','age':18},{'name':'李四','age':22},{'name':'王五','age':17}]
# 根据字典的 age 键排序,想要对列表中的字典排序,需要 key 形参来指定根据字典中的什么键排序
# 使用函数
def func5(x):
return x['age'] # 返回这个字典中'age'键对应的值
# sort 方法接受一个 key 参数,用于指定排序的依据。这里,key 参数被设置为 func5 函数
user_list.sort(key=func5)
# 使用匿名函数
user_list.sort(key = lambda x:x['age'])
print(user_list)
5.10 练习
- 实现学生管理系统
- 学生信息录入
- 学生信息展示
- 学生信息查询
- 学生信息删除
# 学生个人信息格式:{'id':'101','name':'张三','age':'18'}
# 学生信息存储格式:[{},{},{}]
# 录入学生信息
def Enter_students_information():
# 学生信息列表
students = []
# 录入人数
num = int(input('请输入学生信息录入人数:'))
for i in range(num):
id = input(f'请输入{i+1}个学生的学号:')
name = input(f'请输入{i+1}个学生的姓名:')
age = input(f'请输入{i+1}个学生的年龄:')
# 字典存储学生个人信息
students_dict = {"id":id,"name":name,"age":age}
# 单个人信息添加到学生信息列表
students.append(students_dict)
return students
# 展示学生信息列表
def display_students_information(students):
print('-----------学生信息列表------------')
print('学号 姓名 年龄')
# students 是一个列表,student是列表中的字典元素,变量students中的student。
for student in students:
# 使用dict.get("key")获取学生信息的值(value),可添加一个默认值,当key不存在时可返回默认值
print(f'{student.get("id","id")}\t\t{student.get("name","name")}\t\t{student.get("age","age")}')
print('----------------------------------')
# 查询学生信息
def search_student_information(students):
# 通过学生姓名查找
name = input('请输入要查询学生的姓名:\n')
# 标志
found = False
for student in students:
if name == student.get("name"):
print(f'{name}的信息如下:')
print(f'学号:{student.get("id","ID")}\t姓名:{student.get("name","name")}\t年龄:{student.get("age","age")}')
# 存在该学生设为True
found = True
break
if not found:
print(f'对不起,名字叫{name}的学生不存在!')
# 删除学生信息
def delete_student_information(students):
# 通过学生ID删除
id = input('请输入要删除学生的学号:\n')
# students列表使用pop()删除需要一个索引
# 索引列表
index_list = []
# 计数
index = 0
# 遍历students中的student
for student in students:
if id == student.get("id"):
# 匹配的索引添加到索引列表
index_list.append(index)
index += 1
# 从后往前删除,以避免修改尚未处理的索引
for i in reversed(index_list):
students.pop(i)
print(f'学号为{id}的学生信息删除成功!')
if __name__ == '__main__':
students = []
while True:
option = input('请输入功能码:\n1录入学生信息\t2展示学生信息\t3查询学生信息\t4删除学生信息\t5退出\n')
if option == '1':
students = Enter_students_information()
elif option == '2':
display_students_information(students)
elif option == '3':
search_student_information(students)
elif option == '4':
delete_student_information(students)
elif option == '5':
break
else:
print('选择码错误,请重新输入!')
六、面向对象
- 编程方法(编程思想)
- 面向过程
- 把程序看作是一系列需要按照特定顺序执行的过程(函数),每个过程都执行特定的任务。这些过程可以调用其他过程,也可以被其他过程调用,从而形成了一个过程调用网络。
- 特点:结构化、线性执行、数据与操作分离、可重用性低。
- 面向过程编程需要详细规划每个过程的执行步骤,以及过程之间的数据传递方式,它更多地考虑的是程序实现的细节。
- 面向对象
- 把程序看作是一组相互协作的对象,每个对象都有自己的属性和方法,并且知道如何与其他对象进行交互。
- 特点:封装、继承、多态、抽象。
- 面向对象编程主要关注每个对象的职责和能力,以及它们之间的交互方式,相对而言,它更侧重于程序的整体结构和实现结果,而不过于拘泥于具体的执行细节。
- 面向过程
6.1 类和对象
- 类:是对具有相同特征或者⾏为的事物的⼀个统称,它是抽象的,不能直接使⽤。
- 指代多个事物
- 代码中的类是由关键字
class定义
- 对象:是由类创建出来的一个具体存在的事物,可以直接使用。
- 指代具体的一个事物
- 代码中用类去创建(实例化)
- 类的构成(类的三要素):
- 类名:指代一类事物的名称,大驼峰命名法。
- 如:Person、Car
- 属性:事物的特征。
- 如:Person类的属性可能有:name、age、sex等。
- 方法:事物的行为。
- 如:Person类的方法可能有:walk、talk等
- 类名:指代一类事物的名称,大驼峰命名法。
- 使用面向对象编程的步骤:
- 设计类(找类的三要素)
- 定义类
- 创建对象(实例化对象)
- 由对象调用类中的方法
6.2 面向对象基本语法
- 类的基本使用
- 定义类
- 在python中定义类使用关键字
class
- 在python中定义类使用关键字
- 创建对象
类名()- 一般会使用一个变量引用对象
变量 = 类名()
- 调用方法
对象.方法名()
- 定义类
# 类的定义
class Person:
# 在类的缩进中定义类属性和方法,这里没有定义类属性,只定义了方法
def walk(self): # 方法的本质是函数
print("行走")
# 创建对象,可将person看作是一个对象,本质是变量保存对象Person()在内存中的地址
person = Person()
# 调用方法
person.walk()
- self 参数
- self 是形参,名字可以是任意的变量名,只是习惯性叫self。
- self 是⼀个普通的参数,按照函数的语法,在调⽤的时候,必须传递实参值。 但是上面并没有传递实参值,是因为 Python 解释器自动将调⽤这个⽅法的对象作为参数传递给 self。
class Person:
# 奔跑方法
def run(self):
print("奔跑")
print(f"self:{id(self)}") # self:2358807954816
# 创建一个Person对象
person = Person()
# 调用run方法,Python解释器会自动将person对象传递给self
person.run()
print(f"person:{id(person)}") # person:2358807954816
- 属性
- 给对象添加属性:
对象.属性名 = 属性值 - 获取对象的属性值:
对象.属性名 - 在方法中操作属性
- 给对象添加属性:
self.属性名 = 属性值 - 获取对象属性值:
self.属性名
- 给对象添加属性:
- 给对象添加属性:
class Person:
# 奔跑方法
def run(self):
print("奔跑")
# 添加属性
self.move_speed = "7"
# 获取属性值
print(f"奔跑的速度为:{self.move_speed}米/秒")
# 创建一个Person对象
person = Person()
# 添加属性
person.name = '张三'
# 调用run方法,将对象person传递给self,对象person也具有奔跑的属性
person.run()
# 获取属性
print(f"{person.name}奔跑的速度为:{person.move_speed}米/秒")
6.3 魔法方法
- 在python中,方法名以两个下划线开头并以两个下划线结尾,在满足某个条件的情况下,解释器会自动调用的特殊方法称为魔法方法。
- 基本魔法方法:
- 初始化方法
__init__- 构造器,当一个实例被创建的时候调用的初始化方法。用于初始化新创建的对象的状态或属性。
- 调用时机:在创建对象之后,解释器会自动调用该方法。
- 应用场景:初始化对象,为对象添加属性。
- 注意事项:如果属性是会变化的,可以将属性的值作为参数传递,但在创建对象的时候,必须传递实参值。
class Cat:
# 初始化方法
# 属性姓名、颜色、年龄
def __init__(self,name,color,age): #
self.name = name
self.color = color
self.age = age
def eat(self):
print(f"{self.name}是只{self.color}的猫,爱吃小鱼干。") # 小白是只黑色的猫,爱吃小鱼干。
# 创建对象,自动调用初始化方法,传递姓名、颜色、年龄实参值
cat = Cat('小白','黑色',4)
# 调用方法
cat.eat()
print(f"{cat.name}今年{cat.age}岁了") # 小白今年4岁了
__str__方法- 调用时机:使⽤
print(对象)打印对象的时候,解释器会⾃动调⽤该方法。- 如果没有定义
__str__⽅法,默认打印的是对象的引⽤地址。 - 如果定义
__str__⽅法,打印的是⽅法的返回值。
- 如果没有定义
- 应用场景:使⽤
print(对象)打印输出对象的属性信息。 - 注意事项:返回值必须是一个字符串类型。
- 调用时机:使⽤
class Pig:
# 初始化方法
def __init__(self,name,color,age):
self.name = name
self.color =color
self.age = age
def __str__(self):
return f"{self.name}是只{self.color}的小猪,它今年{self.age}岁了"
def talk(self):
print(f"{self.name}说要去踩水坑")
pig = Pig('佩奇','粉色',3)
print(pig)
# 定义了__str__方法输出:佩奇是只粉色的小猪,它今年3岁了
# 没定义__str__方法输出:<__main__.Pig object at 0x00000213EACBB790>
pig.talk() # 佩奇说要去踩水坑
6.4 封装
- 封装指的是将对象的属性和方法组合在一起,并对外界隐藏对象的具体细节,仅通过公开的方法与外界进行交互。
- 在python中,封装主要通过类属性和类方法来实现。
- 封装的好处
- 灵活性:通过封装,可以轻松地修改类的内部实现,而不会影响使用该类的代码。
- 安全性:可以防止外部代码直接访问或修改对象的敏感属性。
- 可维护性:封装使得代码更加模块化,易于理解和维护。
- 封装练习
# 进⼊某 Web 项⽬登录⻚⾯,输⼊⽤户名、密码、验证码之后登录系统
# 设计类
# 类名:LonginPage
# 属性:用户名、密码、验证码
# 方法:登录
class LoginPage:
def __init__(self,userName,passWord,verificationCode):
self.userName = userName
self.passWord = passWord
self.verificationCode =verificationCode
def login(self):
if self.userName == 'admin' and self.passWord == '123456':
if self.verificationCode == '8888':
print(f"{self.userName}登录成功!")
else:
print("验证码错误!")
else:
print("登录失败,用户名或密码错误,请重新登录!")
loginPage = LoginPage('admin','123456','8888')
loginPage.login()
6.5 继承
- 继承是面向对象编程中的一种机制,它允许一个类(子类)继承另一个类(父类)的属性和方法。通过继承,子类可以重用父类的代码,并添加或覆盖自己的属性和方法。
- 单继承:一个子类只能继承一个父类。
- 多继承:python中支持多继承,一个子类可以继承多个父类。
- 继承的好处:减少代码冗余,重复代码不要多次书写,提高编程效率。
- 继承的传递性: C 继承 B,B 继承 A,C 可以使用 A 类中的属性和方法。
# 继承
# 动物类,父类/基类
class Animal:
# 动物具有姓名、年龄、颜色共同属性
def __init__(self,name,age,color):
self.name = name
self.age = age
self.color = color
# 动物具有吃和睡的共同行为
def eat(self):
print(f"{self.name}正在吃东西")
def sleep(self):
print(f"{self.name}正在睡觉")
# 狗类,子类继承父类
class Dog(Animal):
# 狗类具有动物类的共同属性和共同行为
# 狗类的特殊行为,看家
def look_after_the_door(self):
print(f"{self.name}正在看家")
# 猫类,子类继承父类
class Cat(Animal):
# 猫类具有动物类的共同属性和共同行为
# 猫类的特殊行为,抓老鼠
def catch_the_mouse(self):
print(f"{self.name}正在抓老鼠")
# 黑猫警长类,继承父类猫类
class BlackCat(Cat):
# 继承的传递性:黑猫警长类具有猫类的特殊行为也具有动物类的共同属性和行为
# 黑猫警长的特殊行为,说话
def talk(self):
print(f"我是{self.name}")
if __name__ == '__main__':
# 创建对象小黄
dog = Dog("小黄",3,"灰色")
print(f"{dog.name}是一只{dog.color}的小狗,它今年{dog.age}岁了!") # 小黄是一只灰色的小狗,它今年3岁了!
# 调用动物吃的方法
dog.eat() # 小黄正在吃东西
# 调用狗类看门方法
dog.look_after_the_door() # 小黄正在看家
# 创建对象小花
cat = Cat("小花",4,"花色")
print(f"{cat.name}是一只{cat.color}的小猫,它今年{cat.age}岁了!") # 小花是一只花色的小猫,它今年4岁了!
# 调用动物类睡觉方法
cat.sleep() # 小花正在睡觉
# 创建对象黑猫警长
black_cat = BlackCat("黑猫警长",5,"黑色")
print(f"{black_cat.name}是一只{black_cat.color}的猫,它今年{black_cat.age}岁了!") # 黑猫警长是一只黑色的猫,它今年5岁了!
# 调用动物类吃的方法
black_cat.eat() # 黑猫警长正在吃东西 父类的父类方法
# 调用猫类抓老鼠的方法
black_cat.catch_the_mouse() # 黑猫警长正在抓老鼠 父类方法
# 调用黑猫警长类说话的方法
black_cat.talk() # 我是黑猫警长 子类方法
- 重写(override)
- 重写是在子类中定义了和父类中同名的方法。
- 重写的原因:父类中该方法不能满足子类对象的需求。
- 重写的方式:
- 覆盖式重写:父类中的功能全部不要,直接在子类中定义和父类中方法名字一样的方法接口,书写新的代码。
- 扩展式重新:父类中的功能还需要,只是添加了新的功能。先在子类中定义和父类中名字相同的方法,在子类的代码中使用
super().方法名()调用父类中的功能,接着书写新的功能。
# 重写
class Animal:
def __init__(self,name):
self.name = name
# 动物的共同行为,叫
def bark(self):
print(f"{self.name}正在叫!")
class Dog(Animal):
# 覆盖式重写
def bark(self):
print(f"{self.name}正在汪汪叫!")
class Cat(Animal):
# 扩展式重写
def bark(self):
super().bark() # 调用父类叫的方法
print(f"{self.name}正在喵喵叫!")
if __name__ == '__main__':
dog = Dog("小黄")
dog.bark() # 小黄正在汪汪叫!
cat = Cat('小白')
cat.bark() # 小白正在叫!小白正在喵喵叫!
6.6 多态
- 多态是指不同的对象可以通过相同的接口调用方法,而这些方法在不同对象上的具体实现可以不同。多态允许使用统一的接口来处理不同类型的对象。
# 多态 不同子类对象调用相同方法产生不同结果
# 求三角形和矩形的面积
# 定义一个父类(形状)
class Shape:
def __init__(self,shapeName,width,height):
self.shapeName = shapeName
self.width = width
self.height = height
# 形状都有求面积的方法,方法因形状而异,因此父类方法无法满足子类求面积的需求
def area(self):
print("求形状的面积")
# 定义一个子类(矩形)继承Shape
class Rectangle(Shape):
# 重写求面积方法
def area(self):
return self.width * self.height
# 定义子类(三角形)继承Shape
class Triangle(Shape):
# 重写求面积方法
def area(self):
return (self.width * self.height) * 1/2
# 定义一个函数,它接受一个Shape对象并调用其area方法
def print_area(shape):
print(f"{shape.shapeName}的面积为:{shape.area()}")
if __name__ == '__main__':
# 创建矩形对象
rectangle = Rectangle("矩形",2,3)
# 创建三角形对象
triangle = Triangle("三角形",2,3)
# 调用输出方法
print_area(rectangle) # 矩形的面积为:6
print_area(triangle) # 三角形的面积为:3.0
6.7 属性和方法的访问权限
- 在python 中,定义类的时候,可以给属性和方法设置访问权限,即规定在什么地方可以使用。权限一般分为两种: 公有权限和私有权限。
- 公有权限:
- 公有属性和方法是在类定义中不加任何特殊前缀直接定义的。
- 可以在任何地方访问和使用,只要有对象就可以访问和使用。
- 私有权限:
- 只能在类内部定义(class 关键字的缩进中)。
- 只需要在属性名或方法名前面加上两个下划线
__方法名或__属性名, 这个方法或者属性就变为私有的。 - 私有的属性和方法,只能在当前类的内部使用,不能在类外部和子类直接使用。
class Person:
def __init__(self,name,length_of_service):
self.name = name # 公有属性
self.__length_of_service = length_of_service # 私有属性
# 定义外部获取工龄属性值方法
def get_los(self):
return self.__length_of_service
# 定义外部修改工龄属性值的方法
def set_los(self,length_of_service):
self.__length_of_service = length_of_service
class Worker(Person):
def working(self):
print(f"{self.name}正在工作,他的工龄为{self.get_los()}年") # 通过调用公有方法获取私有属性值
# print(f"{self.name}正在工作,他的工龄为{self.__length_of_service}年") # 私有属性只有在当前类可以访问
# 子类无法访问工龄这个私有属性
# AttributeError: 'Worker' object has no attribute '_Worker__length_of_service'
tom = Worker("汤姆",10)
tom.working() # 汤姆正在工作,他的工龄为10年
6.8 对象、属性、方法的划分
- 对象的划分
- 类对象:类,使用class定义的类,在代码执行时,解释器会自动创建的对象。
- 实例对象:由类对象创建的对象称为实例对象,实例对象可以保存实例的特征值(属性值)。
- 属性的划分
- 类属性:类对象具有的特征,是整个类的特征,在类的内部(class 缩进中),方法的外部(def 的缩进外部) 定义的变量。
- 修改:
类对象.属性 = 属性值 - 访问:
类对象.属性
- 修改:
- 实例属性:是每个实例对象具有的特征, 每个实例对象的特征。一般都是在
__init__方法中,使用self.属性名 = 属性值来定义。- 修改:
实例对象.属性 = 属性值 - 访问:
实例对象.属性
- 修改:
- 类属性:类对象具有的特征,是整个类的特征,在类的内部(class 缩进中),方法的外部(def 的缩进外部) 定义的变量。
- 方法的划分
- 类方法:使用
@classmethod装饰器定义的方法,它们需要类本身作为第一个参数(通常是 cls),而不是实例。类方法通常用于创建或修改类级别的数据。 - 实例方法:定义在类中的方法,它们需要通过类的实例来调用。实例方法至少有一个参数,通常是 self,它引用调用该方法的对象。
- 静态方法:使用
@staticmethod装饰器定义的方法,它们不需要类或实例作为参数。静态方法通常用于执行与类或实例无关的功能。
- 类方法:使用
# Dog类,类对象
import random
class Game:
top_score = 0 # 类属性,记录游戏最高分,所有实例共享
# 初始化方法,特殊的实例方法
def __init__(self,player_name):
self.player_name = player_name
# 静态方法,不需要类或实例作为参数
@staticmethod
def show_help():
print("游戏帮助信息")
# 类方法,参数Cls代表类本身
@classmethod
def show_top_score(cls):
print(f"游戏最高分:{cls.top_score}")
# 实例方法
def start_game(self):
self.score = random.randint(10,100)
print(f"本次得分:{self.score}")
if self.score > Game.top_score:
Game.top_score = self.score
if __name__ == '__main__':
# 调用静态方法
Game.show_help()
# 调用类方法
Game.show_top_score()
# 实例化对象
game = Game("小李")
game.start_game()
Game.show_top_score()
game.start_game()
Game.show_top_score()
七、文件和异常
7.1 文件
- 文件介绍:
- 可以存储在长期存储设备(硬盘, U盘)上的一段数据即为文件。
- 计算机只认识 二进制数据(0 和 1),所有的文件在计算机中存储的形式都是二进制,即 0 和 1 ,打开文件看到的是文字而不是 0 和 1 ,是因为打开文件的软件会自动的将二进制转换为文字。
- 文件的分类:
- 文本文件
- 后缀为:
.txt、.py、.md、.json等
- 后缀为:
- 二进制文件
- 后缀为:
.mp3、.mp4、.png、.jpg、.gif、.exe等
- 后缀为:
- 文本文件
- 文件操作
- 文件操作,使用代码来读写文件。
- 自动化测试,测试数据是在文件中保存的,需要从文件中读取测试数据,进行自动化代码的执行。
- 文件操作的步骤:
- 打开文件:
open(file,mode='r',encoding=None)file:表示要打开文件的名字,可使用相对路径和绝对路径。mode = 'r':表示打开文件的方法,参数有r、w、a。r:(read)只读打开,如果文件不存在会报错。w:(write)只写打开,如果文件存在,会覆盖原文件。a:(append)追加打开,在文件末尾写入新的内容。
encoding = None:表示打开文件的编码格式,即二进制数据和汉字转换的规则。参数有utf-8、gbk等utf-8:将一个汉字转换为3个字节(B)的二进制数据。gbk:将一个汉字转换为2个字节的二进制数据。
- 返回值:文件对象,后续对文件的操作都需要这个对象。
- 读文件:
变量 = 文件对象.read()- 返回值:返回读取到的文件内容,类型为字符串。
- 写文件:
文件对象.write()- 参数:写入文件的内容,类型字符串。
- 返回值:写入文件中的字符数。字符串的长度,一般不关注。
- 关闭文件:
文件对象.close()- 如果是写文件,会自动保存(即将内存中的数据同步到硬盘中)。
# 文件操作
# test.txt "这是一个文本文件"
# 只读方式打开文件,data变量引用文件对象
data = open('./test.txt',mode='r',encoding='utf-8')
print(data) # <_io.TextIOWrapper name='./test.txt' mode='r' encoding='utf-8'>
# 读取test.txt文件内容
test_content = data.read()
print(test_content) # 这是一个文本文件
# 关闭文件
data.close()
# 另一种文件打开方式,会自动关闭文件
# 以只写的方式打开文件,如果文件存在会覆盖原文件
with open('./test.txt',mode='w',encoding='utf-8') as f:
print(f)
# 写入内容
f.write('这是写入内容')
with open('./test.txt',mode='r',encoding='utf-8') as f:
print(f.read()) # 这是写入内容
# 以追加方式打开文件,在文件末尾写入新的内容。
with open('./test.txt',mode='a',encoding='utf-8') as f:
f.write('这是追加的内容')
with open('./test.txt',mode='r',encoding='utf-8') as f:
print(f.read()) # 这是写入内容这是追加的内容
# 其他打开方式 r+(读写,文件必须存在)、w+(读写,文件不存在则创建,存在则清空)、a+(读写,文件不存在则创建,存在则在末尾追加)
with open('./test.txt',mode='r+',encoding='utf-8') as f:
data = f.read()
print(data)
f.write('\nhello python')
- 按行读取文件:
文件对象.readline()- 一次性读取一行文件,返回到读取的内容。
# 读写方式打开文件,清空test.txt文件内容
with open('./test.txt','w+',encoding='utf-8') as f:
print(f.read())
f.write('hello python\n文件操作练习')
with open('./test.txt',mode='r',encoding='utf-8') as f:
print(f.read())
# hello python
# 文件操作练习
with open('./test.txt',mode='r',encoding='utf-8') as f:
data = f.readline()
print(data) # hello python
data1 = f.readline()
print(data1) # 文件操作练习
- 读取大文件
# 读取大文件
with open('./test.txt',encoding='utf-8') as f:
while True:
data = f.readline() # 按行读取,读完会返回空字符
if data == '': # 判断是否读完,是则结束循环
break
else :
print(data)
- JSON 文件
- json 文件本质上是文本文件,但由于其结构类似于Python中的字典和列表,因此使用专门的库来处理它们会更为方便。在Python中,json模块提供了处理JSON数据的方法,可以很方便地将JSON数据转换为Python的字典或列表。
- json 文件介绍:
- json ⽂件,是⼀种基于⽂本,独⽴于语⾔的轻量级数据交换格式。基于⽂本,⽂本⽂件,不包含图⽚,视频等。
- 独⽴于语⾔,不是某⼀种语⾔特有的。
- 轻量级,相同的数据量,json ⽂件的占⽤的⽂件大小相对较小。
- 数据交换格式,后端服务器和前端页面交换数据使⽤的格式。
- 在⾃动化测试中经常⽤来存放测试数据,⽂件后缀名为:
.json。
- json 语法:
- json中的数据类型:
- 对象(object):
{}对应python中的字典。 - 数组(array):
[]对应python中的列表。 - 字符串(string):
"",必须使用双引号,对应python中的str。 - 数字类型(number):对应python中的
int、float。 - 布尔类型:
true、false对应python中的True、False。 - 空值:
null对应python中的None。
- 对象(object):
- json ⽂件,是⼀个对象或者是数组,对象和数组可以相互嵌套。
- json 中的对象,是由键值对组成的,键必须是字符串类型。
- json 中的数据直接使⽤逗号隔开,最后⼀个数据后边不能加逗号。
- json 文件的后缀是 .json
- json中的数据类型:
[
{
"name": "张三",
"age": 23,
"address": "北京",
"isMan": true,
"skills": [
"python",
"c++"
]
},
{
"name": "李四",
"age": 25,
"address": "北京",
"isMan": true,
"skills": [
"java",
"c#"
]
}
]
- 读取json 文件
import json # 导入json库
# 打开test.json 文件,该文件是由两个对象组成的数组
with open('./test.json','r',encoding='utf-8') as f:
data = json.load(f)
print(data)
print(type(data)) # <class 'list'> json数组对应python列表
# 遍历字典
for json_dict in data:
print(json_dict)
# 获取张三的年龄信息
if json_dict.get("name") == "张三":
zs_age = json_dict.get("age")
break
print(type(json_dict)) # <class 'dict'>
print(zs_age)
- 写入json文件
- 将python中列表或字典转换为python文件。
- 使用
json.dump()将内容写入json文件。
# 导入json库
import json
# 定义写入内容
user_list =[{"name":"Tom","age":22},{"name":"Jack","age":25}]
# 使用w+方式打开文件
with open('./users.json','w+',encoding='utf-8') as f:
data = json.dump(user_list,f) # dump(写入数据,文件对象)
# 读取users.json 文件
with open('./users.json','r',encoding='utf-8') as f:
data = json.load(f)
print(data) # [{'name': 'Tom', 'age': 22}, {'name': 'Jack', 'age': 25}]
7.2 异常
- 程序在运⾏时,如果Python解释器遇到到⼀个错误,则会停⽌程序的执⾏,并且提示⼀些错误信息,这就是异常。
- 程序停⽌执⾏并且提示错误信息这个动作,通常称之为: 抛出 (raise) 异常。
- 捕获异常:
- 通过捕获异常,程序在遇到错误或异常情况时不会立即终止,而是可以处理这些异常,并在处理完毕后继续执行后续的代码。
- 捕获异常的基本语法
- 在捕获异常的过程中,程序会检查某个代码块(通常称为try块)是否在执行时发生了异常。如果发生了异常,程序会立即跳转到与该异常类型相匹配的except块,并执行该块中的代码来处理该异常。
# 捕获任意类型的异常
try:
# 可能发生异常的代码
except:
# 发生异常执行的代码
- 常见异常类型:
- Exception:标准异常的父类,用来捕获不清楚异常类型的异常。
- SyntaxError:语法错误,通常发生在代码不符合python的语法规则时。比如缺少冒号,括号没有正确闭合等。
- IndentationError:缩进错误,python使用缩进来区分不同的代码块,缩进错误通常发生在不小心改变了缩进级别时。
- TypeError:类型错误,当尝试执行的操作不支持该类型的数据时,就会发生类型错误。比如将整数和字符串相加。
- AttributeError:属性错误,通常发生在尝试访问对象不存在的属性或方法时。
- NameError:名称错误,当程序试图访问一个未被定义的变量时,就会抛出名称错误。
- IndexError:索引错误,通常发生在尝试访问列表或其他序列类型的索引超出范围时。
- ValueError:值错误,操作或函数接收到一个具有正确类型但不适合该操作的参数时引发。比如将字符串转换为整数时遇到非数字字符。
- ZeroDivisionError:除零错误,发生在尝试将一个数除以零时。
- 捕获指定类型的异常:
# 捕获指定类型的异常
try:
num = int(input('请输⼊⼀个整数数字:'))
num1 = 8 / num
print(num1)
except ValueError:
print('输⼊的内容⾮数字,请重新输⼊')
except ZeroDivisionError:
print('不能输出数字 0, 请重新输⼊')
# 捕获未知类型异常
try:
num = int(input('请输⼊⼀个整数数字:'))
num1 = 8 / num
print(num1)
except Exception as e:
print(f'发⽣了异常, {e}')
八、Unittest 框架
- Unittest 框架是python自带的单元测试框架,它支持自动化测试,可以帮助开发人员确保代码按预期工作,并在代码更改时快速检测到任何引入的错误。
- 使用的原因:
- 能够组织多个用例去执行。
- 提供丰富的断言方法。
- 能够生成测试报告。
- 框架组成部分(核心要素):
- TestCase:测试用例,是所有测试用例的父类。它提供了一系列的方法来定义测试逻辑,并包含断言来验证测试结果。
- TestSuite:测试套件,是一个容器,用于组织多个测试用例。
- TestLoader:测试加载,用于加载测试用例,并将它们组织成测试套件。
- TestRunner:测试运行,用于运行测试套件,并输出测试结果。
- Fixture :测试夹具,指的是在测试用例执行前后自动执行的代码结构,用于设置和清理测试环境。
- TestResult:测试结果,用于存储测试结果。它跟踪测试的执行情况,包括哪些测试通过了,哪些失败了,以及失败的原因。
8.1 Unittest 基本使用
- TestCase 测试用例
- 对于简单测试用例,我们可以直接通过继承unittest.TestCase类来定义测试类。
- 步骤:
- 导包:
import unittest。 - 定义测试类:新建测试类必须继承unittest.TestCase。
- 定义测试方法:测试方法命名必须以test开头。
- 导包:
# 加法函数
def add(a, b):
return a + b
# 导包
import unittest
# 定义测试类
class TestMathFunctions(unittest.TestCase):
# 暂时不使用断言方法
# 定义测试方法
def test_add_01(self):
result = add(1, 1)
print("result1=", result)
def test_add_02(self):
result = add(1, 0)
print("result2=", result)
if __name__ == '__main__':
unittest.main()
- TestSuite和TestRunner
- 如果需要批量执行测试用例,我们就需要使用测试套件TestSuite(将多条测试用例集合在一起)。
- 步骤:
- 导包:
import unittest - 实例化套件对象:
变量 = unittest.TestSuite() - 添加⽤例⽅法:
套件对象.addTest(测试类('测试方法'))一次添加一条测试用例。 - 实例化执行对象:
变量 = unittest.TextTestRunner() - 执行对象执行套件对象:
执行对象.run(套件对象)
- 导包:
- TestLoader 测试加载
- 用来加载TestCase到TestSuite中,即加载满足条件的测试用例,并把测试用例封装成测试套件。
- 使用unittest.TestLoader,通过该类下面的discover()方法自动搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件。
- 步骤:
- 导包:
import unittest - 实例化加载对象并加载用例:
变量 = unittest.TestLoader().discover('用例所在的目录','用例文件*.py')(变量引用的是套件对象) - 实例化执行对象:
变量 = unittest.TextTestRunner() - 执行对象执行套件对象:
执行对象.run(套件对象)
- 导包:
- Fixture 测试夹具
- 某个模块的测试用例的测试步骤可能会涉及到多个操作,比如,测试wed项目的登录功能,测试步骤可能是1.打开浏览器 -》2.进入登录页面 -》3.输入用户名、密码、验证码 -》4.关闭登录页面 -》5.关闭浏览器。
- 这里操作步骤1和5,执行完所有测试用例可能只需要执行一次。
- 操作步骤2和4,每条测试用例也只需要执行一次。
- 因此需要一个能够在测试用例执行前后自动执行的代码结构——Fixtrue。
- 某个模块的测试用例的测试步骤可能会涉及到多个操作,比如,测试wed项目的登录功能,测试步骤可能是1.打开浏览器 -》2.进入登录页面 -》3.输入用户名、密码、验证码 -》4.关闭登录页面 -》5.关闭浏览器。
- Fixture控制级别
- 方法级别:运行一次测试方法就会自动执行一次。
- 前置:
def setUp(self),每个用例执行前都会调用一次。 - 后置:
def tearDown(self),每个用例执行后都会调用一次。
- 前置:
- 类级别:在类中所有的测试⽅法执⾏前后会⾃动执⾏的代码,只执⾏⼀次。
- 前置:
@classmethod def setUpClass(cls) - 后置:
@classmethod def tearDownClass(cls)
- 前置:
- 方法级别:运行一次测试方法就会自动执行一次。
import unittest
class TestLogin(unittest.TestCase):
# 方法级别
def setUp(self):
print('2. 打开登录页面')
def tearDown(self):
print('4. 关闭登录页面')
# 类级别
@classmethod
def setUpClass(cls):
print('1. 打开浏览器')
@classmethod
def tearDownClass(cls):
print('5. 关闭浏览器')
# 测试方法
def test_1(self):
print('3. 输⼊⽤户名密码验证码,点击登录 ')
def test_2(self):
print('3. 输⼊⽤户名密码验证码,点击登录 ')
def test_3(self):
print('3. 输⼊⽤户名密码验证码,点击登录 ')
if __name__ == '__main__':
unittest.main()
8.2 断言
- 什么是断言?使用代码自动判断预期结果和实际结果是否相符。
- 常见断言方法:
assertTrue(x):验证x是否为true,如果为false,测试将失败。assertFalse(x):验证x是否为false,如果为true,测试将失败。assertEqual(a,b):验证a是否等于b,如果不相等,测试将失败,并显示两个值的差异。assertNotEqual(a,b):验证a和b是否不相等,如果相等,测试将失败。assertIsNone(x):验证x是否为None,如果不为空,测试将失败。assertIsNotNone(x):验证x是否不为None,如果为空,测试将失败。assertIn(a,b):验证a是否为b的子集,如果a不在b中,测试将失败。assertNotIn(a,b):验证a是否不是b的子集,如果a在b中,测试将失败。
- 使用断言方法测试求和函数
# 求和函数
def add(a,b):
return a+b
# 导包
import unittest
from common.tools import add
# 定义测试类
class TestAdd(unittest.TestCase):
def test_add_case1(self):
self.assertEqual(1,add(1,0))
def test_add_case2(self):
self.assertEqual(2,add(1,1))
def test_add_case3(self):
self.assertEqual(3,add(1,2))
def test_add_case4(self):
self.assertEqual(4,add(1,3))
if __name__ == '__main__':
unittest.main()
8.3 参数化
- 通过参数的方式来传递数据,从而实现数据和脚本分离。并且可以实现用例的重复执行。(在书写用例方法的时候,测试数据使用变量代替,在执行的时候进行据说传递)
- unittest 测试框架,本身不支持参数化,但是可以通过安装unittest扩展插件 parameterized 来实现。
- 安装parameterized插件:
pip install parameterized - 查看安装插件:
pip list

- 使用parameterized插件
# 导包
import unittest
# 导入求和函数模块
from common.tools import add
# 导入参数化模块
from parameterized import parameterized
# 测试数据
data = [(1,2,3),(2,3,5),(2,2,4),(3,5,8)]
# 定义测试类
class TestAdd(unittest.TestCase):
# parameterized装饰器将测试数据作为参数传递给测试方法
@parameterized.expand(data)
def test_add_case(self,a,b,expect):
self.assertEqual(expect,add(a,b))
if __name__ == '__main__':
unittest.main()
8.4 测试报告
- 使用第三方的报告模版,生成报告HTMLTestReport,本质是TestRunner。
- 安装HTMLTestReport插件:
pip install HTMLTestReport

- 使用:
# 导包
import unittest
# 导入HTMLTestReport模块
from htmltestreport import HTMLTestReport
# 导入测试类模块
from case.test_add_case import TestAdd
if __name__ == '__main__':
# 实例化套件对象
suite = unittest.TestSuite()
# 实例化加载对象
loader = unittest.TestLoader()
# 添加测试方法
suite.addTest(loader.loadTestsFromTestCase(TestAdd))
# 实例化执行对象
runner = HTMLTestReport('add_test_report.html','求和函数测试报告') # 参数:file_path(测试报告路径)、title(标题)、description(描述内容)
# 执行测试套件对象
runner.run(suite)
8.5 跳过
-
对于一些未完成的或者不满足测试条件的测试函数和测试类,可以跳过执行(简单来说,不想执行的测试方法,可以设置为跳过)。
-
直接将测试函数标记成跳过:
@unittest.skip('跳过的原因') -
根据条件判断测试函数是否跳过:
@unittest.skipIf(判断条件, reason='原因') # 判断条件为 True, 执行跳过 -
以上就是关于python基础知识学习记录的所有内容了,如有错误还望指正。

2926

被折叠的 条评论
为什么被折叠?



