Loading

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.realx.imag来分别获取 x 的实部和虚部,结果都是浮点型

>>> x.real
12.0
>>> x.imag
34.0

4. 转换类型

4.1 为什么

  • 从文件中读取的数字,默认是字符串,需要转换成数字类型

  • input()语句默认结果是字符串,有数字也需要转换

  • 将数字转换成字符串用以写出到外部系统

4.2 常见的转换语句

语句(函数) 说明
int(x) 转换为整数
float(x) 转换为浮点数
str(x) 将对象 x 转换为字符串

注:浮点数转换为整数时会丢失精度

二、注释

  1. 单行注释
# 我是单行注释
  1. 多行注释
"""
	我是多行注释
"""
  1. 工作日志说明:进行没有完成的功能备注
# 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 说明

  1. for 循环无法定义循环条件,只能从被处理的数据集中依次取出内容进行处理

  2. 待处理数据集,严格来说为序列类型【for 循环本质上是遍历序列类型】

  3. 序列类型指:其内容可以一个个依次取出的一种类型,包括字符串、列表、元组

  4. 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_module1my_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)
posted @ 2024-12-03 00:21  iRuriCatt  阅读(155)  评论(0编辑  收藏  举报