Python基础
一、数据类型
1. 变量
1.1 定义
-
Python 与其他语言的区别:
-
Python:变量相当于标签
-
其他语言:变量相当于容器
-
-
先赋值后使用
str = "hello"
print(str)
1.2 变量的数据类型
-
静态类型语言:在使用变量之前定义其数据类型
-
动态类型语言:在给变量赋值时确定其数据类型,对变量的每一次赋值,都有可能改变变量的类型
【Python 就是动态类型语言】
1.3 查看变量数据类型
-
语法:
type(变量)
-
可以直接输出,也可以用变量存储结果再输出
-
type()
查看的是变量存储的数据的类型,即变量无类型
2. 标识符
-
由字母、数字、下划线组成,不能以数字开头,且区分大小写(可用中文,但不推荐)
-
单独的下划线
_
是一个特殊变量,表示上一次运算的结果 -
见名知意
-
关键字大写后可作为标识符
>>> 55
55
>>> _+100
155
3. 字面量
-
在代码中被写下来的固定的值
-
Python 中常用的6种数据类型
类型 | 描述 | 说明 |
---|---|---|
数字(Number) | 支持:整数、浮点数、复数、布尔 | 复数:4+3j(以 j 结尾表示复数) |
字符串(String) | 描述文本的一种数据类型 | 由任意数量的字符组成 |
列表(List) | 有序的可变序列 | 可有序记录一堆数据(最常用) |
元组(Tuple) | 有序的不可变序列 | 可有序记录一堆不可变的数据集合 |
集合(Set) | 无序不重复集合 | 可无序记录一堆不重复的的数据集合 |
字典(Dictionary) | 无序 Key-Value 集合 | 可无序记录一堆 Key-Value 型的数据集合 |
-
科学计数法
- e(E)表示以10为底的指数,e 之前为数字部分,之后为指数部分,而两部分必须同时出现,指数必须为整数
45e-5 # 0.00045
- 复数型数据
a+bJ 或 a+bj
可通过x.real
和x.imag
来分别获取 x 的实部和虚部,结果都是浮点型
>>> x.real
12.0
>>> x.imag
34.0
4. 转换类型
4.1 为什么
-
从文件中读取的数字,默认是字符串,需要转换成数字类型
-
input()
语句默认结果是字符串,有数字也需要转换 -
将数字转换成字符串用以写出到外部系统
4.2 常见的转换语句
语句(函数) | 说明 |
---|---|
int(x) |
转换为整数 |
float(x) |
转换为浮点数 |
str(x) |
将对象 x 转换为字符串 |
注:浮点数转换为整数时会丢失精度
二、注释
- 单行注释
# 我是单行注释
- 多行注释
"""
我是多行注释
"""
- 工作日志说明:进行没有完成的功能备注
# TODO 说明文字
三、运算符
1. 算术运算符
-
基本运算:加、减、乘、除、取余
-
其他:
-
//
:取整除,c **= a
等价于c = c ** a
-
**
:指数,c //= a
等价于c = c // a
-
2. 链式比较
在 Python 中,可以使用链式比较对多个值进行比较,简化代码
x = 5
print(1 < x < 10) # 输出 True,相当于 1 < x and x < 10
print(1 < x > 3) # 输出 True,相当于 1 < x and x > 3
print(1 <= x < 5) # 输出 False,相当于 1 <= x and x < 5
类似地,比较运算符可以使用等于和不等于运算符确定某些数字是否相等
length = 23
height = 23
width = 6
if length == height and height == width and width == length:
print("This is a cube")
else:
print("This is a cuboid")
# 简化代码
if length == height == width:
print("This is a cube ")
else:
print("This is a cuboid ")
四、内置函数
BIF(Built-in Functions):为方便程序员快速编写脚本程序,Python 提供了丰富的内置函数,如 print()、input() 等
1. input()
- 语法格式:
name = input()
input(提示信息)
:输入内容前,输出提示内容
name = input("你是谁?")
print("哦,你是:%s" % name)
注:无论键盘输入什么类型的数据,获取的数据永远都是字符串类型
2. id() 函数
-
返回指定对象的唯一 id
-
id 是对象的内存地址,并且在每次运行程序时都不同
-
除了某些具有恒定唯一 id 的对象,比如 -5 到 256 之间的整数
id(object) # object:任何对象,字符串、数字、列表等等
五、垃圾回收
-
Python 具有自动内存管理功能,对于没有任何变量指向的值(称为垃圾数据),系统会自动将其删除
-
也可以使用 del 语句删除一些对象引用
del x
注:删除变量 x 后,若再使用它,将出现变量定义错误(name 'x' is not defined)
六、条件分支
if 条件:
...
elif 条件2:
...
else:
...
示例:
if guess == secret:
print("猜中了!")
else:
if guess > secret:
print("猜大了")
else:
print("猜小了")
-
注:
-
不要忘记判断条件后的冒号
-
Python 通过缩进判断语句的归属(作用域)
-
input()
语句可直接写在条件中 -
可嵌套使用(关键点:空格缩进)
-
七、循环结构
1. while循环
while 条件:
...
示例:
while guess != 8:
temp = input("猜错了,请重新输入:")
guess = int(temp)
if guess == secret:
print("猜中了!")
else:
if guess > secret:
print("猜大了")
else:
print("猜小了")
嵌套语句:
while 条件1:
...
while 条件2:
...
注意条件设置,避免造成死循环
2. 补充知识
2.1 print 输出不换行
默认 print 输出时自动换行,只要在print
中加上end = ' '
,即可输出不换行
print("hello", end = '')
print("world", end = '')
2.2 制表符 \t
可以实现多行字符串对齐
案例:打印九九乘法表
i = 1
while i <= 9:
j = 1
while j <= i:
print(f"{j} * {i} = {j * i}\t", end='')
j += 1
i += 1
print()
3. for 循环
for 临时变量 in 待处理数据集(序列):
...
示例:遍历字符串
name = "itheima"
# for 循环处理字符串
for x in name:
print(x)
3.1 说明
-
for 循环无法定义循环条件,只能从被处理的数据集中依次取出内容进行处理
-
待处理数据集,严格来说为序列类型【for 循环本质上是遍历序列类型】
-
序列类型指:其内容可以一个个依次取出的一种类型,包括字符串、列表、元组等
-
for 循环嵌套
3.2 for 循环的变量作用域
-
若在 for 循环外部访问临时变量:
-
实际:可以访问
-
编程规范:不允许、不建议这样做
-
-
如需访问临时变量,可以预先在循环外定义它
4. continue 和 break
-
continue:中断本次循环,直接进入下一次循环
-
break:直接结束循环
注:在嵌套循环中,只能作用在所在的循环上,无法对上层循环起作用
八、range 语句
- 语法格式
range(num1, num2, step) # 左闭右开
-
说明
-
num1:从哪里开始取,省略默认为 0
-
num2:取到哪里结束(取不到)
-
step:数字之间的步长,省略默认为 1
-
-
如:
-
range(5)
取得的数据是:[0, 1, 2, 3, 4]
-
range(5, 10)
取得的数据是:[5, 6, 7, 8, 9]
-
range(5, 10, 2)
取得的数据是:[5, 7, 9]
-
-
示例:
for x in range(5, 10):
print(x)
九、函数
1. 基本使用
# 必须先定义后使用
def 函数名(传入参数):
函数体
return 返回值
函数名(参数)
- 函数的嵌套调用:在一个函数里调用另一个函数
2. None 类型
若函数没有使用 return 返回数据,则函数返回字面量 None 【即函数仍有返回值】
- 示例:
def say_hi():
print("hi")
result = say_hi()
print(f"无返回值函数,返回的内容是:{result}") # None
print(f"无返回值函数,返回的内容类型是:{type(result)}") # <class 'NoneType'>
- 可以主动返回 None:
return None
-
None 类型的应用场景
-
函数无返回值
-
if 判断
-
None 等同于 False
-
一般用于函数中主动返回 None,配合 if 判断做相关处理
-
-
定义变量时暂不需要值时,可用
None
代替:name = None
-
3. 说明文档
给函数添加说明文档,辅助理解函数的作用
def func(x, y):
"""
函数说明
:param x: 形参x的说明
:param y: 形参y的说明
:return: 返回值的说明
"""
-
通过多行注释对函数进行解释说明
-
内容写在函数体之前
4. 变量的作用域
-
局部变量:作用范围在函数内部
-
全局变量:在函数内部和外部均可使用
-
将局部变量声明为全局变量
- 使用
global
关键字,可以在函数内部声明全局变量
- 使用
-
示例:
num = 100
def testA():
print(num)
def testB():
global num
num = 200
print(num)
testA()
testB()
print(f"全局变量 num = {num}")
5. 多个返回值
若函数有多个返回值,则按照返回值的顺序,写对应顺序的多个变量接收即可,变量之间用逗号隔开,并且支持不同类型的数据return
def test_return():
return 1, "hello", True
x, y, z = test_return()
print(x)
print(y)
print(z)
6. 函数参数种类
6.1 位置参数
def user_info(name, age, gender):
print(f"您的名字是:{name}, 年龄是:{age}, 性别是:{gender}")
user_info('TOM', 20, '男')
注:传递的参数和定义的参数的顺序及个数必须一致
6.2 关键字参数
- 函数调用时通过
key=value
形式传递参数
【可以让函数更加清晰,容易使用,且不用按顺序】
def user_info(name, age, gender):
print(f"您的名字是:{name}, 年龄是:{age}, 性别是:{gender}")
user_info(name = 'TOM', age = 20, gender = '男')
# 可不按照固定顺序
user_info(age = 20, name = 'TOM', gender = '男')
# 可与位置参数混用
user_info("小明", age = 20, gender = "男")
注:位置参数必须在关键字参数前面,但关键字参数之间不存在先后顺序
6.3 缺省参数(默认参数)
用于定义函数,为参数提供默认值,调用函数时可不传该默认参数的值
def user_info(name, age, gender='男'):
print(f"您的名字是:{name}, 年龄是:{age}, 性别是:{gender}")
user_info('TOM', 20)
user_info('Rose', 18, '女')
注:缺省参数要放在最后面
6.4 不定长参数(可变参数)
-
使用场景:不确定调用时的传参个数(不传参也可以)
-
不定长参数的类型:① 位置传递 ② 关键字传递
6.4.1 位置传递
def user_info(*args):
print(args)
user_info('TOM')
user_info('TOM', 18)
注:传进的所有参数都会被args变量收集,它会根据传进参数的位置合并为一个元组
6.4.2 关键字传递
def user_info(**kwargs):
print(kwargs)
user_info(name = 'TOM', age = 18, id = 110)
注:所有的 "键 = 值" 都会被 kwargs 接收,同时根据 "键 = 值" 组成字典
6.4.3 元组和字典的拆包
-
作用:简化元组变量 / 字典变量的传递
-
可直接将一个元组变量传递给
args
-
可直接将一个字典变量传递给
kwargs
-
-
方式
-
在元组变量前加
*
-
在字典变量前加
**
-
-
示例:
def demo(*args, **kwargs):
print(args)
print(kwargs)
# 元组、字典变量
gl_nums = (1, 2, 3)
gl_dict = {"name": "小明", "age": 18}
demo(*gl_nums, **gl_dict) # 等价于demo(1, 2, 3, "name": "小明", age=18)
7. 函数作为参数传递
-
将函数传入的作用:传入计算逻辑,而非传入数据
-
不仅仅是相加、相减、相除等,任何逻辑都可以自行定义并作为函数传入
示例:
def test_func(compute):
result = compute(1, 2)
print(f"compute参数的类型是:{type(compute)}")
print(f"计算结果是:{result}")
def compute(x, y):
return x + y
test_func(compute)
8. lambda 匿名函数
lambda 传入参数: 函数体
-
lambda:关键字,表示定义匿名函数
-
传入参数:匿名函数的形参,如 x, y 表示接收2个形参
-
函数体只能写一行代码
-
匿名函数只能临时使用一次
示例:
def test_func(compute):
result = compute(1, 2)
print(result)
test_func(lambda x, y: x + y)
十、数据容器
含义:一种可以容纳多份数据的数据类型,容纳的每1份数据称为1个元素,每个元素可以是任意类型的数据
分类
根据特点不同进行分类,如是否支持重复元素、是否可以修改、是否有序等
分为5类:列表(list)、元组(tuple)、字符串(str)、集合(set)、字典(dict)
1. 列表(list)
- 基本语法:
变量名 = [元素1, 元素2, 元素3, ...]
# 定义空列表
变量名 = []
变量名 = list()
注:列表一次可存储多个数据,可为不同的数据类型,支持嵌套
1.1 索引(下标)
-
与数组的下标用法一致
-
可以反向索引,即从后往前:从 -1 开始,依次递减(-1、-2、-3...)
-
嵌套列表的下标
- 用两个中括号,先写外层的下标,再写里层的下标
注:下标不能超出范围
1.2 常用操作
1.2.1 方法
- 方法和函数功能一样,只是使用时格式不同
class Student:
def add(self, x, y):
return x + y
- 方法的使用
student = Student()
num = student.add(1, 2)
1.2.2 常用方法
方法 | 作用 |
---|---|
列表.index(元素) |
查询某元素的下标,若找不到,报错 ValueError |
列表[下标] = 值 |
修改指定位置的元素值 |
列表.insert(下标, 元素) |
在指定位置插入指定元素 |
列表.append(元素) 列表.extend(其他数据容器) |
将指定元素追加到列表尾部 将其他数据容器的内容取出,依次追加到列表尾部(追加一批数据) |
方法1:使用"+"号合并 方法2:extend方法 方法3:切片 方法4:append方法 |
合并两个列表 |
语法1:del 列表[下标] 语法2: 列表.pop(下标) |
删除某个元素,pop 方法可以将删除元素作为返回值得到 |
列表.remove(元素) |
删除某元素在列表中的第一个匹配项 |
列表.clear() |
清空列表内容 |
列表.count(元素) |
统计某元素在列表内的数量 |
len(列表) |
统计列表内有多少元素 |
- 示例:
myList = [1, 2, 3]
# 查询
index = myList.index(2)
print(f"元素2在列表中的下标索引值是:{index}") # 结果:1
# index = myList.index(4) # 报错
# print(f"元素4在列表中的下标索引值是:{index}")
# 修改
myList[0] = -1
print(f"列表被修改元素值后,结果是:{myList}") # 结果:[-1, 2, 3]
# 插入
myList.insert(1, 6)
print(f"插入666后的结果:{myList}") # 结果:[-1, 6, 2, 3]
# 追加
# 方式1:append
myList.append(4)
print(f"append追加单个元素:{myList}") # 结果:[-1, 6, 2, 3, 4]
myList.append([4, 5, 6])
print(f"append追加列表:{myList}") # 结果:[-1, 6, 2, 3, 4, [4, 5, 6]]
# 方式2:extend
myList.extend([4, 5, 6])
print(f"extend追加列表:{myList}") # 结果:[-1, 6, 2, 3, 4, [4, 5, 6], 4, 5, 6]
# 删除
# 方式1:del
del myList[5]
print(f"del删除:{myList}") # 结果:[-1, 6, 2, 3, 4, 4, 5, 6]
# 方式2:pop
element = myList.pop(0)
print(f"pop删除:{myList}") # 结果:[6, 2, 3, 4, 4, 5, 6]
# 删除某元素在列表中的第一个匹配项
myList.remove(6)
print(f"remove删除:{myList}") # 结果:[2, 3, 4, 4, 5, 6]
# 统计某元素在列表内的数量
print(f"count:{myList.count(4)}") # 结果:2
# 统计列表内有多少元素
print(f"len:{len(myList)}") # 结果:6
# 清空列表内容
myList.clear()
print(f"清空列表:{myList}") # 结果:[]
1.2.3 遍历
- while 循环
index = 0
while index < len(列表):
元素 = 列表[index]
对元素进行处理
index += 1
- for 循环
for element in my_list:
print(f"列表的元素有:{element}")
-
小结:
-
for 循环更简单,while 更灵活
-
for 用于从容器内依次取出元素并处理,while 用以任何需要循环的场景
-
1.3 特点
-
可容纳多个不同类型的元素
-
有序存储(有下标序号)
-
允许重复数据存在
-
可修改
2. 元组(tuple)
当需要在程序内封装数据,又不希望数据被篡改时使用元组
简单理解:元组是只读的列表
元组与列表唯一的不同:不可修改性
2.1 定义
变量名 = (元素1, 元素2, ...)
# 定义空元组
变量名 = () # 方式1
变量名 = tuple() # 方式2
# 定义只有一个元素的元组,后面必须有逗号,否则就不是元组类型
t = ('hello', )
2.2 相关操作
2.2.1 嵌套
- 元组内也可以嵌套元组,并且也可以通过下标取出元素
2.2.2 相关操作
方法 | 作用 |
---|---|
index() |
查找某个数据,若存在则返回对应下标,否则报错 |
count() |
统计某个数据在当前元组出现的次数 |
len(元组) |
统计元组内的元素个数 |
2.2.3 遍历
-
不能修改元组的内容,否则会报错
-
可修改元组内嵌套的 list 的内容
t1 = (1, 2, ['itheima', 'itcast'])
t1[2][1] = 'best'
print(t1) # 结果:(1, 2, ['itheima', 'best'])
3. 字符串
字符串是一个无法修改的数据容器
3.1 基础认识
3.1.1 三种定义方式
-
单引号
-
双引号
-
三引号:
name = """ 黑马程序员 """
-
可实现多行字符串的输出
-
若不用变量去接收,则作为多行注释使用
-
3.1.2 字符串拼接
方式 | 说明 |
---|---|
通过+ 拼接 |
不能和非字符串类型进行拼接 |
通过, 拼接 |
相邻的两个字符串之间会有空格 |
空格自动拼接 | |
多行字符串之间会有\ 自动拼接 |
拼接后的字符串中间没有空格,不能通过多个变量名来进行多行拼接 |
通过乘法* 进行拼接 |
一个字符串与n 相乘的结果为字符串拼接n 次 |
字符串格式化操作符% 拼接 |
|
通过str.format() 方法拼接 |
|
通过str.join() 方法拼接 |
常用来将列表内的字符串拼接成一个大的字符串,列表中的每个元素都需要是字符串类型,str 是连接符 |
通过string模块中的Template对象拼接 | |
通过F-strings拼接 |
# ,拼接
from string import Template
print('str1:', 'hello', 'world')
# +拼接
str2 = 'hello' + '12'
print(f"str2:{str2}")
# 空格拼接
str3 = 'hello' 'world'
print(f"str3:{str3}")
# 换行自动拼接
print("str4:"
"hello"
"world")
# 乘法*拼接
str5 = 'a-' * 10
print(f"str5:{str5}") # a-a-a-a-a-a-a-a-a-a-
# str.join()
myList = ['你', '好', '世', '界']
str6 = '-'.join(myList)
print(f"str6:{str6}")
# string模块的Template对象
t = Template('${s1} ${s2}!')
str7 = t.safe_substitute(s1='hello', s2='world')
print(f"str7:{str7}")
3.2 字符串格式化
3.2.1 方式1
name = "黑马程序员"
msg1 = "学IT就来%s" % name # %s是占位符
print(msg1)
# 多个变量要用括号括起来,并按照占位的顺序填入
tel = 123456789
msg2 = "我的名字:%s, 电话:%s" % (name, tel) # tel的占位符可用%d
print(msg2)
3.2.2 精度控制
-
使用辅助符号
m.n
来控制数据的宽度和精度-
m
:控制宽度,设置的宽度小于数字本身,不生效 -
.n
:控制小数点精度,会进行小数的四舍五入
-
-
注:小数点和小数部分也算入宽度计算
3.2.3 方式2
f"内容{变量}"
示例:
name = "传智播客"
set_up_year = 2006
stock_price = 19.99
print(f"我是{name},我成立于:{set_up_year},我今天的股票价格是:{stock_price}")
- 这种方式不理会类型,不做精度控制,适合对精度没有要求时快速使用
3.2.4 方式3
内容.format(变量)
- 示例1:
# {}中数字表示使用第几个参数
message_content = """
金{0}贺岁,欢乐祥瑞。
金{0}敲门,五福临门。
给{1}及家人拜年啦!
""".format(year, name)
# 使用变量占位
message_content = """
金{current_year}贺岁,欢乐祥瑞。
金{current_year}敲门,五福临门。
给{receiver_name}及家人拜年啦!
""".format(current_year = year, receiver_name = name)
- 示例2:使用
:
分隔,.2f
:保留两位小数
gpa_dict = {"Tom": 3.251, "Amy": 3.864, "John": 4.105}
for name, gpa in gpa_dict.items():
print("{0}你好,你当前的绩点为:{1:.2f}".format(name, gpa))
for name, gpa in gpa_dict.items():
print(f"{name}你好,你当前的绩点为:{gpa:.2f}")
3.2.5 表达式的格式化
-
表达式:一条具有明确执行结果的代码语句
-
示例:
print("1*1的结果是:%d" % (1*1))
print(f"1*1的结果是:{1*1}")
print("字符串在python中的类型是:%s" % type('字符串'))
注:无需使用变量进行数据存储时,可直接格式化表达式,简化代码
3.3 原始字符串(raw strings)
示例:打印C:\now
,\n
会构成换行符
print('C:\now')
# 输出:
C:
ow
解决1:使用\
进行转义,缺点:\
太多
解决2:在字符串前加r
print(r"C:\now")
注:使用字符串时,不能以反斜杠作为结尾
【反斜杠放在字符串末尾表示字符串还没结束,换行继续的意思】
string = "FishC\"
SyntaxError:EOL while scanning string literal
3.4 常用方法
-
可以通过下标进行访问
-
修改、移除指定下标的字符、追加字符等操作无法完成,若必须要做,只能得到一个新字符串,旧字符串无法修改
方法/操作 | 说明 |
---|---|
字符串.index(字符串) |
查找特定字符串的起始下标 |
字符串.replace(字符串1, 字符串2) |
将字符串内的全部字符串1,替换为字符串2 |
字符串.split(分隔符字符串) |
按照指定的分隔符字符串,将字符串划分为多个字符串,并存入列表对象中 |
字符串.strip() |
去除前后空格 |
字符串.strip(字符串) |
去除前后指定字符串 |
字符串.count(字符串) |
统计字符串内某字符串的出现次数 |
len(字符串) |
统计字符串的字符个数 |
遍历 | 支持 while 循环和 for 循环进行遍历 |
- 示例
str1 = "itcast and itheima"
print(f"str1.index('and'):{str1.index("and")}") # 结果7
# 字符串本身不变,得到新的字符串
str2 = "we are we are"
print(f"str2.replace('we', 'you'):{str2.replace("we", "you")}")
# 字符串本身不变,而是得到了一个列表对象
words = "hello world python test"
word_list = words.split(" ") # 按空格进行分割
print(f"words.splt(' '):{word_list}") # 结果:['hello', 'world', 'python', 'test']
print(f"type(word_list):{type(word_list)}") # 结果:<class 'list'>
# 去除前后空格
str3 = " itheima and itcast "
print(f"str3.strip():{str3.strip()}") # 结果:"itheima and itcast"
# 去除前后指定字符串
str4 = "12itheima and itcast21"
print(f"str4.strip('12'):{str4.strip("12")}") # 结果:"itheima and itcast"
注:传入的是"12",其实是按照单个字符去移除,故 "12"、"21"都会被移除
3.5 特点
-
只能存储字符串
-
长度任意
-
支持下标索引
-
允许重复字符串存在
-
不可修改
4. 序列
内容连续、有序,可使用下标索引的一类数据容器 【列表、元组、字符串】
- 切片:从一个序列中取出一个子序列
序列[起始下标:结束下标:步长] # 左闭右开
表示从序列中,从指定位置开始依次取出元素到指定位置结束,得到一个新序列
-
起始下标:表示从何处开始,留空表示从头开始
-
结束下标(不含):表示何处结束,留空表示截取到结尾
-
步长:依次取元素的间隔,省略默认为1
注:
① 步长为负数,表示反向取(注意起始下标和结束下标也要反向标记)
② 此操作不含影响序列本身,而是得到一个新的序列(列表、元组、字符串)
示例:
# 对list进行切片,从1开始,4结束,步长1
my_list = [0, 1, 2, 3, 4, 5, 6]
result1 = my_list[1:4]
print(f"结果1:{result1}")
# 对tuple进行切片,从头到尾,步长1
my_tuple = (0, 1, 2, 3, 4, 5, 6)
result2 = my_tuple[:]
print(f"结果2:{result2}")
# 对str进行切片,从头到尾,步长2
my_str = "01234567"
result3 = my_str[::2]
print(f"结果3:{result3}")
# 对str进行切片,从头到尾,步长-1
my_str = "01234567"
result4 = my_str[::-1] # 等同于将序列反转了
print(f"结果4:{result4}")
# 对列表进行切片,从3开始,到1结束,步长-1
my_list = [0, 1, 2, 3, 4, 5, 6]
result5 = my_list[3:1:-1]
print(f"结果:{result5}")
# 对元组进行切片,从头到尾,步长-2
my_tuple = (0, 1, 2, 3, 4, 5, 6)
result6 = my_tuple[::-2]
print(f"结果:{result6}")
5. 集合
序列的局限:支持重复元素
集合的特点:自带去重功能、并且内容无序
5.1 定义
变量名 = {元素1, 元素2, ...}
# 定义空集合
变量名 = set()
5.2 常用操作
集合不支持下标索引访问,但允许修改
方法 | 说明 |
---|---|
集合.add(元素) |
集合本身被修改,添加了新元素 |
集合.remove(元素) |
移除元素 |
集合.pop() |
从集合中随机取出元素,返回值为取出的元素 |
集合.clear() |
清空集合 |
集合1.difference(集合2) |
1. 取出集合1有而集合2没有的 2. 得到一个新集合,集合1和集合2不变 |
集合1.difference_update(集合2) |
1. 在集合1内,删除和集合2相同的元素 2. 集合1被修改,集合2不变 |
集合1.union(集合2) |
将集合1和集合2组合成新集合,集合1和集合2不变 |
len(集合) |
统计集合元素数量 |
遍历 | 只能用 for 循环,因为集合不支持下标索引 |
- 示例:
my_set = {"Hello", "World"}
# 添加
my_set.add("itheima")
print(my_set) # 结果:{'Hello', 'itheima', 'World'}
# 移除
my_set.remove("Hello")
print(my_set) # 结果{'World', 'itheima'}
# 移除
element = my_set.pop()
print(my_set) # 结果 {'World'}
print(element) # 结果 'itheima'
# 清空
my_set.clear()
print(my_set) # 结果:set(),空集合
# 取出两个集合的差集
set1 = {1, 2, 3}
set2 = {1, 5, 6}
set3 = set1.difference(set2)
print(set3) # 结果:{2, 3} 得到的新集合
print(set1) # 结果:{1, 2, 3} 不变
print(set2) # 结果:{1, 5, 6} 不变
# 消除两个集合的差集
set1.difference_update(set2)
print(set1) # 结果:{2, 3}
print(set2) # 结果:{1, 5, 6} 不变
# 合并两个集合
set3 = set1.union(set2)
print(set3) # 结果:{1, 2, 3, 5, 6} 新集合
print(set1) # 结果:{2, 3} 不变
print(set2) # 结果:{1, 5, 6} 不变
# 遍历
for element in set3:
print(element)
5.3 特点
-
可容纳多个不同类型的数据
-
无序存储(不支持下标索引)
-
不允许重复数据存在
-
可修改
6. 字典
使用{}
,存储的元素是一个一个键值对
# 定义字典变量
my_dict = {key: value, key: value, ...}
# 定义空字典
my_dict = {} # 空字典定义方式1
my_dict = dict() # 方式2
6.1 获取字典数据
-
字典不能使用下标索引,但可以通过 Key 值取得对应的 Value
-
方式1:
dict[key]
# 定义重复Key的字典
stu_score = {"张三": 99, "张三": 88, "李四": 77}
print(stu_score["张三"]) # 结果:88
print(f"重复Key的字典的内容为:{stu_score}") # 结果:{'张三': 88, '李四': 77}
-
方式2:
dict.get(key[, value])
-
key -- 字典中要查找的键
-
value -- 可选,如果指定键的值不存在时,返回该默认值
-
tinydict = {'Name': 'Runoob', 'Age': 27}
print ("Age : %s" % tinydict.get('Age'))
# 没有设置 Sex,也没有设置默认的值,输出 None
print ("Sex : %s" % tinydict.get('Sex'))
# 没有设置 Salary,输出默认的值 0.0
print ('Salary: %s' % tinydict.get('Salary', 0.0))
# 输出
Age : 27
Sex : None
Salary: 0.0
# 嵌套字典
tinydict = {'RUNOOB' : {'url' : 'www.runoob.com'}}
res = tinydict.get('RUNOOB', {}).get('url')
print(f"RUNOOB url 为:{str(res)}")
-
两种方法的区别
-
get(key)
:key 不在字典中时,返回默认值 None 或者设置的默认值 -
dict[key]
:key 不在字典中时,触发 KeyError 异常
-
6.2 嵌套
字典的 Key 和 Value 可以是任意数据类型(Key不可为字典)
stu_score_dict = {
"张三": {
"语文": 77,
"数学": 66,
"英语": 33
}, "李四": {
"语文": 88,
"数学": 86,
"英语": 55
}, "王五": {
"语文": 99,
"数学": 96,
"英语": 66
}
}
score = stu_score_dict["张三"]["语文"]
print(f"张三的语文分数是:{score}")
6.3 常用操作
6.3.1 常用方法
方法 | 说明 |
---|---|
字典[Key] = Value |
新增 / 更新元素,Key 不存在即新增,反之则更新(Key不可重复) |
字典.pop(Key) |
删除指定 Key 的 Value 并返回,同时字典被修改 |
字典.clear() |
清空字典 |
字典.keys() |
获取所有键 |
字典.values() |
获取所有值 |
字典.items() |
获取所有键值对,返回元组数据 |
len() |
统计字典内的元素个数 |
键 in 字典 |
判断键是否已存在 |
- 示例:
stu_score = {
"张三": 77,
"李四": 88,
"王五": 99
}
# 获取所有键
keys = stu_score.keys()
print(keys) # 结果:dict_keys(['张三', '李四', '王五'])
# 统计字典内的元素个数
num = len(stu_score)
print(f"字典中的元素个数有:{num}个")
# 新增
stu_score["张学友"] = 66
print(stu_score) # 结果:{'张三': 77, '李四': 88, '王五': 99, '张学友': 66}
# 更新
stu_score["张三"] = 66
print(stu_score) # 结果:{'张三': 66, '李四': 88, '王五': 99}
# 删除,方式1
value = stu_score.pop("张三")
print(value)
print(stu_score) # 结果:{"李四": 88, "王五": 99}
# 方式2
del stu_score["张学友"]
print(stu_score)
print("张学友" in stu_score)
# 清空
stu_score.clear()
print(stu_score) # 结果:{}
6.3.2 遍历
- 方式1:
for key in keys:
print(f"字典的key是:{key}")
print(f"字典的value是:{my_dict[key]}")
- 方式2:
for key in my_dict:
print(f"字典的key是:{key}")
print(f"字典的value是:{my_dict[key]}")
6.4 特点
-
可容纳多个不同类型的数据
-
每一份数据是键值对
-
可通过 Key 获取到 Value,Key 不可重复(重复会覆盖)
-
不支持下标索引
-
可修改
7. 数据容器特点对比
列表 | 元组 | 字符串 | 集合 | 字典 | |
---|---|---|---|---|---|
元素数量 | 多个 | 多个 | 多个 | 多个 | 多个 |
元素类型 | 任意 | 任意 | 仅字符 | 任意 | Key:除字典外任意类型 Value:任意类型 |
下标索引 | √ | √ | √ | × | × |
重复元素 | √ | √ | √ | × | × |
可修改性 | √ | × | × | √ | √ |
数据有序 | 是 | 是 | 是 | 否 | 否 |
使用场景 | 一批数据,可修改、可重复 | 一批数据,不可修改、可重复 | 一串字符串 | 一批数据,去重 | 一批数据,可用Key检索Value的存储场景 |
8. 数据容器的通用功能
功能 | 描述 |
---|---|
for 循环 | 遍历容器(字典是遍历key) |
max() |
容器内最大元素 |
min() |
容器内最小元素 |
len() |
容器元素个数 |
list() |
转换为列表 |
tuple() |
转换为元组 |
str() |
转换为字符串 |
set() |
转换为集合 |
sorted(序列, [reverse = True]) |
排序,reverse=True 表示降序,得到一个排好序的列表 |
-
字典除了转换为字符串保持原样,转换为其他数据容器时,value值都会被舍弃
-
字符串转换为其他数据容器时,以单个字符为一个元素
-
sorted 排序之后都会变成列表
-
字符串比较大小是比较 ASCII 码值,并且是按位比较,一位一位进行对比
示例:
my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
my_str = "abcdefg"
my_set = {1, 2, 3, 4, 5}
my_dict = {"key1": 1, "key2": 2, "key3": 3, "key4": 4, "key5": 5}
# max最大元素(min最小元素同理)
print(f"列表最大的元素是:{max(my_list)}")
print(f"元组最大的元素是:{max(my_tuple)}")
print(f"字符串最大的元素是:{max(my_str)}") # 比较的是ASCII码值
print(f"集合最大的元素是:{max(my_set)}")
print(f"字典最大的元素是:{max(my_dict)}") # 比较的是Key值
# 排序
print(f"列表对象的排序结果:{sorted(my_list)}")
print(f"元组对象的排序结果:{sorted(my_tuple)}")
print(f"字符串对象的排序结果:{sorted(my_str)}")
print(f"集合对象的排序结果:{sorted(my_set)}")
print(f"字典对象的排序结果:{sorted(my_dict)}")
# 结果:
列表对象的排序结果:[1, 2, 3, 4, 5]
元组对象的排序结果:[1, 2, 3, 4, 5]
字符串对象的排序结果:['a', 'b', 'c', 'd', 'e', 'f', 'g']
集合对象的排序结果:[1, 2, 3, 4, 5]
字典对象的排序结果:['key1', 'key2', 'key3', 'key4', 'key5']
十一、文件
1. 文件编码
-
编码是一种规则集合,记录了内容和二进制间进行相互转换的逻辑
-
有许多编码:UTF-8、GBK、Big5 等,UTF-8 是目前通用的编码格式
-
为什么使用编码:
- 计算机只认识 0 和 1,需要将内容翻译成 0 和 1 才能保存在计算机中,同时也需要编码将计算机保存的 0 和 1,反向翻译回可以识别的内容
2. 文件操作
操作 | 功能 | 说明 |
---|---|---|
f = open(name, mode, encoding) |
打开文件获得文件对象 | name:要打开的文件名(可含文件所在的具体路径) mode:打开文件的模式:只读、写入、追加等 encoding:编码格式,其顺序不是第三位,不能用位置参数,需使用关键字参数 |
f.read(num) |
读取指定长度字节 | num:要从文件中读取的数据的长度(单位:byte),留空表示读取文件所有数据 |
f.readline() |
一次读取一行内容 | |
f.readlines() |
读取全部行,得到列表 | 一次性读取整个文件中的内容,返回的是列表,每行数据为一个元素 |
for line in f |
for 循环文件行,一次循环得到一行数据 | |
f.close() |
关闭文件对象 | 若没有调用close() 且程序也没有停止运行,则这个文件将一直被 Python 程序占用 |
with open() as f |
通过 with open 语法打开文件,可以自动关闭文件 | |
f.write(内容) |
写入文件(w 写入,a 追加,r+ 可读可写) |
-
注:
-
每调用一次 read() 方法,都会从上一次 read() 结果的下一个位置开始读取
-
直接调用 write,内容并未真正写入文件,而是积攒在程序的内存中(即缓冲区)
-
当调用 flush 时,内容会真正写入文件
-
这样做是避免频繁的操作硬盘,导致效率下降(攒一堆,一次性写入磁盘)
-
close 方法内置了 flush 功能
-
文件不存在,会创建新文件,若存在,则清空原有内容
-
3. mode 常用的三种基础访问模式
模式 | 描述 |
---|---|
r | 以只读方式打开文件。文件指针将会放在文件的开头(默认模式) |
w | 以写入方式打开文件。文件不存在,会创建新文件,若存在,则清空原有内容,再写入 |
a | 以追加方式打开文件。文件不存在,会创建新文件,若存在,则在原有内容之后写入 |
- 示例1:读
# 结果:['hello world\n', 'abcdefg\n', 'aaa\n', 'bbb\n', 'ccc']
with open("python.txt", "r") as f:
content = f.readlines()
print(content)
f = open('python.txt', 'r', encoding="UTF-8")
content = f.readline()
print(f"第一行:{content}")
content = f.readline()
print(f"第二行:{content}")
# 关闭文件
f.close()
- 示例2:for 循环读取文件行
# 每一个line临时变量,就记录了文件的一行数据
for line in open("python.txt", "r"):
print(line)
for line in f:
print(f"每一行的数据是:{line}")
- 示例3:写
# 1、打开文件
f = open("D:/test.txt", "w", encoding="UTF-8")
# 2、文件写入
f.write("Hello World!!!")
# 3、内容刷新
# f.flush()
f.close()
十二、异常
程序运行的过程中出现了错误(bug)
1. 捕获异常(异常处理)
-
在力所能及的范围内,对可能出现的 bug 进行提前准备、提前处理
-
在可能发生异常的地方进行捕获,当异常出现时提供解决方式,而不是任由其导致程序无法运行
1.1 基本语法
try:
可能发生异常的语句
except[异常 as 别名:]
出现异常的准备手段
[else:]
未出现异常时应做的事情
[finally:]
不管出不出现异常都会做的事情(例如关闭文件)
- 示例1:
try:
f = open('test.txt', 'r', encoding="UTF-8")
except Exception as e:
f = open('test.txt', 'w', encoding="UTF-8")
else:
print('没有异常')
finally:
f.close()
- 示例2:
try:
weight = float(input("请输入您的体重(单位:kg):"))
height = float(input("请输入您的身高(单位:m):"))
BMI = weight / height ** 2
except ValueError:
print("输入为不合理数字,请重新运行程序,并输入正确的数字")
except ZeroDivisionError:
print("身高不能为0,请重新运行程序,并输入正确的数字")
except:
print("发生了未知错误,请重新运行程序。")
else:
print("您的BMI值为:" + str(BMI))
finally:
print("程序运行结束")
1.2 捕获指定异常
try:
print(name)
except NameError as e:
print('name变量名称未定义错误')
-
注:
-
如果尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常
-
一般 try 下方只放一行尝试执行的代码
-
1.3 捕获多个异常
当捕获多个异常时,可以把要捕获的异常类型的名字放到 except 后,并使用元组的方式进行书写
try:
print(1/0)
except(NameError, ZeroDivisionError) as e:
print('ZeroDivision错误...')
1.4 捕获所有异常
try:
f = open("D:/123.txt", "r")
except Exception as e:
print("出现异常了")
2. 异常具有传递性
当函数 func01 中发生异常,并且没有捕获处理这个异常时,异常会传递到 func02,当 func02 也没有捕获处理这个异常时,main 函数会捕获这个异常,这就是异常的传递性
注:当所有函数都没有捕获异常时,程序就会报错
十三、模块(Module)
1. 初步认识
-
是一个
.py
文件。模块能定义函数、类和变量,模块里也能包含可执行的代码 -
作用:快速实现一些功能,可以认为一个模块就是一个工具包,其中有各种不同的工具用来实现各种不同的功能
2. 模块导入
[from 模块名] import [模块 | 类 | 变量 | 函数 | *] [as 别名]
2.1 方式1
import 模块名1, 模块名2, ...
模块名.功能名()
示例:
# 导入time模块
import time
print("开始")
# 让程序睡眠1s(阻塞)
time.sleep(1)
print("结束")
2.2 方式2
from 模块名 import 类、变量、方法等
from time import sleep
print("你好")
sleep(5)
print("我好")
2.3 方式3
from 模块名 import *
# 使用 * 导入time模块的全部功能
from time import *
print("你好")
sleep(5)
print("我好")
2.4 方式4
-
import 模块名 as 别名
-
from 模块名 import 功能名 as 别名
# 模块别名
import time as t
t.sleep(2)
print("hello")
# 功能别名
from time import sleep as sl
sl(2)
print("hello")
3. 自定义模块
新建一个 python 文件,命名为my_module1.py
,并定义test
函数
# my_module1.py
def test(a, b):
print(a + b)
# test.py
import my_module1
my_module1.test(10, 20)
注:
-
每个 python 文件都可以作为一个模块,模块名就是文件名,即自定义模块名必须符合标识符命名规则
-
当导入多个模块时,且模块内有同名功能,当调用该功能时,调用到的是后面导入的模块的功能
# 模块1代码
def my_test(a, b):
print(a + b)
# 模块2代码
def my_test(a, b):
print(a - b)
# 导入模块和调用功能代码
from my_module1 import my_test
from my_module2 import my_test
# my_test函数是模块2中的函数
my_test(1, 1)
4. 测试模块
在编写完一个模块后,通常会在 py 文件中添加一些测试信息,此时,无论是当前文件,还是其他已经导入了该模块的文件,在运行时都会自动执行 test 函数的调用
解决:
def test(a, b):
print(a + b)
# 只在当前文件中调用该函数,其他导入的文件内不符合该条件,则不执行test函数调用
if __name__ == '__main__':
test(1, 1)
5. __all__
如果一个模块文件中有__all__
变量,当使用from xxx import *
导入时,只能导入这个列表中的元素
# my_module1.py
__all__ = ['test_A']
def test_A():
print('testA')
def test_B():
print('testB')
# test.py
from my_module1 import *
test_A() # 只能使用test_A函数
十四、python 包
-
包就是文件夹,里面可以存放许多 python 的模块,通过包,逻辑上将一批模块归为一类,方便管理
-
创建包时会自动创建
__init__.py
文件,通过该文件表示这个文件夹是 Python 的包
1. 使用步骤
-
新建包:
my_package
-
新建包内模块:
my_module1
和my_module2
-
模块内代码如下:
# my_module1 print(1) def info_print1(): print('my_module1') # my_module2 print(2) def info_print(): print('my_module2')
注:新建包后,包内会自动创建
__init_.py
文件,这个文件控制着包的导入行为
2. 导入包
2.1 方式1
import 包名.模块名
包名.模块名.目标
示例:
import my_package.my_module1
import my_package.my_module2
my_package.my_module1.info.print1()
my_package.my_module2.info_print2()
from my_package import my_module1
from my_package import my_module2
my_module1.info_print1()
my_module2.info_print2()
from my_package.my_module1 import info_print1
from my_package.my_module2 import info_print2
info_print1()
info_print2()
2.2 方式2
from 包名 import *
模块名.目标
-
必须在
__init__.py
文件中写__all__ = ['']
,控制允许导入的模块列表__all__
针对的是from ... import *
这种方式,对import xxx
这种方式无效
3. 第三方包
-
非python官方内置的包,可以提高开发效率,如:
-
科学计算:numpy
-
数据分析:pandas
-
大数据计算:pyspark、apache-flink
-
图形可视化:matplotlib、pyecharts
-
人工智能:tensorflow
-
-
安装
-
方式1:命令行输入
pip install 包名
-
方式2:使用 PyCharm 进行安装
-
十五、面向对象
1. 类
1.1 定义
class 类名称:
类的属性(成员变量)
类的行为(成员方法)
创建对象:
对象 = 类名称()
1.2 定义成员方法
与定义函数基本一致
def 方法名(self, 形参1, 形参2, ..., 形参N):
方法体
self
关键字是成员方法定义时必须写的
-
它用来表示类对象自身
-
当我们使用类对象调用方法时,
self
会自动被 python 传入 -
在方法内部,想要访问类的成员变量,必须使用
self
注:self
关键字尽管在参数列表中,但传参时可以忽略它(不占用参数位置)
示例1:
class Student:
name = None
def say_hi(self):
print(f"大家好呀,我是{self.name},请大家多多关照")
def say_hi2(self, msg):
print(f"Hello 大家好,{msg}")
stu = Student()
stu.name = "周杰伦"
stu.say_hi()
stu.say_hi2("很高兴认识大家")
stu2 = Student()
stu2.name = "林俊杰"
stu2.say_hi()
示例2:设计一个闹钟类
class Clock:
id = None # 序列号
price = Node # 价格
def ring(self):
import winsound
winsound.Beep(2000, 3000)
# 构建两个闹钟对象并让其工作
clock1 = Clock()
clock1.id = "003032"
clock1.price = 19.99
print(f"闹钟ID:{clock1.id},价格:{clock1.price}")
clock1.ring()
1.3 构造方法
构造方法:
__init__()
特点:
- 在创建类对象时会自动执行
- 在创建类对象时将传入参数自动传递给
__init__
方法使用
示例1:
class Student:
# 成员变量定义可以省略
def __init__(self, name, age, tel):
self.name = name
self.age = age
self.tel = tel
print("Student类创建了一个类对象")
stu = Student("周杰伦", 31, "18500006666")
# 虽然成员变量没有定义,但可以正常使用
print(stu.name)
print(stu.age)
print(stu.tel)
1.4 魔术方法
被
__
包围的方法,在对象继承时,子类可以重写父类的魔术方法以实现定制功能,用于增强Python面向对象编程的能力魔术方法在创建对象或对象操作时自动调用,不需要显式使用
__init__
构造方法也是魔术方法之一
1.4.1 __str__
字符串方法
-
控制类对象转换为字符串
-
方法名:
__str__
-
返回值:字符串
-
内容:自定义
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
student = Student("周杰伦", 11)
print(student) # 内存地址
print(str(student)) # 内存地址
↓ ↓ ↓
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"Student类对象,name={self.name}, age={self.age}"
student = Student("周杰伦", 11)
print(student) # 结果:Student类对象,name=周杰伦,age=11
print(str(student)) # 结果:Student类对象,name=周杰伦,age=11
1.4.2 富比较方法
富比较方法 | 使用 | 释义 | 全称 |
---|---|---|---|
object.__lt__(self, other) |
x.__lt__(y) |
x<y | less than |
object.__le__(self, other) |
x.__le__(y) |
x<=y | less and equal |
object.__eq__(self, other) |
x.__eq__(y) |
x==y | equal |
object.__ne__(self, other) |
x.__ne__(y) |
x!=y | not equal |
object.__gt__(self, other) |
x.__gt__(y) |
x>y | greater than |
object.__ge__(self, other) |
x.__ge__(y) |
x>=y | greater and equal |
-
__lt__
小于大于-
方法名:
__lt__
-
传入参数:other,另一个类对象
-
返回值:True 或 False
-
内容:自定义
-
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __lt__(self, other):
return self.age < other.age
stu1 = Student("周杰伦", 11)
stu2 = Student("林俊杰", 13)
print(stu1 < stu2) # True
print(stu1 > stu2) # False
print(stu1.__lt__(stu2)) # True
__le__
可用于 <=、>=
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __le__(self, other):
return self.age <= other.age
stu1 = Student("周杰伦", 11)
stu2 = Student("林俊杰", 14)
print(stu1 <= stu2) # 结果:True
print(stu1 >= stu2) # 结果:False
__eq__
比较运算
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
return self.age == other.age
stu1 = Student("周杰伦", 11)
stu2 = Student("林俊杰", 11)
print(stu1 == stu2) # 结果:True
-
不实现
__eq__
方法:对象之间比较内存,且结果一定是 False,因为不同对象对应不同地址 -
实现了
__eq__
方法:可按照自己的想法决定两个对象是否相等
2. 封装
概念:将现实世界事物在类中描述为属性和方法
2.1 私有成员
-
私有成员变量:变量名以
__
开头,无法赋值,也无法获取值 -
私有成员方法:方法名以
__
开头,无法直接被类对象使用
【在类中提供仅供内部使用的属性和方法,而不对外开放】
class Phone:
IMEI = None # 序列号
producer = None # 厂商
__current_voltage = None # 当前电压(私有成员变量)
def call_by_5g(self):
print("5g通话已开启")
# 私有成员方法
def __keep_single_core(self):
print("让CPU以单核模式运行以节省电量")
phone = Phone()
phone.__keep_single_core() # 报错
phone.__current_voltage = 33 # 不报错,但无效
print(phone.current_voltage) # 报错
- 私有成员无法被类对象使用,但是可以被其他成员使用
class Phone:
__current_voltage = 0.5
def __keep_single_core(self):
print("让CPU以单核模式运行")
def call_by_5g(self):
if self.__current_voltage >= 1:
print("5g通话已开启")
else:
self.__keep_single_core()
print("电量不足,无法使用5g通话,并且已设置为单核运行进行省电")
phone = Phone()
phone.call_by_5g()
3. 继承
继承:继承父类的成员变量和成员方法(不含私有)
3.1 单继承
class 类名(父类名):
类内容体
示例:
class Phone:
IMEI = None # 序列号
producer = None # 厂商
def call_by_4g(self):
print("4g通话")
class Phone2022(Phone):
face_id = True # 面部识别
def call_by_5g(self):
print("2022最新5g通话")
phone = Phone2022()
print(phone.producer)
phone.call_by_4g()
phone.call_by_5g()
3.2 多继承
class 类名(父类1, 父类2, ..., 父类N):
类内容体
示例:
class Phone:
IMEI = None # 序列号
producer = None # 厂商
def call_by_5g(self):
print("5g通话")
class NFCReader:
nfc_type = "第五代"
producer = "HM"
def read_card(self):
print("读取NFC卡")
def write_card(self):
print("写入NFC卡")
class RemoteControl:
rc_type = "红外遥控"
def control(self):
print("红外遥控开启")
class MyPhone(Phone, NFCReader, RemoteControl):
pass
说明:
- 多个父类中,如果有同名的成员,则默认以继承顺序(从左到右)为优先级
【即先继承的保留,后继承的被覆盖】
-
子类构建的类对象可以有自己的成员变量和成员方法,也可以使用父类的成员变量和成员方法
-
pass 是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容
3.3 复写
对父类的成员属性或成员方法进行重新定义【在子类中定义同名的属性或方法】
class Phone:
IMEI = None # 序列号
producer = "ITCAST" # 厂商
def call_by_5g(self):
print("父类的5g通话")
class MyPhone(Phone):
producer = "ITHEIMA" # 复写父类属性
def call_by_5g(self): # 复写父类方法
print("子类的5g通话")
3.4 调用父类同名成员
3.4.1 方式1
父类名.成员变量
父类名.成员方法(self)
3.4.2 方式2
super().成员变量
super().成员方法()
示例:
class Phone:
IMEI = None # 序列号
producer = "ITCAST" # 厂商
def call_by_5g(self):
print("父类的5g通话")
class MyPhone(Phone):
producer = "ITHEIMA"
def call_by_5g(self):
# 方式1
print(f"父类的品牌是:{Phone.producer}")
Phone.call_by_5g(self)
# 方式2
print(f"父类的品牌是:{super().producer}")
super().call_by_5g()
print("子类的5g通话")
phone = MyPhone()
phone.call_by_5g()
print(phone.producer)
注:只可以在子类内部调用父类的同名成员,子类的实体类对象调用默认是调用子类复写的
4. 类型注解
定义:简单理解就是给变量、函数等做一个备注
主要功能:
帮助Pycharm等开发工具对代码进行类型判断,协助代码提示
帮助开发者自身做类型的备注
一般无法直接看出变量类型时会添加变量的类型注解
4.1 变量的类型注解
变量: 类型
4.1.1 基础数据类型注解
var_1: int = 10
var_2: float = 3.1415926
var_3: bool = True
var_4: str = "itheima"
4.1.2 类对象类型注解
class Student:
pass
stu: Student = Student()
4.1.3 基础容器类型注解
my_list: list = [1, 2, 3]
my_tuple: tuple = (1, 2, 3)
my_set: set = {1, 2, 3}
my_dict: dict = {"itheima": 666}
my_str: str = "itheima"
4.1.4 容器类型详细注解
my_list: list[int] = [1, 2, 3]
my_tuple: tuple[str, int, bool] = ("hello", 2, True)
my_set: set[int] = {1, 2, 3}
my_dict: dict[str, int] = {"itheima": 666}
设置类型注解时注意:
-
元组:需要将每一个元素都标记出来
-
字典:需要两个类型,第一个是 key,第二个是 value
4.1.5 在注释中进行类型注解
# type: 类型
示例:
class Student:
pass
var_1 = random.randint(1, 10) # type: int
var_2 = json.loads('{"name": "zhangsan"}') # type: dict[str, str]
def func():
return 10
var_3 = func() # type: Student
4.2 限制
- 不会真正对类型做验证和判断(即类型注解仅是提示性的,不是决定性的)
var_1: int = "itheima"
var_2: str = 123
# 以上代码不会报错
4.3 函数(方法)的类型注解
4.3.1 引入
如上图所示:
-
使用形参 data 时,工具没有任何提示
-
传入参数时,工具无法提示参数类型
这是因为定义函数(方法)时,没有给形参进行注释
4.3.2 形参的类型注解
def 函数方法名(形参名: 类型, 形参名: 类型, ...):
pass
示例:
def add(x: int, y: int):
return x + y
def func(data: list):
pass
4.3.3 返回值的类型注解
def 函数名(形参: 类型, ..., 形参: 类型) -> 返回值类型:
pass
示例:
def add(x: int, y: int) -> int:
return x + y
def func(data: list[int]) -> list[int]:
pass
4.4 Union 类型
4.4.1 引入
- 这种情况好写
my_list: list[int] = [1, 2, 3]
my_dict: dict[str, int] = {"age": 11, "num": 3}
- 下面这种情况怎么写类型注解呢?
my_list = [1, 2, "itheima", "itcast"]
my_dict = {"name": "周杰伦", "age": 31}
4.4.2 语法
- Union 联合类型注解,在变量注解、函数(方法)形参和返回值注解中均可使用
from typing import Union # 必写
my_list: list[Union[str, int]] = [1, 2, "itheima", "itcast"]
my_dict: dict[str, Union[str, int]] = {"name": "周杰伦", "age": 31}
def func(data: Union[int, str]) -> Union[int, str]:
pass
5. 多态
同一个行为,使用不同的对象获得不同的状态
5.1 说明
-
多态常作用在继承关系上
- 函数(方法)形参声明接收父类对象,实际传入子类对象进行工作
5.2 抽象类(接口)
抽象类:含有抽象方法的类
抽象方法:没有具体实现的方法(pass)
抽象类是对子类的一种软性约束,要求子类必须实现父类的一些方法
配合多态使用,获得不同的工作状态
多用于做顶层设计(设计标准),以便子类具体实现
-
父类用来确定有哪些方法(类似于标准)
-
具体的方法实现,由子类自行决定
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
print("汪汪汪")
class Cat(Animal):
def speak(self):
print("喵喵喵")
def make_nosie(animal: Animal):
animal.speak()
dog = Dog()
cat = Cat()
make_noise(dog) # 输出:汪汪汪
make_noise(cat) # 输出:喵喵喵
十六、Python 操作数据库
1. 安装与连接
- 在 Python 中使用
pymysql
来操作 MySQL
pip install pymysql
- 连接
# 导包
from pymysql import Connection
# 获取到MySQL数据库的链接对象
conn = Connection(
host='localhost', # 主机名(或IP地址)
port=3306, # 端口,默认3306
user='root', # 账户名
password='root' # 密码
)
# 打印MySQL数据库软件信息
print(conn.get_server_inifo())
# 关闭到数据库的链接
conn.close()
2. 执行SQL语句
-
执行非查询性质的 SQL 语句(创建表等...)
-
执行查询性质的 SQL 语句
fetchall()
得到全部的查询结果封装入元组内
from pymysql import Connection
# 获取到MySQL数据库的链接对象
conn = Connection(
host='localhost', # 主机名(或IP地址)
port=3306, # 端口,默认3306
user='root', # 账户名
password='root' # 密码
)
# 获取游标对象
cursor = conn.cursor()
conn.select_db("test") # 先选择数据库
# 使用游标对象执行sql语句
# 创建表
cursor.execute("CREATE TABLE test_pymysql(id INT, info VARCHAR(255))")
# 查询
cursor.execute("SELECT * FROM student")
# 获取查询结果
results: tuple = cursor.fetchall()
for r in results:
print(r)
# 关闭到数据库的链接
conn.close()
3. 提交
pymysql 库修改数据库时,需要通过链接对象的 commit 成员方法来进行确认,只有确认后,修改才生效
3.1 手动提交
conn.commit()
示例:
# 导包
from pymysql import Connection
# 获取到MySQL数据库的链接对象
conn = Connection(
host='localhost', # 主机名(或IP地址)
port=3306, # 端口,默认3306
user='root', # 账户名
password='root' # 密码
)
# 获取游标对象
cursor = conn.cursor()
# 选择数据库
conn.select_db("world")
# 执行sql
cursor.execute("insert into student values(1001, '周杰伦', 31, '男')")
# 手动提交
conn.commit()
# 关闭到数据库的链接
conn.close()
3.2 自动提交
- 在获取到MySQL数据库的链接对象时设置
autocommit=True
示例:
conn = Connection(
host='localhost', # 主机名(或IP地址)
port=3306, # 端口,默认3306
user='root', # 账户名
password='root' # 密码
autocommit=True # 设置自动提交
)
十七、闭包
1. 案例引入
account_amount = 0 # 账户余额
def atm(num, deposit=True):
global account_amount
if deposit:
account_amount += num
print(f"存款: +{num}, 账户余额: {account_amount}")
else:
account_amount -= num
print(f"取款: -{num}, 账户余额: {account_amount}")
atm(300)
atm(100, False)
-
尽管功能实现是可以的,但是仍有问题
-
代码在命名空间上(变量定义)不够干净、整洁
-
全局变量有被修改的风险
-
2. 语法定义
定义双层嵌套函数,内部函数可以访问外部函数的变量,且外部函数返回了内部函数
将这个使用外部函数变量的内部函数称为闭包
- 优化后的代码如下
def account_create(initial_amount=0):
def atm(num, deposit=True):
nonlocal initial_amount
if deposit:
initial_amount += num
print(f"存款: +{num}, 账户余额: {initial_amount}")
else:
initial_amount += num
print(f"取款: -{num}, 账户余额: {initial_amount}")
return atm
fn = account_create()
fn(300)
fn(100, False)
3. 简单闭包
def outer(logo):
def inner(msg):
print(f"<{logo}>{msg}<{logo}>")
return inner
fn1 = outer("黑马程序员")
fn1("大家好呀") # <黑马程序员>大家好呀<黑马程序员>
fn1("学Python就来") # <黑马程序员>学Python就来<黑马程序员>
fn2 = outer("传智教育")
fn2("IT职业教育培训") # <传智教育>IT职业教育培训<传智教育>
fn2("学Python就来") # <传智教育>学Python就来<传智教育>
4. 修改外部函数变量的值
-
使用
nonlocal
关键字修饰外部函数的变量 -
nonlocal
关键字修饰变量后标识该变量是上一级函数中的局部变量,如果上一级函数中不存在该局部变量,nonlocal
位置会发生错误(最上层的函数使用nonlocal
修饰变量必定会报错)
def outer(num1):
def inner(num2):
nonlocal num1
num1 += num2
print(num1)
return inner
fn = outer(10)
fn(10)
fn(10)
5. 优缺点
-
优点
-
不定义全局变量也可以让函数持续访问和修改外部变量
-
闭包函数引用的外部变量是外层函数的内部变量,作用域封闭难以被误操作修改
-
-
缺点
- 内部函数持续引用外部函数的值,导致这部分内存空间不被释放,一直占用内存
6. 装饰器
创建一个闭包函数,在闭包函数内调用目标函数【装饰器就是一种闭包】
在不改动目标函数的前提下,为目标函数增加新功能
- 引入
def sleep():
import random
import time
print("睡眠中......")
time.sleep(random.randint(1, 5))
-
希望给 sleep 函数增加一个功能
-
调用 sleep 前输出:我要睡觉了
-
调用 sleep 后输出:我起床了
-
-
下列写法也可以实现,但不推荐
print("我要睡觉了")
sleep()
print("我起床了")
- 优化(一般写法)
def outer(func):
def inner():
print("我要睡觉了")
func()
print("我起床了")
return inner
def sleep():
import random
import time
print("睡眠中......")
time.sleep(random.randint(1, 5))
fn = outer(sleep)
fn()
-
装饰器的语法糖写法
- 使用
@outer
,定义在目标函数之上
- 使用
def outer(func):
def inner():
print("我要睡觉了")
func()
print("我起床了")
return inner
@outer
def sleep():
import random
import time
print("睡眠中......")
time.sleep(random.randint(1, 5))
sleep()
十八、设计模式
设计模式是一种编程套路,可方便程序开发
最常见的设计模式是面向对象
此外还有许多设计模式
单例模式、工厂模式
建造者、责任链、状态、备忘录、解释器、访问者、观察者、中介、模板、代理模式等等
1. 单例模式
-
确保某一个类只有一个实例存在,并提供一个访问它的全局访问点
- 节省内存以及创建对象的开销
-
实现
# StrTools.py
class StrTools:
pass
str_tool = StrTools()
# test.py
from StrTools import str_tool
s1 = str_tool
s2 = str_tool
print(s1)
print(s2) # 两个变量的地址一样,是同一个对象
2. 工厂模式
当需要大量创建一个类的实例时,可以使用工厂模式
基于工厂提供的方法来创建对象
- 原始代码
class Person:
pass
class Worker(Person):
pass
class Student(Person):
pass
class Teacher(Person):
pass
worker = Worker()
stu = Student()
teacher = Teacher()
-
优化后的代码
- 使用工厂类的
get_person()
方法去创建具体的类对象
- 使用工厂类的
class Person:
pass
class Worker(Person):
pass
class Student(Person):
pass
class Teacher(Person):
pass
class Factory:
def get_person(self, p_type):
if p_type == 'w':
return Worker()
elif p_type == 's':
return Student()
else:
return Teacher()
factory = Factory()
worker = factory.get_person('w')
stu = factory.get_person('s')
teacher = factory.get_person('t')
-
优点
-
大批量创建对象时有统一的入口,易于代码维护
-
当发生修改,仅修改工厂类的创建方法即可
-
符合现实世界的模式,即由工厂来制作产品(对象)
-
十九、多线程
1. 进程、线程
-
进程:程序在操作系统内运行,即成为一个运行进程,并分配进程ID方便系统管理
-
线程:进程内部可以有多个线程,程序的运行本质上是由进程内部的线程在实际工作
-
类比:进程好比一家公司,而线程为公司的员工
-
进程之间内存隔离,即不同的进程拥有各自的内存空间
-
线程之间内存共享,线程属于进程,一个进程内的多个线程之间共享这个进程所拥有的内存空间
2. 并行执行
同一时间做不同的工作
-
多任务并行执行:不同的程序同时运行
-
多线程并行执行:一个进程内的多个线程同时运行
3. 多线程编程
3.1 threading 模块
import threading
thread_obj = threading.Thread([group [, target [, name [, args [, kwargs]]]]])
- group: 暂时没用,未来功能的预留参数
- target: 执行的目标任务名
- args: 以元组的方式给执行任务传参
- kwargs: 以字典方式给执行任务传参
- name: 线程名,一般不用设置
# 启动线程,让线程开始工作
thread_obj.start()
3.2 示例1
import time
import threading
def sing():
while True:
print("我在唱歌,啦啦啦...")
time.sleep(1)
def dance():
while True:
print("我在跳舞,哗哗哗...")
time.sleep(1)
if __name__ == '__main__':
# 单线程
sing()
dance()
# 多线程
sing_thread = threading.Thread(target=sing)
dance_thread = threading.Thread(target=dance)
sing_thread.start()
dance_thread.start()
3.3 示例2
import time
import threading
def sing(msg):
while True:
print(msg)
time.sleep(1)
def dance(msg):
while True:
print(msg)
time.sleep(1)
if __name__ == '__main__':
# 创建线程
# args:通过元组(按参数顺序)的方式传参
sing_thread = threading.Thread(target=sing, args=("我要唱歌"))
# kwargs:用字典的形式传参
dance_thread = threading.Thread(target=dance, kwargs={"msg": "我要跳舞"})
# 启动线程
sing_thread.start()
dance_thread.start()
二十、网络编程
1. Socket
socket(简称套接字)是进程之间通信的工具,负责进程之间的网络数据传输
2. 客户端和服务端
-
Socket 服务端:等待其他进程的连接、可接收发来的消息、可回复消息
-
Socket 客户端:主动连接服务端、可以发送消息、可以接收回复
2.1 服务端
-
创建 socket 对象,并绑定 ip 地址和端口
-
服务端开始监听端口
# backlog:表示允许的连接数量,超出的会等待,省略则自动设置一个合理值
socket_server.listen(backlog)
- 接收客户端连接,获得连接对象
# accept方法是阻塞方法,若没连接,会卡在当前行不向下执行代码
# accept返回的是一个二元元组,可使用以下形式,用两个变量接收二元元组的两个元素
conn, address = socket_server.accept()
print(f"接收到客户端连接,连接来自:{address}")
- 回复与发送消息
# 可通过while True无限循环来持续和客户端进行数据交互
# 可通过判断客户端发来的特殊标记,如exit来退出循环
while True:
data = conn.recv(1024).decode("UTF-8")
# recv方法的返回值是字节数组(Bytes),可通过decode使用UTF-8解码为字符串
# recv方法的传参是buffsize,缓冲区大小,一般设置为1024即可
if data == 'exit':
break
print(f"接收到发送来的数据:{data}")
conn.send("你好呀".encode("UTF-8"))
具体示例:
import socket
socket_server = socket.socket() # 创建Socket对象
socket_server.bind(("localhost", 8888)) # 绑定ip地址和端口
socket_server.listen(1) # 监听端口
conn, address = socket_server.accept() # 等待客户端连接,conn为客户端当次连接对象
print(f"接收到了客户端的链接,客户端的信息是:{address}")
while True:
# 接收客户端信息,要使用客户端和服务端的本次链接对象,而非socket_server对象
data: str = conn.recv(1024).decode("UTF-8")
print(f"客户端发来的消息是:{data}")
# 发送回复消息,encode可以将字符串编码转为字节数组对象
msg = input("请输入你要和客户端回复的消息:")
if msg == 'exit':
break
conn.send(msg.encode("UTF-8"))
# 关闭链接
conn.close()
socket_server.close()
2.2 客户端
import socket
# 创建socket对象
socket_client = socket.socket()
# 连接到服务端
socket_client.connect(("localhost", 8888))
# 通过无限循环确保持续的发送消息给服务端
while True:
# 发送消息
msg = input("请输入要给服务端发送的消息:")
if msg == 'exit':
break
socket_client.send(msg.encode("UTF-8")) # 消息编码需为字节数组(UTF-8编码)
# 接收返回消息
recv_data = socket_client.recv(1024)
print(f"服务端回复的消息是:{recv_data.decode('UTF-8')}")
# 关闭链接
socket_client.close()
二十一、正则表达式
一种字符串验证的规则,通过特殊的字符串组合来确定规则
1.Python re模块
方法 | 说明 |
---|---|
match(匹配规则, 被匹配字符串) |
从被匹配字符串开头进行匹配,匹配第一个命中项(含匹配的信息),匹配失败返回空 |
search(匹配规则, 被匹配字符串) |
全局匹配,从前往后找,找到第一个后就停止,不会继续向后;若找不到返回None |
findall(匹配规则, 被匹配字符串) |
全局匹配,找出全部匹配项;找不到返回空 list |
示例1:
s = 'python itheima python itheima python itheima'
result = re.match('python', s)
print(result) # <re.Match object; span=(0, 6), match='python'>
print(result.span()) # (0, 6)
print(result.group()) # python
s = '1python itheima python itheima python itheima'
result = re.match('python', s)
print(result) # None
示例2:
import re
s = '1python666itheima666python666'
result = re.search('python', s)
print(result) # <re.Match object; span=(1, 7), match='python'>
print(result.span()) # (1, 7)
print(result.group()) # python
result = re.findall('python', s)
print(result) # ['python', 'python']
result = re.search('itcast', s)
print(result) # None
result = re.findall('itcast', s)
print(result) # []
2. 元字符匹配
2.1 单字符匹配
字符 | 功能 |
---|---|
. | 匹配任意1个字符(除了\n),\. 匹配点本身 |
[] | 匹配 [] 中列举的字符 |
\d | 匹配数字,即0-9 |
\D | 匹配非数字 |
\s | 匹配空白,即空格、tab |
\S | 匹配非空白 |
\w | 匹配单词字符,即a-z、A-Z、0-9、_ |
\W | 匹配非单词字符 |
2.2 数量匹配
字符 | 功能 |
---|---|
* | 匹配前一个规则的字符出现0至无数次 |
+ | 匹配前一个规则的字符出现至少1次 |
? | 匹配前一个规则的字符出现0次或1次 |
匹配前一个规则的字符出现m次 | |
匹配前一个规则的字符出现至少m次 | |
匹配前一个规则的字符出现m至n次 |
2.3 边界匹配
字符 | 功能 |
---|---|
^ | 匹配字符串开头 |
$ | 匹配字符串结尾 |
\b | 匹配一个单词的边界 |
\B | 匹配非单词边界 |
2.4 分组匹配
字符 | 功能 |
---|---|
| | 匹配左右任意一个表达式 |
() | 将括号中字符作为一个分组 |
2.5 示例
# 匹配账号,只能由字母和数字组成,长度限制6到10位
r = '^[0-9a-zA-Z]{6,10}$'
s = '123456_'
print(re.findall(r, s))
# 匹配QQ号,要求纯数字,长度5-11,第一位不为0
r = '^[1-9][0-9]{4,10}$' # [1-9]匹配第一位,[0-9]匹配后面4到10位
s = '12345678'
print(re.findall(r, s))
# 匹配邮箱地址,只允许qq、163、gmail这三种邮箱地址
r = r'(^[\w-]+(\.[\w-]+)*@(qq|163|gmail)(\.[\w-]+)+$)'
s = 'a.b.c.d.e.f.g@qq.com.a.z.c.d.e'
print(re.match(r,s))
二十二、递归
方法(函数)自己调用自己
def func():
if ...:
func()
return
- os 模块三个基础方法
import os
def test_os():
print(os.listdir("D:/test")) # 列出指定目录下的内容
print(os.path.isdir("D:/test/a")) # 判断给定路径是否为文件夹
print(os.path.exists("D:/tests")) # 判断给定路径是否存在
if __name__ == '__main__':
test_os()
1. 案例:递归找文件
import os
def get_files_recursion_from_dir(path):
"""
从指定的文件夹中使用递归的方式获取全部的文件列表
:param path: 被判断的文件夹
:return: list,包含全部文件,若目录不存在或者无文件就返回一个空list
"""
print(f"当前判断的文件夹是:{path}")
file_list = []
if os.path.exists(path):
for f in os.listdir(path):
new_path = path + "/" + f
if os.path.isdir(new_path):
# 若目录是文件夹
file_list += get_files_recursion_from_dir(new_path)
else:
file_list.append(new_path)
else:
print(f"指定的目录'{path}'不存在")
return []
return file_list
if __name__ == '__main__':
print(get_files_recursion_from_dir("D:/test"))
2. 注意点
-
注意退出条件,否则容易变成无限递归
-
注意返回值的传递,确保从最内层,层层传递到最外层
二十三、json文件
json 基于文本,独立于语言的轻量级的数据交换格式,本质上是一个带有特定格式的字符串
基于文本:是一个文本文件
独立于语言:不是某个语言特有的,每种编程语言都可以使用
轻量级:相同数据,相比于其他格式,占用的大小较小
数据交换格式:后端程序员给前端的数据(json、html、xml)
可以直接使用
read()
和write()
方法去操作文件,但是不方便,所以使用 json 文件自身特有的读取和写入方法在做测试时,常将测试数据定义为 json 文件格式,使用代码读取 json 文件,即读取测试数据,进行传参(参数化)
JSON 作用:使不同的语言能够互相传递数据
1. 语法
-
主要数据类型:对象
{}
和数组[]
,类似 Python 中的字典和列表(可相互嵌套) -
一个 json 文件是一个对象或数组
-
json 中的对象由键值对组成,每个数据之间用逗号隔开,最后一个数据后不用写逗号
-
json 中的字符串必须用
""
-
json 中的其他数据类型
-
数字 ---> int float
-
字符串 string ---> str
-
布尔 true、false ---> True、False
-
null ---> None
-
-
示例:
[
{
"name": "小明",
"age": 18,
"isMan": true,
"like": [
"吃饭",
"睡觉",
"打豆豆"
],
"address": {
"country": "中国",
"city": "上海"
}
},
{
"name": "小红",
"age": 17,
"isMan": false,
"like": [
"听歌",
"学习",
"购物"
],
"address": {
"country": "中国",
"city": "北京"
}
}
]
2. 读取 json 文件
json.load(文件对象)
,返回的是字典或列表
import json
with open("info.json", "r", encoding="utf-8") as f:
# list1 = json.load(f)
# print(list1[0].get('name'))
# print(list1[0].get('address').get('city'))
info_list = json.load(f)
for info in info_list:
print(info.get("name"), info.get("age"), info.get("address").get("city"))
3. 换成 [(), (), ()] 格式
某网站的测试数据如下,需求:提取 json 文件中的用户名、密码和预期结果,组成:[(), (), ()] 格式(自动化参数化需要的数据格式)
import json
def read_data():
new_list = []
with open('data.json', "r", encoding='utf-8') as f:
data = json.load(f)
print(data)
for d in data:
# print(d)
# print((d.get('username'), d.get('password'), d.get('expect')))
new_list.append((d.get('username'), d.get('password'), d.get('expect')))
return new_list
if __name__ == '__main__':
list1 = read_data()
print(list1)
4. json 的写入
f.write(字符串)
不能将Python的列表和字典作为参数传递,如果要写入 json 文件,则使用 json 特定的方法
json.dump(Python中的数据类型, 文件对象)
import json
my_list = [('admin', '123456', '登录成功'), ('root', '123456', '登录失败'), ('admin', '123123', '登录失败')]
with open('test.json', 'w', encoding='utf-8') as f:
json.dump(my_list, f, ensure_ascii=False, indent=2) # 直接显示中文,不以ASCII的方式显示,并进行缩进
5. Python 数据和 Json 数据的相互转化
# 导入json模块
import json
# 准备符合格式json格式要求的python数据
data = [{"name":"老王", "age":16}, {"name":"张三", "age":20}]
# 通过json.dumps(data)方法把python数据转化为了json数据
data = json.dumps(data)
# 通过json.loads(data)方法把json数据转化为了python数据
data = json.loads(data)
注:如果有中文,带上ensure_ascii=False
来确保中文正常转换
示例:
import json
data = [{"name":"张大山", "age":18}, {"name":"王大锤","age":13}, {"name":"赵啸虎","age":16}]
json_str = json.dumps(data, ensure_ascii=False)
print(type(json_str))
print(json_str)
d = {"name":"周杰伦", "addr":"台北"}
json_str = json.dumps(a, ensure_ascii=False)
print(type(json_str))
print(json_str)
# 将json字符串转换为Python数据类型[{},{},{}]
s = '[{"name":"张大山", "age":18}, {"name":"王大锤","age":13}, {"name":"赵啸虎","age":16}]'
l = json.loads(s)
print(type(l))
print(l)
# 将json字符串转换为Python的数据类型{k:v, k:v, k:v}
s = '{"name":"周杰伦", "addr":"台北"}'
d = json.loads(s)
print(type(d))
print(d)