文章目录
- 前言
- 一、Python的基础语法
- 1.标识符
- 2.注释
- 二、Python中常见的数据类型
- 1.Number(数字)
- 1.1.int(整数数据类型)
- 1.2.float(浮点型)
- 1.3.bool(布尔类型)
- 2.String(字符串)
- 3.List(列表)
- 4.Tuple(元组)
- 5.Set(集合)
- 6.Dictionary(字典)
- 三、输入和输出
- 1.读取键盘输入
- 2.格式化输出
- 四、数据类型转换
- 五、运算符
- 1.算术运算符
- 2.比较(关系)运算符
- 3.赋值运算符
- 4.逻辑运算符
- 5.位运算符
- 6.成员运算符
- 7.身份运算符
- 8.运算符优先级
- 六、Python常见数据类型具体操作方法
- 1.字符串常用的操作方法
- 2.列表常用的操作方法
- 3.元组常用的操作方法
- 4.字典常用的操作方法
- 5.集合常用的操作方法
- 6.列表、元组、集合的相互转化
- 七、Python中的可变数据类型与不可变数据类型
- 八、浅拷贝与深拷贝
- 1.浅拷贝
- 2.深拷贝
- 3.总结
- 九、流程控制
- 1.if分支语句
- 2.关键字match与case
- 3.三目运算符
- 4.循环
- 4.1.for循环
- 4.2.while循环
- 4.3.循环中的关键字break与continue
- 十、函数
- 1.函数的定义与调用
- 2.指定形参和返回值的类型
- 3.关键字参数
- 4.默认参数
- 5.不定长参数
- 5.1.不定长位置参数*args
- 5.2不定长关键字参数**kwargs
- 6.函数的局部变量与全局变量
- 7.匿名函数
- 8.函数闭包
- 十一、模块与包的使用
- 十二、Python异常处理
- 十三、文件常用操作
- 1.常见的文件类型
- 2.文件的属性
- 3.文件的读写模式
- 3.1.读
- 3.2.写
- 3.3.读写模式总结
- 4.文件的常用操作
- 5.案例(删除一个非空的文件夹)
- 十四、面向对象
- 1.面向对象技术简介
- 2.封装
- 1.1.类的实例属性定义和实例方法定义
- 1.2.实例属性和实例方法的使用
- 1.3.自定义实例属性
- 1.4.类属性和类方法的定义
- 1.5.类属性和类方法的使用
- 1.5.静态方法的定义及使用
- 3.继承
- 3.1.单继承的使用
- 3.2.多继承的使用
- 3.3.子类调用父类同名属性和方法
- 4.多态
- 5.数据类装饰器
- 十五、装饰器
- 1.装饰器的定义
- 2.装饰器的语法糖使用
- 3.装饰器的使用场景
- 4.带有参数的装饰器
- 5.带有参数的装饰器
- 十六、生成器反射
- 十七、反射
- 1.通过反射添加或覆盖对象方法
- 2.通过反射删除
- 3.通过反射判断是否存在指定的方法
- 4.通过反射读取方法
- 十八、第三方库
- 1.自动化测试使用的第三方库
- 2.第三方库的安装、卸载、查看
- 3.虚拟环境和本地环境的区分
前言
本篇文章内容基于
Python 3.10.6
版本解释器
一、Python的基础语法
1.标识符
- 标识符的定义:变量名,函数名,类名,对象名等等的统称(Python中所有的命名都叫做标识符)
- 标识符的命名规则:
- 第一个字符必须是字母表中字母或下划线
_
- 标识符的其他的部分由字母、数字和下划线组成
- 标识符不能是关键字
- 标识符对大小写敏感(区分大小写)
- 第一个字符必须是字母表中字母或下划线
- 标识符命名建议:
- 见名知意:尽量使用英文单词进行命名,比如名字:name,年龄:age
- 小驼峰命名法则:第一个单词以小写开始,第二个单词以大写开头:myName
- 大驼峰命名法则:每个单词的首字母都大写:FirstName
- 下划线命名法则:user_name
2.注释
-
注释核心作用:
- 让人可以看得懂代码的作用,增加代码的可读性
- 让不想执行的代码直接注释掉,那么就不会参与程序的运行
-
单行注释:Python中单行注释以
#
开头# 这是一个单行注释
-
多行注释:多行注释可以用多个
#
号,还有'''
和"""
# 这是第一行注释 # 这是第二行注释 ''' 这是多行注释 第一行 第二行 ''' """ 这是多行注释 第一行 第二行 """
二、Python中常见的数据类型
列表和元组可以存放Python中任意的数据类型
不可变数据类型
:Number(数字)、String(字符串)、Tuple(元组);可变数据类型
:List(列表)、Dictionary(字典)、Set(集合)- 数据类型归类:
容器类型
:字符串,列表,元组,字典,集合数字类型
:整型,浮点型,布尔类型
1.Number(数字)
1.1.int(整数数据类型)
# 整型(int)
number = 666
print(type(number)) # <class 'int'>
1.2.float(浮点型)
# 浮点型(float)
number = 3.14
print(type(number)) # <class 'float'>
1.3.bool(布尔类型)
-
布尔类型特点:
- 布尔类型只有两个值:
True
和False
- 布尔类型可以和其他数据类型进行比较,比如数字、字符串等。在比较时,Python 会将 True 视为 1,False 视为 0
- 布尔类型可以和逻辑运算符一起使用,包括 and、or 和 not。这些运算符可以用来组合多个布尔表达式,生成一个新的布尔值
- 布尔类型也可以被转换成其他数据类型,比如整数、浮点数和字符串。在转换时,True 会被转换成 1,False 会被转换成 0
# bool(布尔类型) bool1 = True bool2 = False print(type(bool1)) # <class 'bool'> print(type(bool2)) # <class 'bool'>
- 布尔类型只有两个值:
注意
:在Python中,所有非零的数字和非空的字符串、列表、元组等数据类型都被视为 True,只有 0、空字符串、空列表、空元组等被视为 False。因此,在进行布尔类型转换时,需要注意数据类型的真假性
2.String(字符串)
-
Python中的字符串用单引号
''
或双引号""
或三引号''''''
括起来# str(字符串) str1 = '666' str2 = "张三" str3 = '''李四''' print(type(str1)) # <class 'str'> print(type(str2)) # <class 'str'> print(type(str3)) # <class 'str'>
3.List(列表)
-
列表:
[]
表示列表。列表当中可以存放Python中任意的数据类型# list(列表) list1 = [1, "张三", 3.14, True] print(type(list1)) # <class 'list'>
4.Tuple(元组)
-
元组:元组写在小括号
()
里,元素之间用逗号隔开。元组与列表类似,不同之处在于元组的元素不能修改 -
元组的括号可以省略
# tuple(元组) tuple1 = (1, 2, "张三", 3.14, [1, 3]) print(type(tuple1)) # <class 'tuple'> tuple2 = 1, 2, "张三", 3.14, [1, 3] print(type(tuple2)) # <class 'tuple'>
5.Set(集合)
-
集合是一种无序、可变的数据类型,用于存储唯一的元素
-
集合中的元素不会重复,并且可以进行交集、并集、差集等常见的集合操作
-
特性:默认去重(集合里面不存在重复的数据)
-
集合无法存在列表和字典
# set(集合) set1 = {1, 3.14, "张三", True, (1, 4)} print(type(set1)) # <class 'set'>
注意
:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。
6.Dictionary(字典)
-
列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取
-
字典是一种映射类型,字典用
{ }
标识,它是一个无序的 键(key) : 值(value) 的集合 -
键(key)必须使用不可变类型
-
在同一个字典中,键(key)必须是唯一的
# dict(字典) dict1 = {"name": "张三", "age": 18, "sex": "男"} print(type(dict1)) # <class 'dict'>
三、输入和输出
1.读取键盘输入
-
接收用户输入的数据可以调用内建函数:
input()
实现数据获取 -
一般输入的数据会保存到变量中,默认情况获取的所有用户输入的内容都是字符串
-
当程序执行的时候遇到
input
内建函数,程序会挂起(如果不输入回车)那么代码不会继续往下执行username = input("请输入用户名") password = input("请输入密码") print(f"您输入的用户名是:{username},密码是:{password}")
2.格式化输出
- 格式化定义:按照指定的方式,拼接新的字符串内容(简单理解:当需要输出一个字符串的同时,也进行输出变量值)
方式一(不常用,了解即可):
-
使用占位符号
%
实现格式化输出 -
需要根据变量值的不同数据类型进行不同参数的占位
- 格式化输出字符串类型:
%s
占位 - 格式化输出整数类型:
%d
占位 - 格式化输出浮点类型:
%f
占位
name = "张三" age = 18 height = 1.98 print("我的名字是:%s" % name) # 格式化输出字符串 print("我的年龄是:%d" % age) # 格式化输出整数 # 浮点数格式化输出时默认保留6位小数 # 如果需要保留指定的小数位,需要进行修改,那么在f前面加上.2f(保留2为小数) print("我的身高是:%f米" % height) # 格式化输出浮点数 print("我的身高是:%.2f米" % height)
- 格式化输出字符串类型:
-
多个格式化输出的语法格式
name = "张三" age = 18 height = 1.98 # 多个格式化输出的语法格式 print("我的名字是:%s,我的年龄是:%d,我的身高是:%.2f米" % (name, age, height))
方式二(不常用,了解即可):
- 任何的数据类型都可以放到
{}
进行格式化输出
name = "张三"
age = 18
height = 1.98
# 简写模式
print(f"我的名字是:{name},我的年龄是:{age},我的身高是:{height}米")
print(F"我的名字是:{name},我的年龄是:{age},我的身高是:{height}米")
# 完整模式
print("我的名字是:{},我的年龄是:{},我的身高是:{}米".format(name, age, height))
四、数据类型转换
数据类型转换的内建函数
函数 | 作用 |
---|---|
int() | 转换为整数数据类型 |
float() | 转换为浮点数数据类型 |
str() | 转换为字符串数据类型 |
eval() | 用来计算在字符串中的有效Python表达式,并返回一个对象(将字符串原生的数据类型转化为原本的类型) |
-
int():转换为整数数据类型
str1 = "666" print(type(str1)) # <class 'str'> # int()函数——将字符串的原生整数类型进行转化 print(type(int(str1))) # <class 'int'>
-
float():转换为浮点数数据类型
str2 = "666" # float()函数——将字符串的原生浮点类型进行转化 print(type(str2)) # <class 'str'> print(type(float(str2))) # <class 'float'>
-
str():转换为字符串数据类型(万物皆可字符串:任何数据类型都可以加上引号变成字符串)
number = 666 print(type(number)) # <class 'int'> # str()函数——将原生的数据类型转化为字符串 print(type(str(number))) # <class 'str'>
-
eval():将字符串原生的数据类型转化为原本的类型
str3 = "[1,2,3]" print(type(str3)) # <class 'str'> print(type(eval(str3))) # <class 'list'> str4 = "(1,2,3)" print(type(str4)) # <class 'str'> print(type(eval(str4))) # <class 'tuple'> str5 = "{1,2,3}" print(type(str5)) # <class 'str'> print(type(eval(str5))) # <class 'set'> str6 = '{"name": "张三", "age": "18"}' print(type(str6)) # <class 'str'> print(type(eval(str6))) # <class 'dict'> str7 = "666" print(type(str7)) # <class 'str'> print(type(eval(str7))) # <class 'int'>
五、运算符
1.算术运算符
以下假设变量 a=5,变量 b=2
运算符 | 描述 | 实例 |
---|---|---|
+ | 加 | a + b 输出结果 7 |
- | 减 | a - b 输出结果 3 |
* | 乘 | a * b 输出结果 10 |
/ | 除 | a / b 输出结果 2.5 |
% | 取模(返回除法的余数) | a % b 输出结果 1 |
** | 幂 | a ** b 输出结果 25 |
// | 取整除 | a // b 输出结果 2 |
2.比较(关系)运算符
以下假设变量 a=5,变量 b=2
运算符 | 描述 | 实例 |
---|---|---|
== | 等于 | (a == b) 返回 False |
!= | 不等于 | (a != b) 返回 True |
> | 大于 | (a > b) 返回 True |
< | 小于 | (a < b) 返回 False |
>= | 大于等于 | (a >= b) 返回 True |
<= | 小于等于 | (a <= b) 返回 False |
注意
:比较运算符返回的结果类型是布尔值。要么是True
,要么是False
3.赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符 | |
+= | 加法赋值运算符 | |
-= | 减法赋值运算符 | |
*= | 乘法赋值运算符 | |
/= | 除法赋值运算符 | |
%= | 取模赋值运算符 | |
**= | 幂赋值运算符 | |
//= | 取整除赋值运算符 | |
:= | 海象运算符 |
4.逻辑运算符
and
:两个条件必须同时满足最终结果为真or
:两个条件只要一个为真,最终结果为真not
:取反,假变真,真变假
运算符 | 描述 | 实例 |
---|---|---|
and | 布尔"与" | |
or | 布尔"或" | |
not | 布尔"非" |
5.位运算符
运算符 | 描述 | 实例 |
---|---|---|
& | 与运算符 | |
| | 或运算符 | |
^ | 异或运算符 | |
~ | 取反运算符 | |
<< | 左移动运算符 | |
>> | 右移动运算符 |
6.成员运算符
运算符 | 描述 | 实例 |
---|---|---|
in | 如果在指定的序列中找到值返回 True,否则返回 False。 | |
not in | 如果在指定的序列中没有找到值返回 True,否则返回 False。 |
7.身份运算符
运算符 | 描述 | 实例 |
---|---|---|
is | is 是判断两个标识符是不是引用自一个对象 | |
is not | is not 是判断两个标识符是不是引用自不同对象 |
8.运算符优先级
以下表格列出了从最高到最低优先级的所有运算符, 相同单元格内的运算符具有相同优先级。 运算符均指二元运算,除非特别指出。 相同单元格内的运算符从左至右分组(除了幂运算是从右至左分组):
运算符 | 描述 |
---|---|
(expressions…), [expressions…], {key: value…}, {expressions…} | 圆括号的表达式 |
x[index], x[index:index], x(arguments…), x.attribute | 读取,切片,调用,属性引用 |
await x | await 表达式 |
** | 乘方(指数) |
+x, -x, ~x | 正,负,按位非 NOT |
*, @, /, //, % | 乘,矩阵乘,除,整除,取余 |
+, - | 加和减 |
<<, >> | 移位 |
& | 按位与 AND |
^ | 按位异或 XOR |
| | 按位或 OR |
in,not in, is,is not, <, <=, >, >=, !=, == | 比较运算,包括成员检测和标识号检测 |
not x | 逻辑非 NOT |
and | 逻辑与 AND |
or | 逻辑或 OR |
if – else | 条件表达式 |
lambda | lambda 表达式 |
:= | 赋值表达式 |
六、Python常见数据类型具体操作方法
1.字符串常用的操作方法
-
字符串的索引及切片
-
索引
- 字符串是一种有序容器类型的数据,可以通过下标(索引)取值
- 字符串可以通过索引值的正负两极取值
-
从左到右默认从
0
开始 -
从右到左默认从
-1
开始str1 = "今天又是充满希望的的一天" # 可以通过字符串的索引值取字符的实际值 print(str1[1]) # 天 print(str1[-2]) # 一
-
-
切片
-
切片是指对被操作的字符串对象的内容取一部分值,列表,元组都是支持切片操作
-
切片的语法格式:[起始:结束:步长]
str1 = "今天又是充满希望的的一天" # 只写开始,不写结束:默认到最后(默认包含开始索引值的内容) print(str1[6:]) # 希望的的一天 # 有开始也有结束:包含开始的索引值,不包含结束的索引值 # 切片的操作是一个左闭右开的区间 print(str1[6:9]) # 希望的 # 只写结束,不写开始:默认从0(索引)开始 print(str1[:9]) # 今天又是充满希望的 # 开始结束都不写 print(str1[:]) # 今天又是充满希望的的一天 # 对字符串切片操作是可以通过负数索引进行切片操作 print(str1[6:-4]) # 希望 # 当开始和结束的索引值没有交集的时候会取不到实际值 print(str1[-1:6]) # 步长,不写开始不写结束,步长为2 print(str1[::2]) # 今又充希的一
-
-
-
查找字符串中具体某个元素
- 方法一:使用
find()
str1 = "今天又是充满希望的的一天" # 如果该字符串有该元素那么返回元素的索引值 print(str1.find("希")) # 6 # 如果该字符串没有该元素那么返回的索引值是-1(表示没有该元素) print(str1.find("快")) # -1
- 方法二:使用
index()
str1 = "今天又是充满希望的的一天" # 如果该字符串有该元素那么返回元素的索引值 print(str1.index("希")) # 6 # 如果该字符串没有该元素那么程序会报错 print(str1.index("快")) # 报错
- 方法一:使用
-
count()
统计元素在整个字符串当中出现的次数str1 = "今天又是充满希望的的一天" # 会返回该元素在整个字符串当中出现的次数 print(str1.count("天")) # 2
-
replace()
替换字符串中的元素值str1 = "今天又是充满希望的的一天" # 替换字符串中的元素值 print(str1.replace("今", "明"))
-
使用
split()
对字符串进行切片str1 = "今天又是充满希望的的一天" # split对字符串进行切片的方法,返回的数据类型是列表,可以设置参数切几次,切好的数据是字符串类型 print(str1.split("天", 1)) # ['今', '又是充满希望的的一', '']
-
capitalize()
首字母大写,其余全部小写# capitalize()将整个字符串第一个元素(不管是大小写全部做大写处理)之后的内容里面的所有大写字母转化成小写字母 str2 = "abcdABCD" print(str2.capitalize()) # Abcdabcd
-
title()
根据字符串的空格将每个空格之后的首字母大写str3 = "abcd zxcv qwer" # 根据字符串的空格将每个空格之后的首字母大写(前提是空着之后是字母) print(str3.title()) # Abcd Zxcv Qwer
-
startswith()
检测字符串是否以指定元素开头str4 = "good good stady day day up" # 检测字符串是否以指定元素开头 print(str4.startswith("g")) # True print(str4.startswith("b")) # False print(str4.startswith("good")) # True
-
lower()
将整个字符串当中的所有大写字母转化为小写str5 = "I Love You" # 将整个字符串当中的所有大写字母转化为小写 print(str5.lower()) # i love you
-
去除自字符串前面或后面的空格元素
- 去除前面空格元素:
lstrip()
- 去除后面空格元素:
rstrip()
- 去除前后空格元素:
strip()
# 去除自字符串前面或后面的空格元素 str6 = " I Love You " # 去除后面空格元素 print(str6.rstrip()) # " I Love You" # 去除前面空格元素 print(str6.lstrip()) # "I Love You " # 去除前后空格元素 print(str6.strip()) # I Love You
- 去除前面空格元素:
-
isdigit()
判断字符串所有的元素是否由纯数字组成str7 = "12345qwer" # 判断字符串所有的元素是否由纯数字组成 print(str7.isdigit()) # False
-
使用固定的字符隔开字符串当中的所有元素
str8 = "abcd1234" # 字符串的拼接操作:使用固定的字符隔开字符串当中的所有元素 print("*".join(str8)) # a*b*c*d*1*2*3*4 print("-".join(str8)) # a-b-c-d-1-2-3-4 print("0".join(str8)) # a0b0c0d01020304
2.列表常用的操作方法
-
列表中增加数据
-
第一种方式:
append()
添加数据(默认是追加到列表末尾)name_list = ["宝总", "爷叔", "小江西", "蔡司令"] # 第一种方式:append()添加数据(后默认是追加到列表末尾) name_list.append("汪小姐") print(name_list) # ['宝总', '爷叔', '小江西', '蔡司令', '汪小姐']
-
第二种方式:
append()
插入数据name_list = ["宝总", "爷叔", "小江西", "蔡司令"] # 第二种方式:append()插入数据 # 插入到元素下标为1的位置 name_list.insert(1, "李李") print(name_list) # ['宝总', '李李', '爷叔', '小江西', '蔡司令']
-
第三种方式:
extend()
将容器类型数据拆分开来再添加name_list = ["宝总", "爷叔", "小江西", "蔡司令"] # 第三种方式:extend()将容器类型数据拆分开来再添加 name_list.extend(["李李", "汪小姐"]) print(name_list) # ['宝总', '爷叔', '小江西', '蔡司令', '李李', '汪小姐']
-
-
列表中查询数据
-
列表可以通过索引取值(元素),也支持切片操作
list1 = ["a", "b", "c", "d", "e"] print(list1[3]) # d print(list1[1:4]) # ['b', 'c', 'd'] print(list1[::2]) # ['a', 'c', 'e']
-
如果列表的切片步长为-1那么可以将列表反转
list1 = ["a", "b", "c", "d", "e"] print(list1[::-1]) # ['e', 'd', 'c', 'b', 'a']
-
-
列表中修改数据
-
通过索引修改数据:先获取具体要修改的索引值内容然后再赋值
list1 = ["a", "b", "c", "d", "e"] # 通过索引修改数据:先获取具体要修改的索引值内容然后再赋值 list1[1] = "张三" print(list1) # ['a', '张三', 'c', 'd', 'e']
-
-
列表中删除数据(当数据被删除的时候,因为列表是有序的序列,那么现存的数据索引会发生变化)
-
使用
pop()
方法删除name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"] # 使用pop()方法删除 name_list1.pop(2) print(name_list1) # ['宝总', '爷叔', '蔡司令', '李李', '汪小姐']
-
使用
remove()
方法删除name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"] # 使用remove()方法删除 name_list1.remove("蔡司令") print(name_list1) # ['宝总', '爷叔', '小江西', '李李', '汪小姐']
-
使用
clear()
清除列表中所有的数据name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"] # 使用clear()清除列表中所有的数据 name_list1.clear() print(name_list1) # []
-
使用特殊关键字
del
删除具体某个数据(通过索引获取)name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"] # 使用特殊关键字del删除具体某个数据(通过索引获取) del name_list1[2] print(name_list1) # ['宝总', '爷叔', '蔡司令', '李李', '汪小姐']
-
-
reverse()
列表反转name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"] # 列表反转 name_list1.reverse() print(name_list1) # ['汪小姐', '李李', '蔡司令', '小江西', '爷叔', '宝总']
-
count()
统计元素在整个列表当中出现的次数name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"] print(name_list1.count("爷叔")) # 1
-
index()
查询列表当中某个元素的索引值name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"] print(name_list1.index("宝总")) # 0
-
sort()
将列表中的数据进行排序-
从小到大排序
list2 = [3, 5, 1, 7, 16, 12, 20, 2] # sort()将列表中的数据进行排序(从小到大排序) list2.sort() print(list2) # [1, 2, 3, 5, 7, 12, 16, 20]
-
从大到小排序
list2 = [3, 5, 1, 7, 16, 12, 20, 2] # 从大到小进行排序 list2.sort(reverse=True) print(list2) # [20, 16, 12, 7, 5, 3, 2, 1]
-
3.元组常用的操作方法
元组和列表是一样,都是有序的容器类型的数据,但是区别是元组的数据不能被修改,当数据一旦被定义那么就是固定值,元组只支持查询数据功能。
t1 = (1, 2, 3, 4, 5, 6)
# 可以通过索引取值
print(t1[3])
# 可以支持切片操作
print(t1[0:2])
# index,count
print(t1.count(3)) # 1
print(t1.index(2)) # 1
4.字典常用的操作方法
-
字典的特性:
- 可以进行切片和索引取值
- 元素的位置很重
-
字典的快速创建键值对
dict2 = dict(a=1, b=2, c=3) print(dict2) # {'a': 1, 'b': 2, 'c': 3}
-
字典中查询数据
-
通过字典的键取值
dict1 = {"name": "张三", "age": 18, "sex": "男"} # 字典取值:通过字典的键取值 print(dict1["name"]) # 张三
-
查看字典中所有的键
dict1 = {"name": "张三", "age": 18, "sex": "男"} # 查看字典中所有的键 print(dict1.keys()) # dict_keys(['name', 'age', 'sex'])
-
查看指点中所有的值
dict1 = {"name": "张三", "age": 18, "sex": "男"} # 查看指点中所有的值 print(dict1.values()) # dict_values(['张三', 18, '男'])
-
获取字典的所有键值对
dict1 = {"name": "张三", "age": 18, "sex": "男"} # 获取字典的所有键值对 print(dict1.items()) # dict_items([('name', '张三'), ('age', 18), ('sex', '男')])
-
-
字典中增加数据
-
字典中的键一定是唯一的,值随意,当字典中有当前的键值对的时候,那么会通过键覆盖值
-
update()
给字典添加数据:支持单个键值对添加和多个键值对添加dict3 = {'a': 1, 'b': 2, 'c': 3} dict3.update({"d": 4, "e": 5}) print(dict3) # {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
-
setdefault()
添加字典中没有键的键值对数据dict3 = {'a': 1, 'b': 2, 'c': 3} dict3.setdefault("d", 4) print(dict3)
-
-
字典中修改数据
-
通过字典的键去修改值
dict4 = {'a': 1, 'b': 2, 'c': 3} dict4["a"] = 11 print(dict4) # {'a': 11, 'b': 2, 'c': 3}
-
-
字典中删除数据
- 通过
del
关键字删除值(键获取,最终是将整个键值对全部删除)dict5 = {'a': 1, 'b': 2, 'c': 3} del dict5["a"] print(dict5) # {'b': 2, 'c': 3}
- 通过
pop()
方法删除,通过键删除键值对dict5 = {'a': 1, 'b': 2, 'c': 3} dict5.pop("a") print(dict5) # {'b': 2, 'c': 3}
clear()
清空字典dict5 = {'a': 1, 'b': 2, 'c': 3} dict5.clear() print(dict5) # {}
- 通过
5.集合常用的操作方法
集合的特性就是去重,集合里面不存在重复的数据,集合的数据(元素)都是唯一的
集合默认是无序的序列,不能进行索引取值和切片,因为集合中的元素是没有前后顺序的
-
集合中新增数据
set1 = {1, 2, 3, 4, 5} # 集合可以添加数据,前提是集合中没有这个数据才能添加成功 set1.add(6) print(set1) # {1, 2, 3, 4, 5, 6}
-
集合中删除数据
set2 = {"a", 1, "张三", 2} set2.remove("a") print(set2) # {1, 2, '张三'}
6.列表、元组、集合的相互转化
-
列表转元组
list1 = [1, 2, 3, 3, 4, 5, 6, 7] # 列表转元组 tuple1 = tuple(list1) print(tuple1) # (1, 2, 3, 3, 4, 5, 6, 7) print(type(tuple1)) # <class 'tuple'>
-
元组转集合
tuple2 = (1, 2, 3, 3, 4, 5, 6, 7) # 元组转集合 set1 = set(tuple2) print(set1) # {1, 2, 3, 4, 5, 6, 7} print(type(set1)) # <class 'set'>
-
列表转集合
list1 = [1, 2, 3, 3, 4, 5, 6, 7] # 列表转集合 set2 = set(list1) print(set2) # {1, 2, 3, 4, 5, 6, 7} print(type(set2)) # <class 'set'>
-
如果列表和元组中的数据需要去重,那么可以直接转集合,再转回去
# 如果列表和元组中的数据需要去重,那么可以直接转集合,再转回去 # 集合变元组或者列表:去重案例 list1 = [1, 2, 3, 3, 4, 5, 6, 7] print(list(set(list1))) # [1, 2, 3, 4, 5, 6, 7] print(tuple(set(list1))) # (1, 2, 3, 4, 5, 6, 7)
七、Python中的可变数据类型与不可变数据类型
可变数据类型:当数据类型变量的值发生变化,内存地址值不变,那么该数据类型就是可变数据类型(内存地址值是唯一的)
- 可变数据类型:对元素可以进行任意的操作(增删改查)
- 列表
- 集合
- 字典
不可变数据类型:当数据类型变量的值发生变化,内存地址值改变,那么该数据类型就是不可变数据类型
- `不可变数据类型:对元素不能进行任意的操作(增删改查)
- 数字类型
- 整数类型
- 浮点数类型
- 布尔类型
- 字符串
- 元组
- 数字类型
注意
:字典的键一定是不可变的数据类型。字典,列表,集合不能当做字典的键。字典的值没有数据类型的要求
注意
:集合中的元素只能放不可变的数据类型
八、浅拷贝与深拷贝
1.浅拷贝
-
浅拷贝:针对不可变的数据类型进行拷贝
-
浅拷贝:复制一份数据,重新分配一块内存空间(引用原来数据值的内存地址),新的数据里面的值指向还是原来值的内存地址
-
引用:不同的变量里面保存的值是一样的时候,会在内存里面引用同一个内存地址值
-
浅拷贝可以通过赋值 = 来实现
-
浅拷贝:copy可以复制一份数据,但是引用地址还是原来数据的内存地址
-
浅拷贝只针对不可变的数据类型有效:数字类型,字符串,元组
-
针对不可变的数据类型,如果原数据被删除,只要内存地址在,那么被拷贝数据照常使用
# 从指定的模块中导入指定的对象或函数,并将其命名为copy,之后就可以直接使用copy来调用该对象(第一个copy代表模块名,第二个copy代表模块中的对象或者函数名) from copy import copy str1 = "今天又是充满希望的一天!" str2 = copy(str1) print(id(str1)) print(id(str2))
案例:使用浅拷贝对可变数据类型进行拷贝
from copy import copy
list1 = ["张三"]
list2 = []
copy_list1 = copy(list2)
new_list1 = list2.extend(["李四", list1])
copy_list2 = copy(list2)
new_list2 = list2.extend(["李四", list1])
list1.append("王五")
print(list2) # ['李四', ['张三', '王五'], '李四', ['张三', '王五']]
print(copy_list1) # []
print(copy_list2) # ['李四', ['张三', '王五']]
注意
:可变的数据类型不建议使用浅拷贝,因为当拷贝完之后,对原来数据进行修改,所有被拷贝好的数据也会发生变化
2.深拷贝
-
深拷贝:针对可变的数据类型进行拷贝
-
深拷贝可以对可变的数据类型进行拷贝,拷贝好的数据发生变化都是相互独立的不会受到影响
from copy import deepcopy list1 = ["张三"] list2 = [] copy_list1 = deepcopy(list2) new_list1 = list2.extend(["李四", list1]) copy_list2 = deepcopy(list2) new_list2 = list2.extend(["李四", list1]) list1.append("王五") print(list2) # ['李四', ['张三', '王五'], '李四', ['张三', '王五']] print(copy_list1) # [] print(copy_list2) # ['李四', ['张三']]
注意
:可变和不可变的数据类型都可以进行深拷贝,不可变的数据类型不建议使用深拷贝,比较占用内存
3.总结
1
-
使用浅拷贝拷贝可变的数据类型:源数据变化,被拷贝的数据也会变化
-
使用深拷贝拷贝可变的数据类型:源数据变化,被拷贝的数据不会变化
-
不可变的数据类型建议使用浅拷贝
- 不可变的数据类型使用浅拷贝和深拷贝的效果一样(但深拷贝比较占用内存)
-
可变的数据类型一定要使用深拷贝
-
不可变的数据类型使用方法操作完之后都是全新的数据,跟原来数据没有任何关系
- 因为字符串是不可变的数据类型,当使用字符串的所有方法时,生成都是全新地址全新值的数据,所以不会对源数据造成任何影响,方法执行会生成一个新的字符串,会开辟新的内存地址值
-
可变的数据类型使用方法操作完之后都是对原来的数据进行修改,跟原来的数据有密切的关系
-
数据的内容发生变化,都是在同一块内存地址值,内存地址值不会发生任何变化
九、流程控制
- 所有程序执行都有三大体系
- 顺序
- 分支
- 循环
1.if分支语句
-
if分支语句
age = int(input("请输入您的年龄")) if age >= 18: print("您已成年,可以上网") else: print("您未成年,禁止上网")
-
分支语句-多条件判断
score = int(input("请输入成绩1-100")) if score >= 90: print("优秀") elif score >= 80 and score < 90: print("良好") elif score >= 60 and score < 80: print("及格") else: print("不及格")
-
if语句后面跟随的判断条件是通过布尔值判断的
- Frue
- False
-
Python中所有的数据类型,都可以转化为布尔值
- Frue
- 非0的数字:小数,整数,负数
- 非空的字符串
- 非空的容器类型数据:列表,集合,元组,字典等等
- False
- 数字为0
- 为空的容器类型数据都为假
if -1: print("真的") else: print("假的")
- Frue
2.关键字match与case
-
在Python3.10环境更新之后新增了2个匹配的关键字
match
,case
可以用来代替多种情况name = input("请输入您的姓氏") match name: case "王": print("排名第一") case "张": print("排名第二") case "李": print("排名第三") case "刘": print("排名第四")
3.三目运算符
-
简写的if语句:比较两个数的大小
import random a = int(input("请输入一个1-10的整数")) b = random.randint(1,10) print(f"您输入的数字是:{a},随机生成的数字是:{b},两个数最大的值是:{a if a > b else b}")
4.循环
4.1.for循环
-
for循环一般情况会结合
range()
内建函数一起使用构建循环体- 例子1
# range(1,100)左闭右开天,1-99不包含100 for i in range(1, 100): print(i)
- 例子2
# range(10)循环10次,从0开始9结束 for i in range(10): print(i)
- 例子3
# range(10)循环10次,从0开始9结束 for i in range(10): print(i) else: print("for循环结束会执行else后面的代码")
-
for循环可以遍历所有容器类型的数据
- 例子1(字符串)
str1 = "今天又是充满希望的一天!" index = 0 for i in str1: print(f"当前元素的下标是:{index},元素具体值是:{i}") index += 1
- 例子2(列表)
list1 = [1, 2, 3, 4, "张三", "李四"] index = 0 for i in list1: print(f"当前元素的下标是:{index},元素具体值是:{i}") index += 1
- 例子3(字典)
dict1 = {"name": "张三", "age": "18", "sex": "男"} # dict1.values()获取字典中的值 for i in dict1.values(): print(i) # dict1.items()获取字典中的键值对 for i in dict1.items(): print(i)
4.2.while循环
-
while循环和if语句类似,区别在于if语句条件成立只执行一次,while条件只要成立就一直执行,直到条件不成立
i = 0 while i < 100: print(i) i += 1
-
死循环
while True: print("死循环无限执行!!!")
4.3.循环中的关键字break与continue
-
break
:退出当前整个循环for i in range(10): if i == 5: break print(i,end=" ") else: # 循环正常结束才会执行下面的代码 # 当循环中没有出现break终止循环那么else里面的代码就会执行 print("准备就绪")
i = 0 while i <= 10: i += 1 if i == 8: break print(i, end=" ") else: # 循环正常结束才会执行下面的代码 # 当循环中没有出现break终止循环那么else里面的代码就会执行 print("准备就绪")
-
continue
:跳出当次循环,继续下一次循环for i in range(10): if i == 5: continue print(i,end=" ") else: # 循环正常结束才会执行下面的代码 # 当循环中没有出现break终止循环那么else里面的代码就会执行 print("循环结束")
i = 0 while i <= 10: i += 1 if i == 8: continue # break print(i, end=" ") else: # 循环正常结束才会执行下面的代码 # 当循环中没有出现break终止循环那么else里面的代码就会执行 print("循环结束")
十、函数
-
什么是函数:函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段
-
函数的核心作用:提高应用的模块性,和代码的重复利用率
-
函数一般分为两种类型:
- 内建函数:Python自带封装好的函数直接可以使用
- 自定义函数:开发人员通过def关键字自定义函数功能
-
函数定义好了之后并不会执行,需要手动的调用才会执行。不管是内建函数还是自定义函数使用的时候都是通过
函数名()
进行使用 -
函数的三大要素
- 形参:形式参数(定义函数时,函数名后面括号内定义的参数叫做形参)
- 实参:实际参数(调用函数的时候,函数名后面括号内传递的值叫做实参)
- 返回值(定义函数时,函数体中通过return关键字返回的内容叫做返回值)
1.函数的定义与调用
-
函数语法:
def 函数名(参数列表): 函数体
-
定义函数使用
def
关键字,调用函数:函数名(实参)
# 定义函数 def sum(x, y): result = x + y # 返回值return:return会结束当前函数的执行,当功能结束之后需要返回到函数外部的内容 return result # 调用函数 number = sum(10, 20) print(number) # 30
2.指定形参和返回值的类型
-
位置参数:有几个形参就传递几个实参, 不能多也不能少
-
如果对函数的形参(返回值)进行指定类型,在调用函数的时候会有说明
# 指定形参的类型,返回值的类型 def celc(number1: int, number2: int, arithmetical: str) -> float: if arithmetical == "+": return number1 + number2 elif arithmetical == "-": return number1 - number2 elif arithmetical == "*": return number1 * number2 elif arithmetical == "/": return number1 / number2 else: print("对不起,您输入的是不支持的运算符") # 位置参数:有几个形参就传递几个实参, 不能多也不能少 print(celc(10, 20, "+"))
注意
:如果指定了类型,那么不一定要求规定类型也可以正常使用
3.关键字参数
-
关键字参数:通过关键字,来决定参数,指定传参
-
知道形参的前提下,可以指定形参传递实参值,实参通过关键字(形参)指定传过去
def function(a, b, c): print(a) print(b) print(c) function(c=2, a=3, b=5)
-
关键字传参一般结合位置参数一起使用
def function(a, b, c): print(a) print(b) print(c) function(777, c=4, b=5)
注意
:如果结合位置参数一起使用那么关键字参数要在位置参数后面
4.默认参数
-
如果使用默认形参,那么必须放到所有参数的最后面
-
如果形参有默认值,调用函数的时候可以不传递实参。如果传递了实参那么直接覆盖默认值。如果不传递实参,那么就使用默认值。
def function(a, c, b=20): print(a) print(b) print(c) function(a=10, c=30)
5.不定长参数
5.1.不定长位置参数*args
-
不定长位置参数用
*args
表示,如果函数使用不定长形参,那么可以接收任意的实参,而且是以元组的数据类型进行存储(加了一个星号 * 的参数会以元组(tuple)的形式导入) -
不定长参数可以让函数接受不确定长度的实参,可以是0到任意个参数
def function(*args): print(args) function("张三",20,3.14)
-
一般情况不定长的形参会结合位置参数一起使用(当位置形参结合不定长参数一起使用的时候,需要把位置参数放到不定长形参的前面)
# 不定长参数 def function(a, b, *args): print(a) print(b) print(args) function(10, 20, "张三", 30)
5.2不定长关键字参数**kwargs
- 不定长关键字参数
**kwargs
(加了两个星号**
的参数会以字典的形式导入)
def function(**kwargs):
print(kwargs)
function(name="张三", age=18, sex="男") # {'name': '张三', 'age': 18, 'sex': '男'}
6.函数的局部变量与全局变量
-
在函数中,当全局变量和局部变量重名时,默认优先使用局部变量
# 全局变量 # 作用域:可以在函数内部使用,整个py文件也可以使用 number = 888 def function(): # number变量在函数内部叫做局部变量 # 作用域:仅仅是在function函数里面进行使用,函数外部不能进行使用 number = 666 print(f"函数内部number的值是:{number}") print(f"函数调用之前number的值是:{number}") # 888 function() # 666 print(f"函数调用之后number的值是:{number}") # 888
-
在函数中,当全局变量和局部变量重名时,默认优先使用局部变量。如果一定要使用全局变量,那么可以使用关键字
global
进行声明,声明之后没有局部变量只会有全局变量# 全局变量 # 作用域:可以在函数内部使用,整个py文件也可以使用 number = 888 def function(): # number变量在函数内部叫做局部变量 # 作用域:仅仅是在function函数里面进行使用,函数外部不能进行使用 global number # number = 888 number = 666 # number = 666 print(f"函数内部number的值是:{number}") print(f"函数调用之前number的值是:{number}") # 888 function() # 666 print(f"函数调用之后number的值是:{number}") # 666
7.匿名函数
-
使用
lambda
来创建匿名函数 -
所谓匿名,意即不再使用
def
语句这样标准的形式定义一个函数- lambda 只是一个表达式,函数体比 def 简单很多
- lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去
- lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数
-
匿名函数的特点:
- 匿名函数可以有名字,可以没有
- 匿名函数调用跟普通函数没有区别
- 匿名函数没有使用
return
关键字也有返回值 - 匿名函数没有名字也可以调用,定义完函数之后加
()
进行调用
-
匿名函数的定义和使用:
# 匿名函数使用lambda关键字定义 # a,b:代表形参,a+b:代表函数内容(返回值) # function代表匿名函数的名字(自定义) function = lambda a, b: a + b # 调用匿名函数 result = function(10, 20) print(result) # 30
-
匿名函数简写:没有名字直接使用
print((lambda a, b: a + b)(20, 30)) # 50
8.函数闭包
-
闭包就是能够读取其他函数内部变量的函数,在本质上,闭包是将函数内部和函数外部连接起来的桥梁
-
闭包的定义:在函数的嵌套前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数的引用(内部函数的名字),核心点是内部函数使用外部函数的变量,我们把这个构造叫做闭包。
-
闭包的意义:函数被调用完,函数内的局部变量会被销毁,为了方便保存进行闭包操作
-
闭包的构成条件:
- 1.在函数嵌套的前提下形成
- 2.内部函数使用了外部函数的变量
- 3.外部函数返回了内部函数的引用(内部函数的名字)
-
闭包的作用:
- 闭包可以保存外部函数的变量,不会随着外部函数调用完就被销毁
- 由于闭包引用了外部函数的变量,外部函数的变量并没有得到释放,会保存到内存进行消耗
- 函数的引用(函数的名字)可以进行传递,如果复制给一个变量,那么该变量加上括号()那么就可以进行调用,指向的函数引用
-
闭包语法结构的定义和使用
-
案例一:
def function(*args, **kwargs): def sum(a, b): return a + b return sum # 如何执行add函数? # 方法一 result = function()(10, 30) print(result) # 40 # 方法二 sum = function() result1 = sum(20, 30) print(result1) # 50
-
案例二:
def function_out(number1): def function_inner(number2): result = number1 + number2 print(f"外部函数的值是:{number1},内部函数的值是:{number2},两个值相加的结果是:{number1 + number2}") return function_inner f = function_out(10) f(30) # 外部函数的值是:10,内部函数的值是:30,两个值相加的结果是:40 # 简写 function_out(10)(40) # 外部函数的值是:10,内部函数的值是:40,两个值相加的结果是:50
十一、模块与包的使用
-
模块是一个包含所有你定义的函数和变量的文件,其后缀名是
.py
。模块可以被别的程序引入,以使用该模块中的函数等功能(简单来说一个py文件就是一个模块,模块中包含变量、函数、类等,Python中的模块和包可以被其他模块进行导入使用) -
包就是一个py文件集合的项目包(包里面可以有很多的模块(py文件))
-
如何导包
-
方法一:
# 导入random模块,将random模块里面所有的内容进行导入(变量,函数,类) import random # 调用模块里面的randint方法。通过模块名.方法名()进行调用 print(random.randint(1, 10))
-
方法二:
# 指定功能导入(指定某一个变量,某一个函数,某一个类) # 具体导入某一个模块的方法或者函数以及变量或者类的时候可以用逗号隔开,导入多个 from random import randint,randrange # 如果是通过模块具体导入某个方法那么直接通过方法名()进行调用 print(randint(1, 10))
-
方法三:
- 在模块名比较复杂的情况下可以自定义模块名(符合标识符命名规则),如果使用了别名,原来的模块名会失效,只能用别名进行模块内容的调用
# 导入random模块中的所有内容(* 代表被导入模块的所有内容) from random import * print(randint(1, 10))
-
方法四:
# 导入random模块,给random模块起别名为r import random as r # 使用模块别名.方法名()进行调用 print(r.randint(1, 10))
-
注意
:模块名和包名一定要符合标识符的命名规则
十二、Python异常处理
-
异常定义:就是不符合语法规则,就会出现异常信息(bug,程序错误信息提示)
-
异常信息如下:
Traceback (most recent call last): File "D:\develop\PyCharm\workspace\pythonProjectSoftwareTest\30异常处理.py", line 1, in <module> print(a) NameError: name 'a' is not defined
-
异常信心的溯源
:File “D:\develop\PyCharm\workspace\pythonProjectSoftwareTest\30异常处理.py”, line 1, in <module> -
异常代码的具体详细信息
: print(a) -
异常的描述信息
:NameError: name ‘a’ is not defined
异常捕获
-
通过
try
关键字来捕获异常,通过except
关键字进行异常出现后的处理方式 -
如果try中没有出现异常,那么except里面的代码不会执行
-
如果try中有异常,那么出现异常后会直接接执行except里面的代码,try中异常代码后面的代码不会继续执行
try: print("捕获异常") print(a) print("捕获异常") except: print("捕获到了异常,开始执行某某程序")
-
else
,finally
关键字一起使用else
:try当中没有出现异常,那么会执行else里面的代码finally
:不管try当中有没有出现异常,都会执行finally中的代码块
try: print("捕获异常") print(a) print("捕获异常") except: print("try当中出现了异常,那么会执行except里面的代码块") else: print("try当中没有出现异常,那么会执行else里面的代码") finally: print("不管try当中有没有出现异常,都会执行finally中的代码块")
注意
:try是可以进行嵌套使用的
十三、文件常用操作
文件就是在电脑当中进行持久化储存的内容,不同的文件有不同格式
1.常见的文件类型
- 常见的文件类型:
- 文本:.txt、.doc、.wap 等
- 音频:.MP3、.wav、.wma、.midi 等
- 图像:.jpeg、.jpg、.gif、png 等
- 视频:.mp4、.avi、.mpg 等
- 表格:.xlsx 等
- 网页:.html 等
- …… 等
2.文件的属性
- 如果需要定位一个文件那么可以用不同的路径表示
- 绝对路径:绝对路径是指目录下的绝对位置,直接到达目标位置,通常是从盘符开始的路径
- 路径信息 + 文件名及格式
- 相对路径:相对路径就是指由这个文件所在的路径引起的跟其它文件(或文件夹)的路径关系
- 相对文件参照物不同,那么相对路径也会不同。相对某个具体文件的相对位置(不常用)
- 路径信息可以进行跳转
./
代表当前目录../
代表上级目录./
和.//
都是可以无限使用的
- 相对文件参照物不同,那么相对路径也会不同。相对某个具体文件的相对位置(不常用)
- 绝对路径:绝对路径是指目录下的绝对位置,直接到达目标位置,通常是从盘符开始的路径
3.文件的读写模式
open()
:打开文件read()
:读取文件(一次性读取文件全部内容)write()
:写入内容到文件中close()
:关闭文件
3.1.读
-
读取文件内容
read()
:一次性读取文件全部内容readline()
:读取一行readlines()
:读取全部内容,每次一行一行读取,返回的是一个集合,以一行为列表的每个元素
# 如果需要读(r)一个文件,当文件不存在的时候程序会报错 # 打开文件open() # "C:/Users/xiongjian/Desktop/test.txt"代表文件所在路径和文件名 # "r" 代表读,默认 # encoding="utf-8"代表文件的编码格式 file = open("C:/Users/xiongjian/Desktop/test.txt", "r", encoding="utf-8") # read()读取文件全部内容 result = file.read() #打印文件内容 print(result) # close()关闭文件 file.close()
注意
:如果需要读一个文件,当文件不存在的时候程序会报错
3.2.写
-
写入内容到文件中
# 打开文件open() # "C:/Users/xiongjian/Desktop/test.txt"代表文件所在路径和文件名 # "w" 代表写 # encoding="utf-8"代表文件的编码格式 file = open("C:/Users/xiongjian/Desktop/test.txt", "w", encoding="utf-8") # write()写入内容 file.write("这是我写入的内容") # close()关闭文件 file.close()
注意
:如果需要写文件,文件不存在的时候会自动生成一个文件并写入内容
3.3.读写模式总结
w
:代表写入- 如果以写入的模式打开文件,文件不存在时会新建一个文件,然后进行写入
- 如果以写入的模式打开文件,文件存在并且有内容的情况下,会覆盖原来内容,写入新内容
r
:代表读取- 如果以读的模式打开文件,那么文件不存在时程序会报错
- 不指定读写或其他参数打开文件,默认是以读的模式打开文件。因为形参有默认值是
mode='r'
a
:代表追加- 追加写入内容,不会将原来内容清除,而是追加到内容的末尾
注意
:以上三种读写模式一般都是用于普通文本(txt格式的文件)。
- 如果是其他文件:会以二进制的方式读取(所有文件的存储方式都是以二进制为主,所以以储存方式读取可以保证文件的完整性)
rb
:以二进制的格式打开一个文件,用于读wb
:以二进制的格式打开一个文件,用于写ab
:以二进制的格式打开一个文件,用于追加写入- 二进制读写使用场景:图片、音频、视频、Excel等等
注意
:如果是二进制的文件,那么不要指定编码格式,不然程序会报错
- 任意的读写模式后面都可以加上
+
号 - 作用:可以让文件同时具备读写功能
r+
w+
a+
rb+
wb+
ab+
注意
:r+
、w+
、a+
、rb+
、wb+
、ab+
可以对打开的文件对象模式进行读和写(但是不能同时进行)
4.文件的常用操作
- 先导入os(文件操作)模块
-
remove()
:删除文件(如果删除的文件不存在,程序会报错)import os # remove()删除文件,注意:如果删除的文件不存在,程序会报错 # r:当路径信息中有转义字符,可以消除转义 os.remove(r"C:\Users\xiongjian\Desktop\test.txt")
-
renames()
:重命名import os # renames()重命名,语法:renames("原文件名","新文件名") # r:当路径信息中有转义字符,可以消除转义 # 如果新文件名前面没有路径信息,那么默认保存在当前项目中,相当于原文件移动到当先项目路径并改名(注意:如果文件与项目文件不再同一个磁盘下代码会报错) os.renames(r"D:\test.txt", "tests.txt")
-
复制
-
getcwd()
:获取当前文件的绝对路径信息import os # 获取当前文件的绝对路径信息 print(os.getcwd())
-
mkdir()
:创建文件夹import os # mkdir()创建文件夹 os.mkdir("test")
-
rmdir()
:删除文件夹(注意:如果删除一个不存在的文件夹会报错,删除非空文件夹也会报错)import os # rmdir()删除文件夹,注意:如果删除一个不存在的文件夹会报错,删除非空文件夹也会报错 os.rmdir(r"C:\Users\xiongjian\Desktop\test")
-
listdir()
:获取文件夹内的文件及目录信息(返回的是一个列表)import os # listdir()获取文件夹内的文件及目录信息 print(os.listdir(r"C:\Users\xiongjian\Desktop\test")) # 获取文件夹内的文件及目录个数 print(len(os.listdir(r"C:\Users\xiongjian\Desktop\test")))
-
5.案例(删除一个非空的文件夹)
import os
# 创建一个函数
def delete_folder(path):
# os.path.exists(path)判断返回路径是否存在。返回的是布尔值
if os.path.exists(path):
# 遍历文件夹下所有子目录和文件并删除
# os.walk():扫描某个指定目录下所包含的子目录和文件,返回的是一个迭代器
for root, dirs, files in os.walk(path, topdown=False):
for file in files:
# os.remove删除文件
# os.path.join(root, file)把目录和文件名合成一个路径
os.remove(os.path.join(root, file))
for dir in dirs:
# os.rmdir()删除文件夹
# os.path.join(root, 文件夹)把目录和文件名合成一个路径
os.rmdir(os.path.join(root, dir))
os.rmdir(path)
else:
print("Folder not found 找不到文件夹")
# 调用函数:
delete_folder(r"C:\Users\xiongjian\Desktop\test")
十四、面向对象
- 软件测试及开发比较主流的开发思想分为两种
面向过程
:需要实现一个功能的时候,看中的是开发的步骤和过程,每一个步骤都是亲力亲为用代码去编写然后实现功能面向对象
:需要实现一个功能的时候,不看中开发的步骤和过程,核心是谁来帮我实现这个功能- 在面向对象的编程中,对象是数据和与之相关的操作的封装。这种范式使得代码更加模块化、可重用性更高,并且更易于理解和维护。
- 面向对象的三大特征:
封装
继承
多态
1.面向对象技术简介
类(Class)
:用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例方法
:类中定义的函数类变量
:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用数据成员
:类变量或者实例变量用于处理类及其实例对象的相关的数据方法重写
:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写局部变量
:定义在方法中的变量,只作用于当前实例的类实例变量
:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用self
修饰的变量继承
:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。实例化
:创建一个类的实例,类的具体对象对象
:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法
2.封装
- 将特征及行为封装成类
特征
:设置成类的实例属性行为
:设置成类的实例方法
- 类的基本定义和使用:
- 如何定义类
- 如何创建对象
- 实例属性封装
- 实例方法封装
1.1.类的实例属性定义和实例方法定义
-
类的实例属性定义和实例方法定义
- 类里面并且在init构造方法里面定义的变量,叫做实例属性
- 类里面定义的函数,叫做实例方法,默认有个
self
参数(没人加任何装饰器)
# 定义一个人类 # 使用class关键字创建类:class关键字后面接类名(类名要符合标识符命名规则,并且一般推荐使用大驼峰命名法) # 在不发生继承的情况下,类后面的括号可写可不写 class Person(): # 类有一个名为 __init__() 的特殊方法(构造方法,有的称之为魔法方法),该方法在类实例化时会自动调用 # 当对象一旦被创建,自动执行init构造方法里面的内容 def __init__(self): # self代表对象本身 # 特征:设置成类的实例属性 # 对象的实例属性全部封装到init构造方法中 self.name = "张三" self.age = 18 self.sex = "男" # 行为:设置成类的实例方法 # 类当中的函数叫做方法:函数可以没有形参,而方法一定要有一个形参(对象本身self) # 默认的self形参后面可以自定义任何类型的形参:位置参数,不定长参数,默认参数等等...... def sleep(self, time): print(f"睡觉,睡了{time}小时") def eat(self): print("吃饭") def play_games(self): print("玩游戏") # 如何创建一个对象(对象是通过类实例化的产物) # 通过人类Person创建一个对象,person1代表对象 person1 = Person() # 通过人类Person创建一个对象,person2代表对象 person2 = Person() # 实际对象是谁,那么谁就是self # 所有通过Person类创建的对象全部拥实例属性和实例方法
1.2.实例属性和实例方法的使用
-
实例属性和实例方法的使用
# 定义一个人类 # 使用class关键字创建类:class关键字后面接类名(类名要符合标识符命名规则,并且一般推荐使用大驼峰命名法) # 在不发生继承的情况下,类后面的括号可写可不写 class Person(): # 类有一个名为 __init__() 的特殊方法(构造方法,有的称之为魔法方法),该方法在类实例化时会自动调用 # 当对象一旦被创建,自动执行init构造方法里面的内容 def __init__(self): # self代表对象本身 # 特征:设置成类的实例属性 # 对象的实例属性全部封装到init构造方法中 self.name = "张三" self.age = 18 self.sex = "男" # 行为:设置成类的实例方法 # 类当中的函数叫做方法:函数可以没有形参,而方法一定要有一个形参(对象本身self) # 默认的self形参后面可以自定义任何类型的形参:位置参数,不定长参数,默认参数等等...... def sleep(self, time): print(f"睡觉,睡了{time}小时") def eat(self): print("吃饭") def play_games(self): print("玩游戏") # 如何创建一个对象(对象是通过类实例化的产物) # 通过人类Person创建一个对象,person1代表对象 person1 = Person() # 通过人类Person创建一个对象,person2代表对象 person2 = Person() # 实际对象是谁,那么谁就是self # 所有通过Person类创建的对象全部拥实例属性和实例方法 print(person1.name) # 张三 print(person1.age) # 18 print(person1.sex) # 男 # 通过对象调用实例方法 # 对象名.方法名() person1.sleep(7) # 睡觉,睡了7小时 person1.eat() # 吃饭 person1.play_games() # 玩游戏 # 每一个对象都可以调用相同的实例方法(在内存里面是统一管理的区域) print(person2.name) # 张三 print(person2.age) # 18 print(person2.sex) # 男 person2.sleep(8) # 睡觉,睡了8小时 person2.eat() # 吃饭 person2.play_games() # 玩游戏
1.3.自定义实例属性
-
在实例方法当中使用实例属性
class Person(): # 因为创建对象时会自动调用init构造方法,那么如果需要创建对象的时候传递实参,需在init构造方法中就应该定义形参 def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def sleep(self, time): print(f"睡觉,睡了{time}小时") def eat(self): print("吃饭") def play_games(self): print("玩游戏") # 实例方法中可以使用实例属性 def show(self): # 通过self.属性名进行使用 print(f"姓名:{self.name},年龄:{self.age},性别:{self.sex}") person1 = Person("张三", 18, "男") person1.show() # 姓名:张三,年龄:18,性别:男 person2 = Person("李四", 20, "女") person2.show() # 姓名:李四,年龄:20,性别:女
1.4.类属性和类方法的定义
-
类属性和类方法的定义
- 类里面定义的变量,就叫做类属性
- 加上装饰器:
@classmethod
的方法叫做类方法
class Person(): # 类里面定义的变量,就叫做类属性 # name就是类属性 name = "张三" def __init__(self): # 类里面并且在init构造方法里面定义的变量,叫做实例属性 self.name1 = "李四" # 类方法的定义 # 加上装饰器:@classmethod # 默认的第一个参数是cls:代表类名 Person = cls @classmethod def sleep(cls): print("类方法sleep被调用了") def eat(self): print("实例方法eat被调用了")
1.5.类属性和类方法的使用
-
类属性和类方法的使用
- 类只能调用类属性和类方法,不能使用实例方法和实例属性
- 对象可以使用类属性和实例属性,类方法和实例方法
class Person(): name = "张三" def __init__(self): self.name1 = "李四" @classmethod def sleep(cls): print("类方法sleep被调用了") def eat(self): print("实例方法eat被调用了") # 类只能调用类属性和类方法,不能使用实例方法和实例属性 # 类属性和类方法的使用 # 通过类调用类属性:类名.属性名 print(Person.name) # 张三 # 通过类调用类方法:类名.方法名() Person.sleep() # 类方法sleep被调用了 # 对象可以使用类属性和实例属性,类方法和实例方法 # 创建对象 person = Person(); # 对象调用类属性 print(person.name) # 张三 # 对象调用实例属性 print(person.name1) # 李四 # 对象调用类方法 person.sleep() # 类方法sleep被调用了 # 对象调用实例方法 person.eat() # 实例方法eat被调用了
-
总结:实例属性和实例方法跟类属性类方法的区别
类只能使用类属性和类方法
对象可以使用类属性和实例属性以及类方法和实例方法
1.5.静态方法的定义及使用
-
类中除了实例方法和类方法还有
静态方法
-
静态方法
:类中的函数,第一个参数不是self
也不是cls
而可以没有参数 -
类和对象都可以使用静态方法的使用
-
静态方法的定义及使用
class Person(): name = "张三" def __init__(self): self.name = "张三" # 静态方法的定义 # 静态方法:使用@staticmethod装饰器 @staticmethod def play_games(): print("我是play_games静态方法") # 类方法 @classmethod def sleep(cls): print("类方法sleep被调用了") # 实例方法 def eat(self): print("实例方法eat被调用了") # 类和对象都可以使用静态方法的使用 # 类调用静态方法play_games 类名.静态方法名() Person.play_games() # 我是play_games静态方法 # 创建对象 person = Person() # 对象调用静态方法play_games 对象名.静态方法名() person.play_games() # 我是play_games静态方法
了解
:类当中的方法可以使用装饰器@property
变成属性
3.继承
- 在程序当中,继承的描述是多个类之间的所属关系
- 如果一个A类里面有分装好的属性和方法,那么B类继承A类之后,可以直接使用A类的所有属性和方法
- 如果类与类之间发生了继承关系,那么A类就叫做父类(基类)B类叫做子类
- 继承的类型有两种
- 单继承
- 多继承
3.1.单继承的使用
class Person():
hobby = "钓鱼"
def __init__(self):
self.name = "张三"
# 实例方法
def eat(self):
print("实例方法eat被调用了")
# 类方法
@classmethod
def sleep(cls):
print("类方法sleep被调用了")
# 静态方法
@staticmethod
def play_games():
print("静态方法play_games被调用了")
# Person2类继承了Person类(Person2是子类,Person是父类)
class Person2(Person):
pass
# 根据Person2类创建对象
p1 = Person2()
# 使用Person类当中的类属性
print(p1.hobby) # 钓鱼
# 使用Person类当中的实例属性
print(p1.name) # 张三
# 使用Person类当中的类方法
p1.sleep() # 类方法sleep被调用了
# 使用Person类当中的实例方法
p1.eat() # 实例方法eat被调用了
# 使用Person类当中的静态方法
p1.play_games() # 静态方法play_games被调用了
3.2.多继承的使用
-
当父类有同名方法和同名属性(包括构造方法,魔法属性),会优先使用第一个继承的方法或者属性,不会重复执行也不会覆盖
-
使用魔法属性
__mro__
可以显示继承关系class Person(): hobby = "钓鱼" def __init__(self): self.name = "张三" # 实例方法 def eat(self): print("实例方法eat被调用了") # 类方法 @classmethod def sleep(cls): print("类方法sleep被调用了") # 静态方法 @staticmethod def play_games(): print("静态方法play_games被调用了") class Person2(): age = 18 def __init__(self): self.height = 180 # Person3类继承了Person类和Person2类 class Person3(Person, Person2): pass # 根据Person3类创建对象 p1 = Person3() # 使用Person类当中的类属性 print(p1.hobby) # 钓鱼 # 使用Person类当中的实例属性 print(p1.name) # 张三 # 使用Person类当中的类方法 p1.sleep() # 类方法sleep被调用了 # 使用Person类当中的实例方法 p1.eat() # 实例方法eat被调用了 # 使用Person类当中的静态方法 p1.play_games() # 静态方法play_games被调用了 # 使用Person2类当中的类属性 print(p1.age) # 18 # 使用Person2类当中的实例属性 # 当父类有同名方法和同名属性(包括构造方法,魔法属性),会优先使用第一个继承的方法或者属性,不会重复执行也不会覆盖 # print(p1.height) # 执行报错 因为只会执行Person2类中的__init__构造方法,该方法中没有height实例属性 # 通过魔法属性__mro__显示继承关系 print( Person3.__mro__) # (<class '__main__.Person3'>, <class '__main__.Person'>, <class '__main__.Person2'>, <class 'object'>)
总结
:当子类方法和属性跟父类冲突时(属性和方法重名),优先使用子类重名的属性或者方法
3.3.子类调用父类同名属性和方法
通过内建函数
super()
可以调用父类的同名方法和属性
class Person():
def eat(self):
print("Person类中的实例方法eat被调用了")
class Person2():
def eat(self):
print("Person2类中的实例方法eat被调用了")
# Person3类继承了Person类和Person2类
class Person3(Person, Person2):
def eat(self):
# 通过内建函数super()可以调用父类的同名方法(使用父类的eat()方法)
super().eat()
# 默认情况子类和父类属性方法同名优先使用子类属性和方法
p1 = Person3()
p1.eat() # Person类中的实例方法eat被调用了
4.多态
-
在程序设计中,鸭子类型是动态类型的一种风格。
-
鸭子类型:当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子
-
忽略对象的实际形态(状态),而是以胜任的方式去充当该类型。
-
多态的概念:多态是指一类事物有多种形态,忽略对象的实际形态(状态),而是以胜任的方式去充当该类型。
class Person(): def __init__(self): self.name = "张三" def play_games(self): print("玩游戏") # 创建一个person对象 person = Person() # 创建一个function函数 def function(): person.play_games() print(person.name) # 调用function函数 function()
5.数据类装饰器
-
数据类装饰器:可以对类进行装饰的装饰器
-
自动为类创建很多特殊方法包括魔法方法,不需要手动的定义
init
直接使用,实例属性的另外一种定义格式 -
数据类装饰器的使用:
- 先导入
dataclasses
模块 - 然后使用
@dataclasses.dataclass
import dataclasses # 该模块在Python3.7版本之后才能使用 # 数据类定义的变量可以被类方法和实例方法使用 @dataclasses.dataclass class Person(): name = "张三" # 实例属性的定义 age: int = 18 def show(self): print(f"我的年龄是:{self.age}岁") @classmethod def show2(cls): print(f"我的年龄是:{cls.age}岁") # 当创建对象传递实参,当数据被实例属性使用的时候会用用实参传递过来的值,类属性使用的时候会使用默认值 person = Person(20) person.show() # 我的年龄是:20岁 person.show2() # 我的年龄是:18岁
- 先导入
十五、装饰器
- 装饰器的概念:可以在不修改原来代码的情况下(函数原有的功能),为装饰器的对象(原来的函数)增加新的功能或者添加限制条件以及帮助输出
- 装饰器的常用的种类:
- 函数的装饰器
- 类的装饰器
- 主要的设计模式:开放封闭的原则(对外扩展开发,对内关闭修改)
1.装饰器的定义
-
装饰器本身是一个函数
-
装饰器的返回值是一个函数的引用(函数名字)
-
装饰器只能必须一定是一个形参(形参:用来接收函数的引用(接收函数的名字))
-
核心的使用原则:装饰器是给已有的函数增加额外的功能,本质上是一个闭包函数
-
装饰器的功能特点:
- 不修改被装饰的函数原代码
- 不修改已有函数的调用方式
- 给已有函数增加额外功能(通过函数外部的装饰器实现)
# 场景:去某平台购物,先登录才能添加商品到购物车 def login(function): def login_in(): print("进入登陆页面") print("输入账号密码点击登陆") print("正在进行登陆验证......") print("登陆成功") function() # function函数的引用: function = shopping ---> function() = shopping() return login_in def shopping(): print("买个iPhone15手机") # 这里的shopping变量可以随便命名 shopping = login(shopping) # shopping = login_in shopping() # shopping() = login_in()
-
代码执行流程
2.装饰器的语法糖使用
-
Python提供了装饰器的精简的书写方式:
语法糖格式
-
@装饰器的名字,通过语法糖完成对已有函数的装饰
-
注意:装饰器要写在被装饰的函数定义的上面
# 场景:去某平台购物,先登录才能添加商品到购物车 def login(function): def login_in(): print("进入登陆页面") print("输入账号密码点击登陆") print("正在进行登陆验证......") print("登陆成功") function() return login_in @login # @login等同于shopping = login(shopping) def shopping(): print("买个iPhone15手机") shopping()
-
解释器在执行代码的时候遇到装饰器会先加载装饰器代码并执行
# 会打印输出 "装饰器代码已经开始执行......" def login(function): def login_in(): print("登陆成功") function() print("装饰器代码已经开始执行......") return login_in @login def shopping(): print("买个iPhone15手机")
3.装饰器的使用场景
-
统计一个函数的执行时间
-
输出日志信息
-
缓存处理
-
实现路由
统计一个函数的执行时间案例实现
import time def get_time(function): def inner(): begin = time.time() function() end = time.time() print(f"当前模块代码执行的时间是:{end - begin}秒") return inner @get_time def count(): for i in range(1, 2000000): print(i) count()
4.带有参数的装饰器
- 使用装饰器完成符号传递实参进行运算
def operation(flag):
def out_funciton(fn):
def inner_function(number1, number2):
if flag == "+":
print("您输入的符号是加号,正在努力计算结果......")
elif flag == "-":
print("您输入的符号是减号,正在努力计算结果......")
elif flag == "*":
print("您输入的符号是乘号,正在努力计算结果......")
elif flag == "/":
print("您输入的符号是除号,正在努力计算结果......")
result = fn(number1, number2)
return result
return inner_function
return out_funciton
@operation("+")
def add(a, b):
return a + b
@operation("-")
def subtract(a, b):
return a - b
@operation("*")
def multiply(a, b):
return a * b
@operation("/")
def divide(a, b):
return a / b
print(add(12, 30))
print(subtract(40, 20))
print(multiply(2, 9))
print(divide(9, 3))
5.带有参数的装饰器
十六、生成器反射
-
使用了
yield
的函数被称为生成器 -
yield
是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器 -
当在生成器函数中使用
yield
语句时,函数的执行将会暂停,并将yield
后面的表达式作为当前迭代的值返回。然后,每次调用生成器的next()
方法或使用for
循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到yield
语句。这样,生成器函数可以逐步产生值,而不需要一次性计算并返回所有结果 -
生成器当中可以有一个或者多个
yield
关键字 -
调用一个生成器函数,返回的是一个迭代器对象
-
生成器的定义及使用
def function(number): while number > 0: yield number number -= 1 # 创建生成器对象 fun = function(5) # 通过迭代生成器获取值 print(next(fun)) # 输出: 5 print(next(fun)) # 输出: 4 print(next(fun)) # 输出: 3 # 使用 for 循环迭代生成器 for value in fun: print(value) # 输出: 2 1
十七、反射
- 反射原理:通过字符串的名字(属性名,方法名),对实例对象进行修改和访问
- 对类对对象进行属性和方法的操作(添加,删除,修改,查看)
1.通过反射添加或覆盖对象方法
-
使用内建函数
setattr()
class A(): def a(self): print("这是a方法") def b(self): print("这是b方法") def c(self): print("这是c方法") x = A() # 给x对象设置一个动态实例方法 setattr(x, "d", print) x.d("通过d方法输出内容") setattr(x, "d", input) result = x.d("通过d方法获取用户输入内容:") print(result) # 覆盖 setattr(x, "b", print) x.b("这是通过反射覆盖b方法")
2.通过反射删除
-
使用内建函
delattr()
class A(): def a(self): print("这是a方法") def b(self): print("这是b方法") def c(self): print("这是c方法") x = A() # 删除 delattr(x, "a")
3.通过反射判断是否存在指定的方法
-
使用内建函数
hasattr()
class A(): def a(self): print("这是a方法") def b(self): print("这是b方法") def c(self): print("这是c方法") x = A() print(hasattr(x, "a")) # True print(hasattr(x, "d")) # False
4.通过反射读取方法
-
使用内建函数
getattr()
class A(): def a(self): print("这是a方法") def b(self): print("这是b方法") def c(self): print("这是c方法") x = A() for i in ["a", "b", "c"]: function = getattr(x, i) function()
十八、第三方库
- 需要完成具体某个功能甚至整体功能会引入第三方库
- 第三方库:模块,包,库
1.自动化测试使用的第三方库
- 接口自动化:requests
- web自动化:selenium
- app自动化:appium
- 测试报告:allure
2.第三方库的安装、卸载、查看
-
安装
pip install 第三方库的名字(包名)
-
卸载
pip uninstall 第三方库的名字(包名)
-
查看
#查看当前环境的包名字以及版本号 pip list
3.虚拟环境和本地环境的区分
- 虚拟环境
虚拟环境里面的项目包第三方库都是独立的,不会跟本地冲突也不会有任何印象