1. 基本数据类型-掌握注释-数字与字符串
变量的声明与关键字规范
变量的声明与关键字规范
basic_types.py
name = "大周"
my_name = "大周1"
age = 18
name1: str = "aa"
name2: str = 1
and = 1
注释-Python代码的说明文档
单行注释
"""
开头3个引号,结尾3个引号,在中间的内容全都是注释
这就是多行注释
"""
声明一个变量叫做name,其值为字符串,让值等于大周
name = "大周"
my_name = "大周1"
age = 18
name1: str = "aa"
name2: str = 1
这里就是单行注释
and = 1
print函数应用-单行打印与多行打印的实现
"""
本节课讲解的内容是,单行打印与多行打印
这个文件名称是不规范的,不能这么起
工程里应该叫做print_study.py
"""
单行打印
print("hello world")
name = "大周"
print()函数中,可以传入一个变量的名称,也可以传入一个变量的值,这个值可以是字符串,也可以是数字
print(name)
print(18)
print()函数中,可以传入多个参数,多个参数之间用逗号隔开
print(name, 18)
使用print函数进行多行打印
第一种办法,使用转义字符\n,达到回车换行的目的
print("我是多行打印,\n我想要换行")
第二种办法,使用多行字符串,直接打印
print("""
我是第一行
我是第二行
我是第三行
""")
a = """
我是第四行
我是第五行
我是第六行
"""
print(a)
Python内置基础数据类型全解析
数字类型
常用的分为两种,一种是整数,另外一种是小数,小数又叫浮点数
整数
a = 1
b = -1
小数,也叫浮点数
c = 1.1
d = -1.1
字符串,字符串它有一个长度,理论上来说,我们暂时可以理解为无限长度
name = "大周啊啊啊啊啊啊啊啊大周啊啊啊啊啊啊啊啊大周啊啊啊啊啊啊啊啊大周啊啊啊啊啊啊啊啊大周啊啊啊啊啊啊啊啊"
多行字符串
name = """我是第一行
我是第二行
我是第三行
"""
布尔类型,布尔类型只有两个值,真和假
my_bool1 = True
my_bool2 = False
print(a,b,c,d,name,my_bool1,my_bool2)
基本运算-各数据类型的算数运算
基本运算:各数据类型的算数运算
"""
数字类型、字符串类型、布尔类型的加减乘除运算
"""
数字类型
a = 10
b = 3
print(a+b)
print(a-b)
print(a*b)
print(a/b)
字符串的加法,又叫做字符串的拼接
a = "hello"
b = "world"
print(a+b)
print(a-b) 字符串不支持减法运算
字符串如果想要做乘法运算,只能与整数类型相乘
i = 2
print(a*i)
print(a/b) 字符串与字符串不支持除法运算
布尔值的加减乘除运算
x = True # True相当于1
y = False # False相当于0
print(x+y)
print(x-y)
print(x*y)
print(y/x)
数据类型转换-隐式转换与显式转换
数据类型转换:隐式转换与显式转换
a = 5 # int 类型
b = 2.0 # float 类型
result = a + b # 隐式转换:int 转换为 float
print(result) # 输出:7.0
print(type(result)) # 输出:<class 'float'>
type()函数就是查看某一个变量的数据类型的
x = "大周"
y = 1 # 1 转换成字符串就是 "1"
你需要用到显示转换来解决x + y的问题
str()函数,实现的就是将其它数据类型转换成字符串类型
y = str(y)
r = x + y
print(r)
print(type(r))
int()函数是实现,将其它数据类型转换成整数类型
所以,要想将其它数据类型转换成一个整数类型,那么这个数据类型必须看起来是一个整数
z = "10"
z = int(z)
print(z)
print(type(z))
float()函数,实现将其它数据类型转换成浮点数类型
x = float(z)
print(x)
print(type(x))
布尔值的数据类型转换
x = True
y = False
布尔值转int
x = int(x)
print(x)
print(type(x))
#######
x = int(y)
print(x)
print(type(x))
一个整数类型可以转换成布尔类型吗?
x = -1
y = bool(x)
print(y)
print(type(y))
一个整数类型是可以转换成布尔值类型的,如果这个值是0,那么转换后就是False
如果这个是非0,那么转换后就是True
2. 理解Python的条件逻辑-比较运算与逻辑运算
比较运算符-两个值的大小-相等性比较
比较运算符:两个值的大小 / 相等性比较
a = 5
b = 10
print(a == b)
print(a != b)
x = 3
y = 7
print(x < y)
print(x <= y)
print(x > y)
print(x >= y)
示例:字符串比较(基于 ASCII 值)
str1 = "apple"
str2 = "banana"
print(str1 < str2)
print("A" > "Z")
print("a" > "z")
a = "ab"
b = "ac"
print(a<b)
逻辑运算符-多条件的组合与判断
逻辑运算符:多条件的组合与判断
x = 5
y = 10
True and True = True
and 当所有组合条件都为True,则整体结果为True
print( x > 0 and y > 0)
True or False = True
or 当所有组合条件中,至少有一个为True,则整体结果为True
print( x > 0 or y < 0)
not 取反
not True = False
print( not x > 0)
我可以使用3个及以上条件进行判断吗?
x = 5
y = 10
z = 15
True and True and True = True
print( x > 0 and y > 0 and z > 0)
True or True or False = True
print( x > 0 or y > 0 or z < 0)
False or False or False = False
print(x < 0 or y < 0 or z < 0)
条件控制语句-基于逻辑判断的代码执行分支
条件控制语句:基于逻辑判断的代码执行分支
if语句
if 逻辑判断条件:
x = 0
if x > 5:
print("x大于5")
else:
print("x小于5")
print("主程序运行结束")
x = 16
if x > 5 and x < 10:
print("x大于5,小于10")
elif x > 10 and x < 15:
print("x大于10")
elif x > 15:
print("x大于15")
else:
print("x小于5")
在这里,我的代码可以不是结束,可以是经过if逻辑判断后,处理的结果再次进行处理
print("主程序运行结束")
海象运算符-一行搞定赋值-判断-优化代码效率
海象运算符:一行搞定赋值 + 判断,优化代码效率
写法:这里一个变量的名称 := 是一个表达式,这个表达式的返回值是赋给这个变量的值
x = 10
y = 5
z = x > y
print(z)
if z:
print("x大于y",z)
if x > y:
z = z > y
print("x大于y",x > y)
使用海象运算符,对以上代码进行重新书写
if z := x > y:
print("x大于y",z)
"""
写法:这里一个变量的名称 := 是一个表达式,这个表达式的返回值是赋给这个变量的值
表达式: x > y 结果就是True
使用了海象运算符 :=
就是将表达式的结果True,赋值给 海象运算符前边的 这个变量 z
z = True
"""
实战练习-BMI身体质量指数运算器
实战练习:BMI身体质量指数运算器
"""
需求描述:
BMI指数(身体质量指数)的运算公式为:
BMI = 体重(kg) ÷ 身高(m)²
即:用体重的千克数除以身高米数的平方。
计算示例
例如,一个人体重为70千克,身高为1.75米,则BMI计算如下:
70 ÷ (1.75 × 1.75) = 70 ÷ 3.0625 ≈ 22.86
常用分类标准
根据中国卫生健康委员会发布的《成人体重判定》标准(适用于18-65岁普通成年人):
体重过低:BMI < 18.5
正常体重:18.5 ≤ BMI < 24
超重:24 ≤ BMI < 28
肥胖:BMI ≥ 28
要求:由用户自己输入身高和体重,然后输出用户是肥胖、超重、正常体重、体重过低,再加上其BMI的值
"""
让用户从键盘自己输入
a = input("从键盘输入>>>>")
print(a)
print(type(a))
写法一:用传统的书写方法
height = float(input("请输入身高:"))
weight = float(input("请输入体重:"))
bmi = weight / height ** 2
if bmi < 18.5:
print("体重过低","其BMI指数是",bmi)
elif bmi < 24:
print("正常体重","其BMI指数是",bmi)
elif bmi < 28:
print("超重","其BMI指数是",bmi)
elif bmi >= 28:
print("肥胖","其BMI指数是",bmi)
else:
print("输入错误")
写法二:用海象运算符进行书写代码 变量 := 表达式
height = float(input("请输入身高:"))
weight = float(input("请输入体重:"))
if (bmi := weight / height ** 2) < 18.5:
print("体重过低","其BMI指数是",bmi)
print("请保持健康")
elif bmi< 24:
print("正常体重","其BMI指数是",bmi)
elif bmi< 28:
print("超重","其BMI指数是",bmi)
elif bmi >= 28:
print("肥胖","其BMI指数是",bmi)
else:
print("输入错误")
"""
代码块:
位于同一个缩进位置的代码,叫同一个代码块
缩进:指的是4个空格,或者是一个tab(你键盘上字母q左边的那个按钮)
"""
3. 玩转循环-Python重复执行代码的核心
初识Python循环-while循环的核心逻辑
初识Python循环:while循环的核心逻辑
while 逻辑判断条件:
注意:使用while循环的时候,一定一定要知道循环的结束条件是什么,否则,可能会造成死循环
a = 3
while a > 0:
print(a)
a = a - 1
if a == 1:
break
print("循环运行结束,跳出循环")
循环灵活控制-用continue跳过本次循环
循环灵活控制:用continue跳过本次循环
continue 跳过本次循环,继续下一次循环
a = 1
while True:
a = a + 1
# 只打印偶数
if a % 2 != 0:
# 跳过本次循环
continue
print(a)
if a > 10:
break
简化赋值操作-快速掌握赋值运算符
简化赋值操作:快速掌握赋值运算符
+= -= *= /= %=
+=
a = 1
a = a + 1
print(a)
a += 1
a += 1
print(a)
-=
b = 5
b = b - 1
b -= 1
print(b)
*=
c = 2
c = c * 1
c *= 3
print(c)
/=
d = 8
d = d / 2
d /= 4
print(d)
实战练习-手把手实现简易计算器
实战练习:手把手实现简易计算器
"""
需求描述:
用户从键盘输入
先输入一个数字,然后让用户输入操作符号,操作符号支持 加减乘除
最后再输入一个数字
最后计算出结果
当用户输入字母q的时候,退出计算器,否则用户重新开始输入第一个数字,再次进行计算
"""
while True:
first_number = float(input("请输入第一个数字:"))
operation = input("请输入操作符号:")
if operation == "q":
break
second_number = float(input("请输入第二个数字:"))
if operation == "+":
print(first_number + second_number)
elif operation == "-":
print(first_number - second_number)
elif operation == "*":
print(first_number * second_number)
elif operation == "/":
print(first_number / second_number)
else:
print("输入错误")
4. 玩转字符串-Python-文本处理核心
字符串格式化输出-让文本输出更灵活
字符串格式化输出:让文本输出更灵活
第一种方式 .format
name = "老王"
age = 18
score = 98.49999
s = "欢迎{},你的年龄是{},你的分数是{}".format(name,age,score)
print(s)
第二种方式 %s %d %f
%s代表的是,字符串替换
%d代表的是,数字替换
%f代表的是,小数替换
s = "欢迎%s,你的年龄是%d,你的分数是%.1f" % (name,age,score)
print(s)
第三种方式,就是在字符串前边加一个f,f-string
print(f"欢迎{name},你的年龄是{age},你的分数是{score}")
print(f"欢迎{name},你的年龄是{age},你的分数是{score:.2f}")
文本操作-字符串查找与替换
文本操作:字符串查找与替换
字符串的查找,常用方法是find,find这个方法返回值是字符串中,子串的索引,如果没有找到,返回-1
索引:其实指的就是位置
日常生活中,我们数数字,或者是数位置,都是从1开始的
在Python编程中,数位置是从0开始的
text = "Python是一门优秀的编程语言,我喜欢Python"
print(text[0]) # 访问text这段文本中的第0个位置的字符
print(text[1])
print(text[2])
print(f"查找的位置信息是{text.find('Python')}")
print(f"查找的位置信息是{text.find('Java')}")
总结:find方法返回值是子串在字符串中的索引,如果没有找到,返回-1
从右侧查找,我们使用方法:rfind
print(f"从右侧查找的位置信息是{text.rfind('Python')}")
另外一个查找的函数叫做index()
index()函数与find()不同的地方是,find如果找不到则返回-1,index如果找不到则抛出异常
print(f"index()方法返回的位置信息是{text.index('Python')}")
print(f"index()方法返回的位置信息是{text.index('Java')}")
字符串替换,替换用的方法是replace
print(text.replace("Python","Java"))
去除两端的空字符方法:strip()
空字符包括:空格 、换行符\n、制表符\t tab
text = " Python是一门优秀的编程语言,我喜欢Python \n\t"
print(text)
print(text.strip())
成员运算符-判断字符和子串是否存在
成员运算符:判断字符和子串是否存在
in not in
text = "Python是一门优秀的编程语言,我喜欢Python"
print("P" in text)
print("P" not in text)
print("我" in text)
print("我" not in text)
print("语言" in text)
print("语言" not in text)
print("," in text)
print("," in text)
实战练习-基于关键字匹配的聊天机器人
实战练习:基于关键字匹配的聊天机器人
robot = "擎天柱"
while True:
user_input = input("用户说:")
if user_input in "拜拜" or user_input in "再见" or user_input in "88":
print(f"{robot}:好的,与你聊天很愉快,期待下次再见")
break
elif user_input == "你是谁":
print(f"{robot}:我叫{robot}")
elif user_input.find("学习") > -1:
print(f"{robot}:我现在正在跟大周老师学习Python")
elif user_input.find("水果") > -1:
print(f"{robot}:我喜欢香蕉、苹果、大鸭梨!!")
else:
print(f"{robot}:不好意思哦,我没有理解你说的是什么...")
5. 高级数据类型-列表-元组-字典与进阶语法
列表类型-Python最常用的序列容器
列表类型
声明一个列表类型
list1 = [1,2,3,4,5]
访问列表中元素。
索引从0开始
print(list1[0],type(list1[0]))
print(list1[1],type(list1[1]))
list2 = ["1","2",3,4,5]
print(list2[0],type(list2[0]))
print(list2[1],type(list2[1]))
list3 = ["1","2",3.5,4,5]
list4 = ["1","2",3.5,True,5]
list5 = [["1","2"],3.5,True,5]
print(list5[0],type(list5[0]))
list6 = [["1","2"],[3.5,True,5]]
print(list6[0][0])
print(list6[1][1])
列表是一个可迭代的对象
列表的基础操作-访问与修改元素
列表的基础操作:访问与修改元素
访问:正向访问,与 反向访问
list1 = [1,2,3,4,5]
从右到左就叫做反向反问
我想要快速的访问到列表中的最后一个元素
print(list1[-1])
切片访问
语法:[start:end:step] start代表开始的位置,end代表结束的位置,step代表步长
print(list1[0:3]) # 包括start的位置,但不包括end的位置
print(list1[0:5:2])
print(list1[::-1]) # 字符串的快速反转
print(list1[:3]) # 如果你的开始位置是从头开始的,那么start为0可以不写
print(list1[2:]) # 如果你结束的位置是0,那么end为0可以不写
列表元素的新增
list1.append(6) # append是在结尾处新增列表元素
print(list1)
list1.insert(0,100) # index代表着插入的位置,object代表着要插入的值
print(list1)
list1.extend([7,8,9]) # 列表的拼接,扩展
print(list1)
列表元素的修改
list1[0] = 1000
print(list1)
列表元素的删除
list1.remove(1000)
print(list1)
r = list1.pop(1) # pop删除的元素,返回删除的元素,参数传递为索引
print(r)
print(list1)
r = list1.pop() # 如果不写参数,则默认删除最后一个元素
print(r)
print(list1)
del list1[0]
print(list1)
元组类型-不可变的序列容器
元组类型:不可变的序列容器 其类型叫做:tuple
声明一个元组类型
t1 = (1,2,3,4,5)
print(t1,type(t1))
t2: tuple = (1,2,3,4,5)
print(t2,type(t2))
print(t1[0])
t3 = (1,2.2,"hello",True,[1,2,3])
print(t3[0])
t3[0] = 100
print(t3)
t4 = (1,)
print(t4,type(t4))
t3.append(100)
del t3[0]
print(t3[4])
t3[4] = [100,200]
t3[4] = [100,200,300]
t3[4].append(100)
t3[4][0]=200
print(t3)
字典类型-键值对形式的映射容器
字典类型:键值对形式的映射容器
在Python中我们叫做字典,在其他语言中,或者是更为广泛的应用场景中,我们管长成字典这个样子的数据类型叫做json
声明一个字典
基本的格式 {key:value,key:value,key:value}
d1 = {
"name": "张三",
"age": 18,
"sex": "男"
}
以上是最为常用的一种声明方式
其中的key是不可变的数据类型,比如字符串、数字、元组
d2 = {
"name": "张三",
"age": 18,
"sex": "男",
1 : "张三",
(1,2,3) : "张三",
}
print(d2,type(d2))
第二种字典的声明方式
d3 = dict(name="张三",age=18,sex="男")
print(d3,type(d3))
第三种,声明一个空的字典
d4 = dict()
第四种,声明一个空的字典
d5 = {}
a ="1"
a = "2"
print(a)
字典的基础操作-增删改查
字典的基础操作:增删改查
如何查询字典
d1 = {
"name": "张三",
"age": 18,
"sex": "男",
"scores": {
"chinese": 96,
"english": 98,
"math": 99
}
}
字典的查询
print(d1["name"])
print(d1["scores"])
print(d1.get("name"))
print(d1["aaa"]) # 当我使用[]的形式进行字典访问的时候,如果key不存在,则抛出异常
print(d1.get("aaa")) # 当我使用get方法进行字典访问的时候,如果key不存在,则返回None,就是不存在的意思
字典的修改: 更新、添加
d1["name"] = "王五"
print(d1)
d1["address"] = "北京市顺义区"
print(d1)
d1.update({"name": "李四","class":"一年二班"})
print(d1)
字典的删除
del d1["name"]
print(d1)
r = d1.pop("class")
print(r)
print(d1)
再谈循环-for循环
再谈循环:for 循环(遍历高级数据类型)
使用for循环,遍历列表数据类型
list1 = [1,2,3,4,5]
for i in list1:
print(i)
if i == 3:
break
使用for循环,遍历列表数据类型的索引
print(range(3))
for i in range(3):
print(i)
len函数,获取列表的长度
print(len(list1))
range(len(list1)) = range(5) =[0,1,2,3,4]
for i in range(len(list1)):
print(i,list1[i])
for循环遍历元组
t1 = (1,2,3,4,5)
for v in t1:
print(v)
for 循环遍历字典
d1 = {
"name": "张三",
"age": 18,
"sex": "男",
"scores": {
"chinese": 96,
"english": 98,
"math": 99
}
}
第一种遍历方式,先拿出来key,再根据key访问value
for k in d1:
print(k,d1[k])
第二种遍历方式,同时拿到key和value
for k,v in d1.items(): # 使用items方法拿到key和value
print(k,v)
第三种遍历方式,只访问value
for v in d1.values(): # 使用values方法
print(v)
实战案例:魔法读心术代码实现
实战案例:魔法读心术代码实现(列表趣味应用)
游戏玩法说明:有6张卡片,分别为A、B、C、D、E、F,每张卡片上有一些数字,这些数字是经过精密的排列的,如下图
让用户记住其中一个数字,并告知程序,这个数字都位于哪个卡片上,我们的程序就能够打印出来用户想的是什么数字
A = [1, 9, 17, 25, 33, 41, 49, 57, 3, 11, 19, 27, 35, 43, 51, 59, 5, 13, 21, 29, 37, 45, 53, 61, 7, 15, 23, 31, 39, 47, 55, 63]
B = [2, 10, 18, 26, 34, 42, 50, 58, 3, 11, 19, 27, 35, 43, 51, 59, 6, 14, 22, 30, 38, 46, 54, 62, 7, 15, 23, 31, 39, 47, 55, 63]
C = [4, 12, 20, 28, 36, 44, 52, 60, 5, 13, 21, 29, 37, 45, 53, 61, 6, 14, 22, 30, 38, 46, 54, 62, 7, 15, 23, 31, 39, 47, 55, 63]
D = [8, 12, 24, 28, 40, 44, 56, 60, 9, 13, 25, 29, 41, 45, 57, 61, 10, 14, 26, 30, 42, 46, 58, 62, 11, 15, 27, 31, 43, 47, 59, 63]
E = [16, 20, 24, 28, 48, 52, 56, 60, 17, 21, 25, 29, 49, 53, 57, 61, 18, 22, 26, 30, 50, 54, 58, 62, 19, 23, 27, 31, 51, 55, 59, 63]
F = [32, 36, 40, 44, 48, 52, 56, 60, 33, 37, 41, 45, 49, 53, 57, 61, 34, 38, 42, 46, 50, 54, 58, 62, 35, 39, 43, 47, 51, 55, 59, 63]
实现方法揭秘:
用户想的数字,其实就是这个数字位于的卡片上的第一个数字的和
声明一个变量,用于保存用户输入的卡片的字符串
cards = input("请输入你认为的数字位于的卡片,多张卡片使用英文的逗号进行分隔,不要撒谎哦,请输入:")
我们要把用户输入的字符串,拆分成一个列表,使用英文的逗号进行拆分
split函数就是用来分隔字符串的,参数传递为分隔符,返回值是一个list
card_list = cards.split(",")
声明一个变量,用于存储卡片上的第一个数字
cards_number_list = []
for card in card_list:
if card.upper() == "A":
cards_number_list.append(A[0])
elif card.upper() == "B":
cards_number_list.append(B[0])
elif card.upper() == "C":
cards_number_list.append(C[0])
elif card.upper() == "D":
cards_number_list.append(D[0])
elif card.upper() == "E":
cards_number_list.append(E[0])
elif card.upper() == "F":
cards_number_list.append(F[0])
计算存储在cards_number_list当中这些数字的和
your_number = 0
for number in cards_number_list:
your_number += number
print("你认为的数字是:%d" % your_number)
Python结构化模式匹配match-case
Python 结构化模式匹配(match-case)
Python 3.10 新增了结构化模式匹配(structural pattern matching)
match-case语法,是在一定的特定的场景下,替代if elif else
语法:
match value:
a = 3
match a:
case 1:
print("a等于1")
case 2:
print("a等于2")
case _:
print("a不等于1和2")
列表的数据类型进行演示
list1 = [1,2,3,4]
match list1:
case [1,2,3,4,5]:
print("list1等于[1,2,3,4,5]")
case [1,2,3,4]:
print("list1等于[1,2,3,4]")
case [1,2,3]:
print("list1等于[1,2,3]")
case [1,2]:
print("list1等于[1,2]")
case [1]:
print("list1等于[1]")
l1 = [1,2,3,4,5]
match l1:
case []:
print("这里是一个空列表")
case [x]:
print("列表中只有一个元素,这个元素是:",x)
case [x,y]:
print("列表中有两个元素,第一个元素是:",x,"第二个元素是:",y)
case [x,*r]:
print("列表中有多个元素,第一个元素是:",x,"后面的元素是:",r)
字典的数据类型进行演示
dict1 = {"name":"张三"}
match dict1:
case {"name":"张三","age":18}:
print("dict1等于{'name':'张三','age':18}")
case {"name":"张三"}:
print("dict1等于{'name':'张三'}")
user = {"namea":"张三","age":18}
match user:
case {"name":name,"age":age} if age > 18:
print(f"{name},成年人")
case {"name": name, "age": age}:
print(f"dict1等于{name},未成年人")
case _:
print("没有匹配上")
or 的匹配方法
i = 4
match i:
case 1 | 2 | 3:
print("i等于1或者2或者3")
case _:
print("没有匹配上")
Python列表推导-简洁创建列表的进阶语法
Python 列表推导式:简洁创建列表的进阶语法
一句话理解列表推导式: 一个for循环加上一个append,快速创建列表
[表达式 for 变量 in 可迭代对象]
[表达式 for 变量 in 可迭代对象 if 条件]
传统方式创建平方数列表
squares_traditional = []
for i in range(1, 6):
squares_traditional.append(i ** 2)
print(f"传统方式: {squares_traditional}")
使用列表推导式
squares_comprehension = [i**2 for i in range(1, 6)]
print(f"推导式方式: {squares_comprehension}")
筛选偶数并求平方
even_squares = [i ** 2 for i in range(1, 11) if i % 2 == 0]
print(f"偶数的平方: {even_squares}")
复杂条件筛选
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
filtered_numbers = [num for num in numbers if num > 3 and num < 8]
print(f"3到8之间的数: {filtered_numbers}")
生成坐标点
coordinates = [(x, y, z) for x in range(3) for y in range(3) for z in range(3)]
print(f"坐标点: {coordinates}")
传统嵌套循环对比
coords_traditional = []
for x in range(3):
for y in range(3):
coords_traditional.append((x, y))
print(f"传统方式: {coords_traditional}")
"""
外层为0时
(0,0)
(0,1)
(0,2)
外层为1时
(1,0)
(1,1)
(1,2)
外层为2时
(2,0)
(2,1)
(2,2)
[(0,0),(0,1),(0,2),(1,0)......]
"""
6. 函数的定义与使用-Python代码复用核心
函数入门-声明并调用你的第一个函数
函数入门:声明并调用你的第一个函数
声明函数的基本语法
def 函数的名称(函数的参数):
函数体
def function_name(parameters):
声明一个函数,实现两个数字相加的功能
def add(a,b):
print(a + b)
调用这个函数
add(1,2)
add(2,3)
add(4,5)
def my_print():
print("hello world")
my_print()
my_print()
my_print()
my_print()
函数返回值-让函数给你返回结果
函数返回值:让函数给你 “返回结果”
def add(a,b):
r = a + b
return r
我想用两数相加的结果,再做一点事情
res = add(1,2)
print(res)
代码在函数中,运行到return,在return下边的代码就不会执行了
def add1(a,b):
r = a + b
return r
print("hello world")
res1 = add1(2,4)
print(res1)
函数参数-玩转位置-关键字- 默认参数-可变参数
函数参数:玩转位置 / 关键字 / 默认参数 / 可变参数
函数的位置参数
def greet(name:str, age:int):
"""位置参数:按顺序传入,位置很重要"""
return f"你好,我是{name},今年{age}岁"
正确调用
result1 = greet("小明", 18)
print(result1)
错误调用 - 位置颠倒
result2 = greet(20, "小红")
print(result2)
def introduce(name, age, city):
"""关键字参数:通过参数名指定值,顺序不重要"""
return f"姓名:{name},年龄:{age},城市:{city}"
使用关键字参数
result3 = introduce(age=25, name="李雷", city="北京")
print(result3)
混合使用位置参数和关键字参数
result4 = introduce("韩梅梅", city="上海", age=23)
print(result4)
result4 = introduce(city="上海", age=23, "韩梅梅")
位置参数和关键字参数混合使用时,位置参数必须位于关键字参数前边
否则位置参数找不到应该传递给谁
def create_profile(name, age, gender="未知", hobby="无"):
"""默认参数:为参数设置默认值"""
return f"姓名:{name},年龄:{age},性别:{gender},爱好:{hobby}"
使用默认值
profile1 = create_profile("张三", 20)
print(profile1)
部分覆盖默认值
profile2 = create_profile("李四", 22, "男")
print(profile2)
注意:默认参数必须放在非默认参数后面
def bad_function(name="无名", age):
pass
def calculate_sum(*numbers):
"""*args:接收任意数量的位置参数,打包成元组"""
print(f"接收到的参数: {numbers}")
print(f"参数类型: {type(numbers)}")
return sum(numbers)
传入不同数量的参数
sum1 = calculate_sum(1, 2, 3)
print(f"1+2+3 = {sum1}")
sum2 = calculate_sum(10, 20, 30, 40, 50)
print(f"多个数之和 = {sum2}")
sum3 = calculate_sum()
print(f"空参数之和 = {sum3}")
def flexible_function(required_param, *optional_params):
"""混合使用:必需参数 + 可变参数"""
print(f"必需参数: {required_param}")
print(f"可选参数: {optional_params}")
if optional_params:
print(f"可选参数个数: {len(optional_params)}")
flexible_function("必须值")
flexible_function("必须值", "额外1", "额外2", "额外3")
def create_student(**info):
"""**kwargs:接收任意数量的关键字参数,打包成字典"""
print(f"接收到的信息: {info}")
print(f"信息类型: {type(info)}")
student_info = "学生信息:"
for key, value in info.items():
student_info += f"{key}={value}, "
return student_info.rstrip(", ")
传入关键字参数
student1 = create_student(name="小明", age=18, grade="高三", subject="理科")
print(student1)
student2 = create_student(name="小红", age=17)
print(student2)
def advanced_function(normal_param, *args, **kwargs):
"""综合使用所有参数类型"""
print(f"普通参数: {normal_param}")
print(f"可变位置参数: {args}")
print(f"可变关键字参数: {kwargs}")
advanced_function(
"固定参数",
"额外参数1", "额外参数2",
key1="值1", key2="值2"
)
列表/元组解包给位置参数
def multiply(x, y, z):
return x * y * z
numbers = [2, 3, 4]
result = multiply(*numbers)
print(f"解包列表: {result}")
字典解包给关键字参数
def register_user(username, email, password):
return f"注册用户: {username}, 邮箱: {email}"
user_info = {"username": "alice", "email": "alice@email.com", "password": "123456"}
registration = register_user(**user_info)
"""
**user_info
username=alice
email=alice@email.com
password=123456
register_user(username=alice,email=alice@email.com,password=123456)
"""
print(registration)
小技巧-让函数返回多个值
小技巧:让函数返回多个值
函数返回多个值,只不过是在return后边加多个值而已,多个值使用逗号进行分隔
def get_name_and_age():
"""返回姓名和年龄"""
name = "小明"
age = 18
return name, age
a = get_name_and_age()
print(a)
print(type(a))
a,b = get_name_and_age()
print(a)
print(b)
a,_ = get_name_and_age()
print(a)
def get_name_and_age1():
"""返回姓名和年龄"""
name = "小明"
age = 18
classes = "1班"
return name, age,classes
a,_,_ = get_name_and_age1()
print(a)
递归函数-函数自己调用自己的进阶玩法
递归函数:函数自己调用自己的进阶玩法
使用递归函数时,一定要明确递归什么时候结束
def a(n):
if n > 10:
return
print(n)
a(n+1)
a(1)
"""
n = 1
n = 2
n = 3
"""
def factorial(n):
"""计算阶乘 n! = n × (n-1) × ... × 1"""
if n <= 1:
return 1
else:
return n * factorial(n - 1)
"""
5 * factorial(4)
5 * 4 * factorial(3)
5 * 4 * 3 * factorial(2)
5 * 4 * 3 * 2 * 1
"""
print(factorial(5))
7. 闭包与装饰器-Python函数进阶技巧
读懂Python变量作用域-局部与全局
Python变量的作用域
"""
作用域类型
1. 全局作用域(Global): 定义在函数 / 类 外部的变量 , 整个程序都能访问
2. 局部作用域(Local):定义在函数 / 类 / 代码块 内部的变量 , 仅在定义它的代码块内有效
"""
一句话理解:变量的作用域 = 变量能被访问 或者是被 修改的有效范围
全局变量的访问
name = "大周"
def print_name():
print("函数内部访问全局变量",name)
print_name()
print("函数外部访问全局变量",name)
局部变量的访问限制
def set_age():
age = 18
print("函数内部访问局部变量",age)
set_age()
函数外部可以访问局部变量age吗?
print("函数外部访问局部变量",age)
容易犯错的点:局部变量覆盖了全局变量
num = 100
def change_num():
num = 200
print("函数内部访问局部变量",num)
change_num()
print("函数外部访问全局变量",num)
如何在局部修改全局变量,使用global关键字
使用global关键声明一下,某个代码块或者是函数内部的变量,告诉Python,这是一个全局变量
count = 0
def add_count():
global count
count += 1
print("当前计数为(函数内部):",count)
add_count()
print("函数外部查看修改后的count值:",count)
以下写法会直接抛出异常
count = 0
def add_count():
count += 1
print("=========当前计数为(函数内部):",count)
add_count()
闭包:嵌套函数的进阶应用(什么是闭包)
闭包:嵌套函数的进阶应用(什么是闭包)
普通嵌套函数 ≠ 闭包
什么是嵌套函数
def outer():
message = "hello"
def inner():
print(message)
inner()
outer()
"""
理解什么是闭包
1. 通俗解释
闭包是「有记忆的嵌套函数」—— 外层函数把内层函数返回出来(而非执行),
内层函数不仅嵌套在外部函数里、引用外部变量,还能在外部函数执行完后,依然 “记住” 外部变量的状态,独立被调用。
你可以这样记:
- 嵌套函数 = 内层函数 “住在” 外层函数里;
- 闭包 = 内层函数 “搬出去住”,但带走了外层函数的 “生活用品”(变量)。
2. 专业定义(3 个必须满足的条件)
闭包是满足以下 3 个条件的嵌套函数(缺一不可):
2.1. **嵌套**:内层函数定义在外层函数内部;
2.2. **引用**:内层函数引用了外层函数的非全局变量(自由变量);
2.3. **返回**:外层函数返回内层函数对象(而非执行内层函数)。
"""
def outer_func(prefix):
prefix = prefix
def inner_func(name):
return f"{prefix},{name}"
return inner_func
调用外层函数,返回内层函数
hi = outer_func("Hi")
独立调用内部函数,仍然能使用之前的prefix变量
print(hi("Mike"))
print(hi("Jack"))
再次创建一个新的闭包,与前一个闭包无关
hello = outer_func("Hello")
print(hello("Mike"))
print(hello("Jack"))
"""
闭包的特性
1. 状态保留:外层函数执行完成之后,变量仍然被内层函数保留,无需用全局变量来存储
2. 变量私有化:外层变量只能被内层函数访问,全局无法直接修改,避免全局变量污染
3. 代码复用:基于同一个外层函数,可以创建多个带不同初始状态的内层函数,逻辑复用
4. 延迟执行:外层函数仅配置状态,内层函数在需要时才执行逻辑
"""
def counter(start=0):
count = start
def incr():
nonlocal count
count += 1
return count
return incr
创建计数器闭包
cnt = counter(1)
print(cnt())
print(cnt())
实战场景描述:创建不同税率的价格计算函数
def create_tax_calc(tax_rate):
def calc(price):
return price * (1 + tax_rate)
return calc
创建不同税率的计算函数
calc_tax_5 = create_tax_calc(0.05)
print(calc_tax_5(100))
calc_tax_9 = create_tax_calc(0.09)
print(calc_tax_9(100))
装饰器函数-基于闭包的函数增强
装饰器函数:基于闭包的函数增强
"""
先明确两个核心概念的关系:
闭包:装饰器的「底层实现基础」(满足 “嵌套函数 + 引用外层变量 + 返回内层函数”);
函数增强:装饰器的「核心目的」(在不修改原函数代码的前提下,给函数添加额外功能,如计时、日志、权限校验)。
简单说:装饰器是闭包的 “专属应用形态”—— 外层函数接收「被增强的原函数」作为参数,内层函数(闭包)包裹原函数执行逻辑并添加新功能,
最后返回内层函数,从而实现 “无侵入式增强”。
"""
import functools
def add_log(func):
def wrapper():
print(f"函数{func.__name__}开始执行了...")
func()
print(f"函数{func.__name__}执行完毕...")
return wrapper
def say_hello():
print("hello world")
用闭包增强原函数,手动绑定
enhance_say_hello = add_log(say_hello)
enhance_say_hello()
装饰器语法 @符号简化了书写流程。 语法糖、注解
@add_log
def say_hello1():
print("hello world1111")
say_hello1()
进阶应用
1. 处理带参数的原函数
原函数有参数时,内层函数需要用*args 和 **kwargs 来接收参数
def add_log1(func):
def wrapper(*args, **kwargs):
print(f"函数{func.__name__}开始执行了...参数:{args}{kwargs}")
result = func(*args, **kwargs)
print(f"函数{func.__name__}执行完毕...,返回值是:{result}")
return wrapper
@add_log1
def calc(a, b, op="+"):
if op == "+":
return a + b
elif op == "-":
return a - b
elif op == "*":
return a * b
elif op == "/":
return a / b
print(calc(1, 2, ))
print(calc(10, 2, op="-"))
带参数的装饰器
def add_log2(level="info"):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"{level}函数{func.__name__}开始执行了...参数:{args}{kwargs}")
result = func(*args, **kwargs)
print(f"{level}函数{func.__name__}执行完毕...,返回值是:{result}")
return result
return wrapper
return decorator
@add_log2(level="warning")
def my_print():
print("执行有风险的内容")
my_print()
保留原函数的元信息
def add_log3(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"函数{func.__name__}开始执行了...参数:{args}{kwargs}")
result = func(*args, **kwargs)
print(f"函数{func.__name__}执行完毕...,返回值是:{result}")
return wrapper
@add_log3
def say_hello2():
"""这是原函数的文档"""
print("hello world")
验证元信息
print(say_hello2.__name__)
加上@functools.wraps(func)后,输出say_hello2
装饰器实战案例-计时器统计函数耗时
装饰器实战案例:计时器统计函数耗时
import functools
import time
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
end_time = time.time()
print("函数耗时:%s" % (end_time - start_time))
return wrapper
@timer
def test():
time.sleep(1)
test()
装饰器实战案例-权限校验控制访问权限
装饰器实战案例:权限校验控制访问权限
根据用户在装饰器上传入的角色,来决定是否允许访问
def check_permission(role):
def decorator(func):
def wrapper(*args, **kwargs):
if role == 'admin':
print('管理员权限,允许访问')
return func(*args, **kwargs)
else:
print('无权限访问')
return wrapper
return decorator
@check_permission('admin')
def delete_data():
print('删除数据成功')
delete_data()
@check_permission('user')
def del_data():
print('user删除数据成功')
del_data()
yield关键字-生成器的核心
yield关键字:生成器的核心
"""
1. 通俗解释
yield 关键字是 Python 中「创建生成器的唯一核心手段」,它的作用可以理解为:
- 给函数 “打暂停键”:函数执行到 yield 时,会返回指定值,同时[暂停执行],保留当前所有变量的状态;
- 给函数 “续跑键”:再次调用生成器的next()或send()时,函数从暂停的位置继续执行,直到遇到下一个 yield(或函数结束)。
对比普通函数:
- 普通函数用return:执行到 return 直接结束,再次调用会重新执行;
- 生成器函数用yield:执行到 yield 暂停,再次调用 “续跑”,是「按需生成数据」的核心。
2. 核心结论
yield = 暂停执行 + 返回值 + 保留状态,没有 yield 就无法创建生成器,因此 yield 是生成器的 “灵魂”。
"""
生成器函数
def generator_func():
print("开始执行生成器")
yield 1
print("生成器继续执行")
yield 2
print("生成器结束")
gen = generator_func()
print(type(gen))
print(next(gen))
print(next(gen))
print(next(gen))
一般生成器对象,我们会使用for循环进行触发,这样就会自动的帮助我们处理StopIteration这个错误
for i in gen:
print("获取的值是",i)
"""
1.普通函数
- 执行逻辑:一次性执行完毕,返回结果
- 内存占用:一次性生成所有的数据,比较占用内存
- 返回值类型:直接返回结果,int、str、list、dict等其他对象
- 重复调用:重新执行整个函数
2.生成器函数
- 执行逻辑:分段执行,yield处就暂停执行,然后再用next调用后,再继续泡
- 按需要生成数据,几乎不怎么占用内存
- 返回值类型:返回生成器对象,generator
- 从上次暂停出继续跑
"""
生成器进阶:双向通信与简化嵌套
生成器进阶:双向通信与简化嵌套
我们可以通过send方法接收外部传入的值,实现双向通信
def chat_bot():
print("机器人:你好!")
while True:
message = yield "请输入你的问题,输入q退出"
if message == "q":
print("机器人:再见!")
break
print("Bot: ", message)
yield f"机器人:你问的问题是:{message},我不会回答"
双向通信
bot = chat_bot()
print(next(bot))
print(bot.send("你叫什么名字?"))
print(next(bot))
print(bot.send("q"))
yield from 可以简化嵌套生成器
声明一个子生成器
def sub_generator():
yield 1
yield 2
声明一个主生成器,用yield from 简化
def main_generator():
print("开始子生成器")
yield from sub_generator()
print("结束子生成器")
yield 3
调用主生成器
gen = main_generator()
for i in gen:
print(i)
8. 玩转Python高阶函数:Lambda与三大神器
Lambda匿名函数:一行搞定简单函数
Lambda匿名函数:一行搞定简单函数
"""
1. 通俗解释
Lambda 函数是 Python 中「极简版的函数」—— 没有函数名(匿名)、只用一行代码定义
专门处理逻辑简单的运算和判断,不用像普通函数那样写def 函数名():的完整结构,所以能 “一行搞定”。
2.语法结构
lambda 参数列表: 表达式
核心规则
1. 参数列表:和普通函数一样(支持位置参数、默认参数,不支持关键字参数/可变参数的复杂写法)
2. 表达式:只能有一个,表达式的结果就是函数的返回值(无需写return)
3. 无函数名:定义后要么立即调用,要么赋值给变量/作为参数传递
"""
普通函数,写一个计算两数之和
def add(a, b):
return a + b
lambda匿名函数,重写两数之和
add1 = lambda a, b: a + b
a = add(1,2)
b = add1(1,2)
print(a)
print(b)
使用lambda表达式,求平方
square = lambda x: x * x
print(square(5))
判断数字是不是为偶数,后边加上一个三元运算符
is_even = lambda x: "偶数" if x % 2 == 0 else "奇数"
print(is_even(5))
print(is_even(6))
print((lambda a,b: a+b)(1,2))
map函数:可迭代对象的批量映射计算
map函数:可迭代对象的批量映射计算
"""
1. 通俗解释
map 函数的核心作用是:把一个函数 “映射” 到可迭代对象(列表、元组、字符串等)的每一个元素上,批量执行计算,返回一个新的迭代器。
- “映射”:把函数逻辑应用到每个元素上(比如给每个数平方、给每个字符串转大写);
- “批量计算”:无需手动写 for 循环,自动遍历可迭代对象并执行函数;
- “可迭代对象”:支持列表、元组、字符串、生成器等所有可迭代类型。
2. 基础语法
语法结构
map(函数, 可迭代对象1[, 可迭代对象2, ...])
核心规则
1. 函数:可以是普通函数、Lambda匿名函数(最常用),接收的参数个数需和可迭代对象数量一致;
2. 可迭代对象:可以传1个或多个(多个时,map会按位置取每个可迭代对象的元素传给函数);
3. 返回值:map对象(迭代器),需转成列表/元组才能直观看到结果,也就是需要用list()函数包裹起来,转换一下。
"""
给列表当中每一个数字计算平方
nums = [1,2,3,4,5]
result = []
手动for循环实现一下
for num in nums:
result.append(num**2)
print(result)
map函数实现
def square(x):
return x**2
map_obj = map(square, nums)
print(map_obj)
print(list(map_obj))
结合lambda表达式实现
print(list(map(lambda x: x**2, nums)))
列表当中的字符串元素转成大写字母
words = ['hello', 'world', 'python', 'programming']
upper_words = list(map(str.upper, words))
print(upper_words)
列表当中的字符串类型的数字转成整数
numbers = ['1', '2', '3', '4', '5']
integers = list(map(int, numbers))
print(integers)
map函数传入多个可迭代的对象
nums1 = [1,2,3,4,5]
nums2 = [6,7,8,9,10]
result = list(map(lambda x, y: x+y, nums1, nums2))
print(result)
nums1 = [1,2,3,4,5]
nums2 = [6,7,8,9]
result = list(map(lambda x, y: x+y, nums1, nums2))
print(result)
reduce函数:可迭代对象的累积堆叠运算
reduce函数:可迭代对象的累积堆叠运算
"""
1. 通俗解释
reduce 函数的核心作用是:对可迭代对象的元素进行 “累积式” 运算 —— 先取前两个元素执行函数,
再将结果和第三个元素执行函数,以此类推,直到所有元素处理完毕,最终返回一个单一值。
- “累积”:运算结果会作为下一次运算的输入之一,像 “滚雪球” 一样堆叠;
- “堆叠”:每次运算都是 “上一轮结果 + 下一个元素” 的组合运算;
- “单一值”:无论可迭代对象有多少元素,最终只返回一个结果(区别于 map 的批量映射)。
2. 基础语法
注意:Python 3中reduce已从内置函数移到functools模块,需先导入
from functools import reduce
语法结构
reduce(函数, 可迭代对象[, 初始值])
核心规则
1. 函数:必须接收2个参数,用于处理“上一轮结果”和“当前元素”;
2. 可迭代对象:列表、元组、字符串等(不能为空,除非指定初始值);
3. 初始值(可选):若指定,先将初始值和第一个元素执行函数;若不指定,从前两个元素开始;
4. 返回值:单一的累积运算结果。
"""
from functools import reduce
计算列表中所有数字的和
nums = [1, 2, 3, 4, 5]
手动for循环去实现
total = 0
for num in nums:
total += num
print(total)
reduce函数实现
def add(x, y):
return x + y
total = reduce(add, nums)
print(total)
结合lambda表达式进行实现
total = reduce(lambda x, y: x + y, nums)
print(total)
累计求乘积
nums = [1, 2, 3, 4, 5]
total = reduce(lambda x, y: x * y, nums)
print(total)
累积求最大值
max_num = reduce(lambda x, y: x if x > y else y, nums)
print(max_num)
filter函数:可迭代对象的条件过滤
filter函数:可迭代对象的条件过滤
"""
1. 通俗解释
filter 函数就像一个 “数据筛子”—— 你定义好 “筛选规则”(判断函数)
它会自动遍历可迭代对象(列表 / 元组 / 字符串等),只留下符合规则的元素,剔除不符合的,最终返回一个过滤后的迭代器。
- 筛选规则:由一个返回布尔值(True/False)的函数定义(True 留、False 弃);
- 核心优势:无需手动写 for 循环,用函数式风格实现 “一行过滤”。
2. 基础语法
filter(判断函数, 可迭代对象)
关键规则
1. 判断函数:接收1个参数,必须返回布尔值(或可被视为布尔值的内容,如非0数字、非空字符串);
2. 可迭代对象:列表、元组、字符串、生成器等所有可迭代类型;
3. 返回值:filter对象(迭代器),需转列表/元组才能直观查看结果(Python 3特性);
4. 特殊情况:判断函数传None时,默认过滤“假值”(0、""、[]、False等)。
"""
筛选列表中的偶数
list_num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
手动for循环实现
result = []
for num in list_num:
if num % 2 == 0:
result.append(num)
print(result)
使用filter函数实现
result = list(filter(lambda x: x % 2 == 0, list_num))
print(result)
筛选列表中的正数
list_num = [1, -2, 3, -4, 5, -6, 7, -8, 9, -10]
result = list(filter(lambda x: x > 0, list_num))
print(result)
筛选列表、字典中符合的元素
users = [
{
"name": "张三",
"age": 18,
"gender": "男"
},
{
"name": "李四",
"age": 19,
"gender": "女"
},
{
"name": "王五",
"age": 20,
"gender": "男"
}
]
筛选出年龄大于18岁的数据
result = list(filter(lambda x: x["age"] > 18, users))
print(result)
9. 面向对象编程:Python核心范式
初识面向对象:什么是Python的面向对象
初识面向对象:什么是Python的面向对象
面向过程
指的是我们要实现某个需求,只要按照步骤,以此书写函数去实现即可
使用零散的函数来处理数据
def print_student(name,age,score):
print(f"学生信息:姓名:{name}, 年龄:{age}, 成绩:{score}")
def update_score(score, add):
return score + add
处理学生1的信息
stu1_name = "小明"
stu1_age = 18
stu1_score = 90
print_student(stu1_name,stu1_age,stu1_score)
处理学生2的信息
stu2_name = "小王"
stu2_age = 19
stu2_score = 80
print_student(stu2_name,stu2_age,stu2_score)
总结:面向过程书写代码的问题:学生的属性(姓名、年龄、分数)和学生的行为(更新分数)都是分离的,新增学生时
我们需要重复定义变量,代码冗余,维护成本较高
面向对象的编程思想
class Student:
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
def update_score(self, add):
self.score = self.score + add
def print_student(self):
print(f"学生信息:姓名:{self.name}, 年龄:{self.age}, 成绩:{self.score}")
创建学生1对象 实例化对象的过程
stu1 = Student("小明", 18, 90)
stu1.print_student()
stu1.update_score(10)
创建学生2对象
stu2 = Student("小王", 19, 80)
stu2.print_student()
stu2.update_score(10)
面向对象编程的优势:学生的属性和行为是被封装在一起的。
在新增学生时只需要创建对象,代码简洁、易维护、可复用
面向对象的三大核心特征:封装、继承、多态
封装的妙用:给对象 “打包” 数据和功能
封装的妙用:给对象 “打包” 数据和功能
"""
1. 通俗比喻
封装就像你日常用的「快递盒」:
- **打包内容**:把商品(数据 / 属性)和使用说明书(功能 / 方法)放进盒子里;
- **对外暴露**:只留一个快递单(必要的接口),别人不用知道盒子里的商品怎么生产、说明书怎么写,只需知道怎么用;
- **内部隐藏**:盒子里的细节(比如商品的零件、说明书的排版)对外不可见,避免被随意改动。
对应到 Python 面向对象中:
- **“打包”**:把对象的「属性(数据)」和「方法(功能)」绑定在一起,成为一个独立的 “对象”;
- **“隐藏”**:把不需要对外暴露的内部细节(如敏感属性、核心逻辑)私有化,只开放安全的访问接口;
- **“规范”**:对外提供统一的接口,使用者无需关心内部实现,只需调用接口即可。
2. 核心价值(封装的 “妙用” 核心)
数据安全:避免外部随意修改对象的敏感数据(比如把学生分数改成负数)
代码复用:封装好的对象可以在不同场景重复使用(比如一个 Student 类可以创建无数学生对象)
降低耦合:外部只依赖接口,内部逻辑修改后(如分数计算规则),外部代码无需改动
提高可读性:代码结构清晰,对象的功能都集中在类内部,不用到处找零散的函数 / 变量
"""
name = "小明"
age = 18
def print_info():
print(f"学生信息:姓名:{name}, 年龄:{age}")
封装:把属性和方法打包到类中
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def print_info(self):
print(f"学生信息:姓名:{self.name}, 年龄:{self.age}")
创建对象,可以直接使用封装好的属性和方法
p = Person("小明", 18)
p.print_info()
封装进阶:私有成员与属性装饰器
封装进阶:私有成员与属性装饰器
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def print_info(self):
print(f"学生信息:姓名:{self.name}, 年龄:{self.age}")
创建对象,可以直接使用封装好的属性和方法
p = Person("小明", 18)
p.print_info()
print(p.name)
私有成员:添加 __ 前缀. 私有成员不能被外部访问,只能通过类内部的公开接口操作,保证数据的安全
class BankAccount:
"""银行账户类:封装账户信息,保证余额安全"""
def __init__(self, account_num, balance=0):
self.account_num = account_num
self.__balance = balance
def get_balance(self):
return f"账户{self.account_num}的余额为:{self.__balance}"
def deposit(self, amount):
if amount > 0:
self.__balance += amount
return f"账户{self.account_num}存款成功,余额为:{self.__balance}"
else:
return "存款金额必须大于0"
def withdraw(self, amount):
if amount > 0 and amount <= self.__balance:
self.__balance -= amount
return f"账户{self.account_num}取款成功,余额为:{self.__balance}"
else:
return "取款金额必须大于0且小于余额"
实例化一个账户对象
account = BankAccount("1234567890",1000)
print(account.account_num)
print(account.get_balance())
存款500元
print(account.deposit(500))
取款2000元
print(account.withdraw(200))
属性装饰器:添加 @property
class Student:
"""学生类:封装学生的信息,保证数据安全"""
def __init__(self, name, score):
self.name = name
self.__score = score
@property
def score(self):
return self.__score
@score.setter
def score(self, value):
if 0 <= value <= 100:
self.__score = value
else:
raise ValueError("分数必须在0~100之间")
使用装饰器后的封装
s = Student("小明", 90)
访问分数,属性score被 @property 修饰,所以 score 属性被访问时,score() 方法被调用
print(s.score)
修改分数:像普通赋值一样即可,使用调用的是score.setter方法
s.score = 1
print(s.score)
私有方法:添加 __ 前缀
class Order:
"""订单类:封装订单信息,保证数据安全"""
def __init__(self, goods, price):
self.goods = goods
self.price = price
self.__total = 0
def __calculate_total_price(self):
self.__total = self.price + 10
def generate_order(self):
self.__calculate_total_price()
return f"订单生成成功,商品:{self.goods},总价:{self.__total}"
order = Order("电脑", 1000)
print(order.generate_order())
order.__calculate_total_price()
类的方法:实例方法、类方法与静态方法
类的方法:实例方法、类方法与静态方法
"""
类的三种方法,核心差异在于「绑定的对象不同」和「能访问的属性不同」,用通俗的比喻先建立认知:
表格
方法类型 通俗比喻 绑定对象 第一个参数 能访问的属性
实例方法 「对象的专属功能」 实例(对象) self 实例属性、类属性
类方法 「类的通用功能」 类 cls 类属性(无法直接访问实例属性)
静态方法 「类的工具函数」 无(独立存在) 无 无(需手动传参才能访问)
简单来说:
实例方法:给「具体对象」用的,比如学生对象的 “修改分数”;
类方法:给「整个类」用的,比如学生类的 “统计总人数”;
静态方法:和类 / 对象无关的工具函数,只是 “挂靠” 在类里,比如 “判断分数是否合法”。
"""
"""
实例方法(最常用)
语法:直接定义在类中,第一个参数必须是self(代表当前实例);
调用:通过「实例对象」调用(类也能调用,但需手动传 self,不推荐);
核心:操作实例的属性,是类中最基础的方法。
"""
class Student:
total_students = 0
def __init__(self, name, score):
self.name = name
self.score = score
Student.total_students += 1
def print_info(self):
print(f"学生信息:姓名:{self.name}, 分数:{self.score}")
def modify_score(self, score):
if 0 <= score <= 100:
self.score = score
else:
print("分数不合法")
s1 = Student("小明", 90)
s1.print_info()
s1.modify_score(100)
s1.print_info()
s2 = Student("小王", 80)
s2.print_info()
"""
类方法
语法:用@classmethod装饰器,第一个参数必须是cls(代表当前类);
调用:可通过「类」或「实例」调用(推荐用类调用);
核心:操作类属性,不依赖实例,适合做 “类级别的通用操作”。
"""
class Student:
total_students = 0
def __init__(self, name, score):
self.name = name
self.score = score
Student.total_students += 1
@classmethod
def get_total(cls):
return f"当前学生总人数:{cls.total_students}"
@classmethod
def create_student(cls, name, score):
return cls(name, score)
调用类方法:直接用类的名字进行调用
print(Student.get_total())
用类方法创建实例:工厂模式
s1 = Student.create_student("张三", 91)
print(s1.name,s1.score)
print(Student.get_total())
print(s1.get_total()) 当一个方法为类方法的时候,不推荐直接使用实例对象调用类方法
"""
静态方法
语法:用@staticmethod装饰器,无默认参数(self/cls 都不需要);
调用:可通过「类」或「实例」调用;
核心:和类 / 实例无关的工具函数,只是逻辑上挂靠在类里,避免全局函数污染。
"""
class Student:
def __init__(self, name, score):
self.name = name
if Student.check_score(score):
self.score = score
print(f"学生信息:姓名:{self.name}, 分数:{self.score}")
else:
print("分数不合法")
@staticmethod
def check_score(score):
if 0 <= score <= 100:
return True
else:
return False
调用静态方法:用类的名字进行调用
print(Student.check_score(100))
print(Student.check_score(101))
创建实例的时候,用静态方法做校验
s1 = Student("小王", 80)
s2 = Student("小王", 101)
"""
什么场景使用什么方法?
1. 用实例方法的场景(90% 的情况)
需要访问 / 修改实例属性(如self.name、self.score);
功能是「某个具体对象的专属行为」(如学生对象改分数、打印自己的信息)。
2. 用类方法的场景
需要访问 / 修改类属性(如total_students);
做「类级别的通用操作」(如统计总人数、工厂方法创建实例);
方法逻辑只依赖类,不依赖具体实例。
3. 用静态方法的场景
方法逻辑和「类、实例」都无关,只是一个工具函数;
想把工具函数 “归类” 到类中,避免定义全局函数(比如分数校验、日期格式化);
不需要访问任何类属性 / 实例属性。
"""
类的继承:让子类继承父类的能力
类的继承:让子类 “继承” 父类的能力
"""
继承就像现实中的「亲子关系」:
父类(基类 / 超类):比如 “人”,拥有通用的属性(姓名、年龄)和行为(吃饭、睡觉);
子类(派生类):比如 “学生”“老师”,继承了 “人” 的所有属性和行为,
同时又有自己的专属属性(学生的分数、老师的工号)和行为(学生上课、老师讲课)。
对应到 Python 中:
继承的核心价值是代码复用:子类无需重复编写父类已有的属性和方法,直接 “继承” 使用;
继承的延伸价值是扩展能力:子类可以在父类基础上新增属性 / 方法,或修改父类的方法(重写),实现 “通用 + 专属” 的逻辑。
"""
没有继承时
class Student:
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
def eat(self):
print(f"{self.name} 正在吃饭")
def study(self):
print(f"学生 {self.name} 正在学习")
class Teacher:
def __init__(self, name, age, work_number):
self.name = name
self.age = age
self.work_number = work_number
def eat(self):
print(f"{self.name} 正在吃饭")
def teach(self):
print(f"老师 {self.name} 正在讲课")
有继承时
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print(f"{self.name} 正在吃饭")
class Student(Person):
def study(self):
print(f"学生 {self.name} 正在学习")
class Teacher(Person):
def teach(self):
print(f"老师 {self.name} 正在讲课")
stu = Student("小王", 18)
stu.study()
stu.eat()
tea = Teacher("老李", 38)
tea.teach()
tea.eat()
子类对父类能力的扩充
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print(f"{self.name} 正在吃饭")
class Student(Person):
def __init__(self,name,age,score):
super().__init__(name,age)
self.score = score
def eat(self):
super().eat()
print(f"学生 {self.name},吃完饭之后还需要学习")
stu2 = Student("小王", 18, 90)
print(stu2.name, stu2.age, stu2.score)
stu2.eat()
class Teacher(Person):
def __init__(self,name,age,work_number):
super().__init__(name,age)
self.work_number = work_number
def eat(self):
print(f"老师 {self.name},吃完饭之后还需要讲课")
tea2 = Teacher("老王", 38, "123456")
print(tea2.name, tea2.age, tea2.work_number)
tea2.eat()
多继承
class Father:
def speak_english(self):
print("会说英语")
def eat(self):
print("父亲会吃")
def __know(self):
print("父亲会知识")
def _protect(self):
print("我是一个被保护的方法")
class Mother:
def play(self):
print("会玩")
def eat(self):
print("母亲会吃")
class Child(Mother,Father ):
pass
child = Child()
child.speak_english()
child.play()
child.eat()
child.__know()
child._protect()
father = Father()
father._protect()
类的多态:同一个行为的不同表现形式
类的多态:同一个行为的不同表现形式
"""
多态就像现实中的「“打招呼” 这个行为」:
- 同一个行为:打招呼;
- 不同表现形式:
- 中国人打招呼:说 “你好”;
- 美国人打招呼:说 “Hello”;
- 等等
对应到 Python 面向对象中:
- **同一个行为**:类的同名方法(比如speak()、run());
- **不同表现形式**:不同子类对这个同名方法的实现逻辑不同;
- **核心价值**:调用者无需关心对象的具体类型,只需调用统一的方法,对象会自动执行对应的逻辑(“一个接口,多种实现”)。
"""
没有多态的时候
class Cat:
def miao(self):
print("喵喵喵")
class Dog:
def wang(self):
print("汪汪汪")
class Bird:
def jiji(self):
print("叽叽叽")
def make_sound(animal):
if isinstance(animal, Cat):
animal.miao()
elif isinstance(animal, Dog):
animal.wang()
elif isinstance(animal, Bird):
animal.jiji()
else:
print("不支持的动物")
使用
make_sound(Cat())
make_sound(Dog())
make_sound(Bird())
有多态的时候
class Animal:
def speak(self):
raise NotImplementedError("子类必须实现这个方法")
class Dog(Animal):
def speak(self):
print("汪汪汪")
class Cat(Animal):
def speak(self):
print("喵喵喵")
class Bird(Animal):
def speak(self):
print("叽叽叽")
def make_sound(animal):
animal.speak()
make_sound(Cat())
make_sound(Dog())
make_sound(Bird())
进阶小技巧:用Type语句定义泛型别名
进阶小技巧:用 Type 语句定义泛型别名
def func(a: int,b: str) -> str:
pass
def func1(a: list[dict[str,str|int]]) -> list[dict[str,str|int]]:
pass
"""
为什么需要 “泛型别名”?
1. 核心痛点(无泛型别名的问题)
在 Python 中,当我们需要频繁使用**复杂的泛型类型**(如list[dict[str, int]]、tuple[str, int, bool])时,会出现两个问题:
- 代码冗余:同一复杂类型写多次,重复且易出错;
- 可读性差:复杂类型直接写在代码里,一眼看不出含义(比如list[dict[str, int]]到底代表 “用户列表” 还是 “商品列表”?);
- 维护成本高:如果需要修改类型(如把list改成tuple),要改所有用到的地方。
2. 泛型别名的核心价值
用Type语句(Python3.10以前:typing.TypeAlias或 Python 3.10 + 的type关键字)
给复杂泛型类型起一个**有语义的别名**,解决上述痛点:
- 简化代码:用简短别名替代复杂类型;
- 提升可读性:别名带语义(如UserList代替list[dict[str, int]]);
- 易维护:修改类型只需改别名定义,无需改所有使用处。
"""
定义一个泛型
type UserList = list[dict[str, str|int]]
type ScoreList = list[int]
定义泛型别名
type UserInfo = dict[str, str|int]
type UserList = list[UserInfo]
没有泛型别名的时候,写起来代码非常的复杂
def get_user_info(user_list: list[dict[str, str|int]]) -> list[dict[str, str|int]]:
有了泛型别名的嗯时候,代码就变得非常的简洁,语义也变得清晰了
def get_user_info(users: UserList) -> UserList:
if not users:
return (False,"用户列表为空")
return (True,f"处理了{len(users)}个用户")
users: UserList = [
{"name": "小明", "age": 18},
{"name": "小王", "age": 19},
{"name": "小张", "age": 20},
]
print(get_user_info(users))
联合泛型别名
type numeric = int|float
type data = list[numeric] | tuple[numeric]
def get_sum(data: data) -> numeric:
return sum(data)
print(get_sum([1,2,3,4,5]))
print(get_sum((1,2.2,3,4,5.34)))
异常类:Python 自带的错误处理模板
异常类:Python 自带的错误处理模板
""""""
"""
异常类的核心本质(为什么叫 “错误处理模板”)
1. 通俗比喻
Python 的内置异常类,就像生活中「标准化的错误报告单」:
- 模板(异常类):比如 “账单金额错误” 模板、“地址不存在” 模板,每个模板都定义了错误的类型、原因;
- 填写模板(抛出异常):当程序出错时,Python 会根据错误类型,自动 “填写” 对应模板(创建异常类实例),包含错误信息、调用栈等;
- 处理模板(捕获异常):开发者可以针对不同模板(异常类),
编写对应的处理逻辑(比如对 “值错误” 提示用户输入合法值,对 “文件不存在” 提示检查路径)。
2. 核心定义
- 异常类:Python 内置了一系列预定义的类(如ValueError、TypeError),
每个类对应一种特定类型的错误,是处理错误的 “标准化模板”;
- 核心价值
- 标准化:统一错误类型,避免开发者自定义混乱的错误提示;
- 易处理:可精准捕获某类错误,针对性处理;
- 可扩展:支持继承内置异常类,自定义业务专属异常。
"""
没有异常类时
def divide(a, b):
if b == 0:
print("除数不能为0")
else:
print(a / b)
result = divide(10, 0)
print(result)
有异常类时
def divide(a, b):
print(a / b)
异常的捕捉
try:
divide(10, 1)
except ZeroDivisionError as e:
print(f"除数不能为0的错误:{e}")
finally:
print("这里的代码是无论是否发生错误都会被执行,一般被用来释放资源")
"""
Python 内置异常类体系(核心模板分类)
Python 的内置异常类有清晰的继承层级,核心根类是BaseException,日常开发中常用的是Exception(所有非系统退出类异常的父类)。
1. 核心异常类层级(简化版)
BaseException
├── SystemExit(程序退出,不捕获)
├── KeyboardInterrupt(用户中断,如Ctrl+C)
└── Exception(日常处理的核心父类)
├── ArithmeticError(算术错误)
│ ├── ZeroDivisionError(除数为0)
│ └── OverflowError(数值溢出)
├── LookupError(查找错误)
│ ├── IndexError(索引越界)
│ └── KeyError(字典键不存在)
├── TypeError(类型错误)
├── ValueError(值错误)
├── FileNotFoundError(文件不存在)
├── IOError(IO操作错误)
└── AttributeError(属性不存在)
2. 常用内置异常类
| 异常类 | 适用场景 | 示例 |
| :-----------------: | :-----------------------------: | :------------------------------: |
| TypeError | 操作 / 函数应用于错误类型的对象 | 1 + "2"(数字 + 字符串) |
| ValueError | 数据类型正确,但值不合法 | int("abc")(字符串无法转数字) |
| ZeroDivisionError | 除法 / 取模运算中除数为 0 | 10 / 0 |
| IndexError | 序列(列表 / 元组)索引超出范围 | [1,2,3][5] |
| KeyError | 字典中查找不存在的键 | {"name":"张三"}["age"] |
| FileNotFoundError | 打开不存在的文件(mode='r') | open("none.txt", "r") |
| AttributeError | 访问对象不存在的属性 / 方法 | str.abc()(字符串无 abc 方法) |
| ImportError | 导入模块 / 对象失败 | import nonemodule |
"""
def process_data(data):
"""处理数据"""
try:
num = int(data)
result = 100 / num
return result
except TypeError as e:
print(f"数据类型错误:{e}")
except ValueError as e:
print(f"数据值错误:{e}")
except ZeroDivisionError as e:
print(f"除数不能为0的错误:{e}")
process_data("abc")
process_data("0")
process_data([1,2,3])
主动抛出异常
def check_data(age):
if not isinstance(age , int):
raise TypeError("年龄必须是整数")
if age < 0 or age > 120:
raise ValueError("年龄必须在0-120之间")
print("数据校验通过,年龄合法")
try:
check_data(1.8)
except (TypeError, ValueError) as e:
print(f"数据校验失败:{e}")
自定义异常:打造专属的错误类型
"""自定义异常:打造专属的错误类型"""
class BusinessError(Exception):
"""业务逻辑异常"""
def __init__(self,code, msg):
self.code = code
self.msg = msg
super().__init__(f"[{self.code}]:{self.msg}")
class UserNotFoundError(BusinessError):
"""用户不存在异常"""
def __init__(self, user_id):
super().__init__(1001, f"用户{user_id}不存在")
class PermissionDeniedError(BusinessError):
"""权限不足异常"""
def __init__(self, user_id, action):
super().__init__(1002, f"用户{user_id}无{action}权限")
def get_user(user_id):
users = {"1001": "张三", "1002": "李四"}
if user_id not in users:
raise UserNotFoundError(user_id)
return users[user_id]
def check_permission(user_id, action):
permissions = {"1001": ["查看", "编辑"], "1002": ["查看"]}
if user_id not in permissions:
raise UserNotFoundError(user_id)
if action not in permissions[user_id]:
raise PermissionDeniedError(user_id, action)
try:
check_permission("1002", "编辑")
except UserNotFoundError as e:
print(f"业务错误:{e} -> 错误码:{e.code}")
except PermissionDeniedError as e:
print(f"业务错误:{e} -> 错误码:{e.code}")
except BusinessError as e:
print(f"通用业务错误:{e}")
10. 高性能编程:Python并发与异步编程
多进程编程:让程序 “同时” 跑在多个CPU上
多进程编程:让程序 “同时” 跑在多个CPU上
import multiprocessing
import time
def task(name, duration):
print(f"进程{name}开始执行,预计耗时{duration}")
time.sleep(duration)
print(f"进程{name}执行完毕")
if __name__ == '__main__':
start = time.time()
p1 = multiprocessing.Process(target=task, args=("进程1", 3))
p2 = multiprocessing.Process(target=task, args=("进程2", 3))
p1.start()
p2.start()
p1.join()
p2.join()
end = time.time()
print(f"总耗时{end-start}")
使用进程池的方式来实现多进程的并发
def square(n):
time.sleep(1)
return n * n
if __name__ == '__main__':
start = time.time()
pool = multiprocessing.Pool(processes=4)
result = pool.map(square, range(10))
pool.close()
pool.join()
end = time.time()
print(result)
print(f"总耗时{end-start}")
多线程实战:优化文件IO任务
多线程实战:优化文件IO任务
import os
import threading
import time
from concurrent.futures import ThreadPoolExecutor
生成测试文件
def create_test_files():
for i in range(5):
with open(f"test{i}.txt", "w", encoding="utf-8") as f:
f.write(f"{i}--这是测试文件的内容" * 1000)
def read_file(file_path):
print(f"开始读取文件:{file_path}")
with open(file_path, "r", encoding="utf-8") as f:
content = f.readlines()
print(f"{file_path} 文件的内容是:{content}")
time.sleep(0.5)
print(f"文件{file_path}读取完毕,文件行数是{len(content)}行")
return len(content)
if __name__ == '__main__':
file_paths = [f"test{i}.txt" for i in range(5)]
start = time.time()
for file in file_paths:
read_file(file)
print(f"单线程的总耗时{time.time()-start}秒")
start = time.time()
threads = []
for file_path in file_paths:
t = threading.Thread(target=read_file, args=(file_path,))
threads.append(t)
t.start()
for t in threads:
t.join()
print(f"多线程的总耗时{time.time()-start}秒")
start = time.time()
with ThreadPoolExecutor(max_workers=5) as executor:
results = executor.map(read_file, file_paths)
print(f"线程池-多线程的总耗时{time.time() - start}秒")
协程异步编程:更轻量的 “迷你线程”
协程异步编程:更轻量的 “迷你线程”
如何定义协程
import asyncio
import time
定义一个函数,这个函数是协程函数,需要借助关键字async
async def hello(name):
print(f"协程{name}开始执行")
await asyncio.sleep(1)
print(f"协程{name}执行完毕")
async def main():
task1 = asyncio.create_task(hello("A"))
task2 = asyncio.create_task(hello("B"))
await task1
await task2
if __name__ == "__main__":
start_time = time.time()
asyncio.run(main())
end_time = time.time()
print(f"总耗时{end_time-start_time}")
"""
async def : 定义协程函数,调用后不会立即执行,而是返回一个协程对象
asyncio.create_task: 将协程对象封装成为任务,加入事件循环等待执行
await: 后边必须跟可等待的对象,比如协程, 触发io等待时,主动让权,让其他协程执行
asyncio.run: 启动事件循环,运行主协程
"""
协程对比线程,模拟高并发场景
import threading
from concurrent.futures import ThreadPoolExecutor
async def async_task(i):
await asyncio.sleep(i)
return i
async def async_main():
tasks = [asyncio.create_task(async_task(i)) for i in range(10)]
results = await asyncio.gather(*tasks)
return results
def thread_task(i):
time.sleep(i)
return i
def thread_main():
with ThreadPoolExecutor(max_workers=10) as executor:
executor.map(thread_task, range(10))
if __name__ == "__main__":
start_time = time.time()
asyncio.run(async_main())
end_time = time.time()
print(f"协程总耗时{end_time-start_time}")
thread_main()
end_time = time.time()
print(f"线程总耗时{end_time-start_time}")
使用协程优化文件io任务
import aiofiles
创建测试文件
def create_test_files():
for i in range(10):
with open(f"test{i}.txt", "w", encoding="utf-8") as f:
f.write(f"{i}--这是测试文件的内容" * 1000)
异步读取文件
async def read_file_async(file_path):
print(f"开始读取文件:{file_path}")
async with aiofiles.open(file_path, "r", encoding="utf-8") as f:
content = await f.readlines()
print(f"{file_path} 文件的内容是:{content}")
await asyncio.sleep(0.1)
print(f"异步文件{file_path}读取完毕,文件行数是{len(content)}行")
return len(content)
批量异步读取文件
async def batch_read_files_async():
file_paths = [f"test{i}.txt" for i in range(10)]
tasks = [asyncio.create_task(read_file_async(path)) for path in file_paths]
results = await asyncio.gather(*tasks)
if __name__ == "__main__":
create_test_files()
start = time.time()
asyncio.run(batch_read_files_async())
end = time.time()
print(f"异步总耗时{end-start}秒")