当前位置: 首页 > news >正文

python3-01-base

python3-01-base

01、注释

全文总结

核心维度 具体内容
注释定义 对代码的解释说明,仅提升可读性,不会被Python解释器执行
注释分类 1. 单行注释:以#开头,仅注释单行内容;2. 多行注释:以''' '''""" """包裹,可注释多行内容
核心注意点 多行注释嵌套时,外层和内层需用不同符号(如外层'''、内层""",反之亦然),否则会导致注释失效
排错性作用 可临时注释部分代码,逐步测试未注释代码,定位报错原因(注释的代码不会执行,仅保留代码结构)

完整详细讲解(带新人步骤)

步骤1:理解注释的本质

注释是给人看的解释,Python运行代码时会完全忽略注释内容。

  • 核心价值:自己/同事后续看代码时,能快速理解代码意图;
  • 关键特征:注释内容不会出现在代码执行结果中。

步骤2:学习单行注释(最常用)

定义

#开头,#右侧的所有内容均为注释(仅作用于当前行)。

代码示例+执行过程

# 这是单行注释,解释下面的代码:打印"你好 python"
print("你好 python")  # 这是行尾的单行注释,解释本行代码

执行过程

  1. Python解释器读取第一行,识别到#,直接跳过该行;
  2. 读取第二行,先跳过#后的注释内容,执行print("你好 python"),控制台输出:你好 python

步骤3:学习多行注释

定义

用于注释多行内容,有两种写法:

  • 单引号版:''' 注释内容 '''
  • 双引号版:""" 注释内容 """

代码示例+执行过程

# 示例1:三个单引号的多行注释
'''
这是多行注释的第一行
这是多行注释的第二行
下面的代码会被注释,不会执行:
print("家穷人丑,一米49")
print("小学文化,农村户口")
'''# 示例2:三个双引号的多行注释
"""
这是双引号版多行注释
下面的代码同样被注释,不会执行:
print("破屋三间,药不离口")
"""# 执行核心代码
print("你好 python")

执行过程

  1. 解释器读取''' '''包裹的内容,判定为多行注释,直接跳过;
  2. 解释器读取""" """包裹的内容,同样判定为多行注释,直接跳过;
  3. 执行最后一行print("你好 python"),控制台输出:你好 python
  4. 所有被多行注释包裹的print语句都未执行,无对应输出。

步骤4:掌握注释的核心注意点(避坑)

核心规则:多行注释不能嵌套同类型符号,否则注释会提前结束,导致部分代码暴露(非注释状态)。

反例(错误写法)+执行过程

'''
print("家穷人丑,一米49")
'''print("小学文化,农村户口")'''  # 内层用了和外层相同的''',导致注释失效
print("破屋三间,药不离口")
'''

执行过程

  1. 解释器读取第一个''',开始多行注释;
  2. 读取到第二个'''时,判定注释结束,后续的print("小学文化,农村户口")变成可执行代码;
  3. 执行print("小学文化,农村户口"),控制台输出该内容;
  4. 后续的'''被识别为语法错误,代码直接报错。

正例(正确写法)+执行过程

'''
print("家穷人丑,一米49")
print("小学文化,农村户口")
"""  # 内层用双引号注释,和外层单引号不冲突
print("破屋三间,药不离口")
"""
print("没有老婆,网上征友")
'''
print("最终执行的代码")

执行过程

  1. 解释器读取外层''',判定为多行注释开始;
  2. 内层""" """被包含在''' '''内,整体仍为注释,无语法错误;
  3. 所有被''' '''包裹的代码均被跳过,仅执行最后一行print("最终执行的代码")
  4. 控制台输出:最终执行的代码

步骤5:利用注释做排错(核心实用技巧)

原理

临时注释部分代码,逐步放开注释测试,定位“哪一行代码导致报错”。

代码示例+排错过程

# 第一步:注释大部分代码,只保留核心行测试
"""
print("家穷人丑,一米49")
print("小学文化,农村户口")
"""
print("破屋三间,药不离口")  # 先执行这一行,测试是否报错
# 执行结果:控制台输出"破屋三间,药不离口",无报错# 第二步:放开一行注释,继续测试
"""
print("家穷人丑,一米49")
print("小学文化,农村户口")
"""
print("破屋三间,药不离口")
print("没有老婆,网上征友")  # 新增执行该行
# 执行结果:输出两行内容,无报错# 第三步:放开所有注释,最终测试
print("家穷人丑,一米49")
print("小学文化,农村户口")
print("破屋三间,药不离口")
print("没有老婆,网上征友")
print("革命道路,并肩携手")
# 执行结果:所有行正常输出,无报错

排错逻辑:如果某一步放开注释后报错,说明“刚放开的这行代码有问题”,可针对性修改。

应用场景及案例(带详细执行过程)

应用场景1:代码功能说明(提升可读性)

场景描述

开发时给核心业务代码加注释,说明代码用途、入参/出参、特殊逻辑。

案例代码+执行过程

# 功能:计算两个数的和(新手入门示例)
# 入参:num1=10,num2=20;出参:两数之和
num1 = 10  # 定义第一个加数
num2 = 20  # 定义第二个加数
sum_result = num1 + num2  # 计算两数之和
print(f"10+20的结果是:{sum_result}")  # 打印结果

执行过程

  1. 所有#开头的注释被跳过;
  2. 依次执行变量定义、求和、打印操作;
  3. 控制台输出:10+20的结果是:30
  4. 新人/后续维护者可通过注释快速理解“这段代码是做加法的”,无需逐行分析代码逻辑。

应用场景2:临时屏蔽代码(保留代码,不执行)

场景描述

开发中某段代码暂时不用,但不想删除(后续可能复用),用注释临时屏蔽。

案例代码+执行过程

# 业务场景:用户登录功能,暂时屏蔽“验证码校验”逻辑
print("请输入用户名:")
print("请输入密码:")
"""
# 临时注释验证码逻辑,后续版本再启用
print("请输入验证码:")
verify_code = input()  # 获取用户输入的验证码
if verify_code != "123456":print("验证码错误,登录失败")
"""
print("登录成功(暂不校验验证码)")

执行过程

  1. 注释内的“验证码校验”代码被完全跳过;
  2. 仅执行用户名、密码提示和“登录成功”打印;
  3. 控制台输出:
请输入用户名:
请输入密码:
登录成功(暂不校验验证码)
  1. 后续如需恢复验证码逻辑,只需删除""" """即可,无需重新写代码。

应用场景3:调试排错(定位报错代码)

场景描述

代码运行报错时,用注释逐步屏蔽代码,找到报错源头。

案例代码+排错过程

# 初始报错代码:TypeError(字符串和数字无法相加)
print("计算结果:" + 100)  # 报错行# 排错步骤1:注释报错行,测试基础代码
"""
print("计算结果:" + 100)
"""
print("基础代码正常执行")  # 输出:基础代码正常执行,无报错# 排错步骤2:放开注释,修改代码后测试
print("计算结果:" + str(100))  # 将数字转为字符串,修复报错
# 执行结果:控制台输出"计算结果:100",无报错

执行过程

  1. 初始代码执行时,"计算结果:" + 100触发类型错误,代码报错;
  2. 注释报错行后,剩余代码正常执行,说明基础逻辑无问题;
  3. 放开注释并修改代码(str(100)转字符串),代码正常执行,定位到“类型不匹配”是报错原因。


02、数据类型_变量_list_tuple_str_number

全文总结

模块 核心特性 关键语法/要点
变量 指向内存空间的可修改标签;无原生常量(约定大写);支持多赋值/交换 1. 命名:字母/数字/下划线,首字符非数字,禁用关键字,区分大小写;
2. 赋值:a=5/a,b=11,12/a=b=77
3. 交换:a,b=b,a(Python特有);
4. 常量:约定全大写(如SHENFENZHENG="xxx"
数字类型(Number) 含4类:int(整型)、float(浮点)、bool(布尔)、complex(复数);type()查类型,id()查内存地址 1. int:支持十进制/二进制(0b)/八进制(0o)/十六进制(0x),打印自动转十进制;
2. float:支持小数/科学计数法(如3.66e3);
3. bool:仅True/False,用于判断;
4. complex:3+4jcomplex(3,4)表示
字符串(str) 有序、不可修改;支持转义字符、格式化;三引号跨行,r前缀取消转义 1. 定义:单/双/三引号;
2. 转义:\n(换行)、\t(缩进)、\r(行首);
3. 格式化:%d(整型)、%f(浮点)、%s(字符串),支持位数控制(%3d/%.2f
列表&元组 有序可索引的容器;列表(list)可修改,元组(tuple)不可修改 1. 列表:[]定义,listvar[1]=99修改值;
2. 元组:()定义,单元素需加逗号((1,)),不可修改;
3. 索引:正向(0开始)/逆向(-1开始),len()查长度

完整详细讲解

第一步:变量基础(从0理解内存与赋值)

1.1 变量的本质

变量是贴在内存空间上的“标签”,赋值即修改标签指向的内容:

# 示例:变量赋值与修改
rujia_305 = "张三"  # 内存存入"张三",rujia_305指向该空间
rujia_305 = "王文"  # 内存存入"王文",rujia_305改为指向该空间
print(rujia_305)    # 运算:读取rujia_305指向的内容 → 输出:王文
1.2 变量的3种声明方式
# 方式1:单独赋值
a = 5
b = 6
print(a)  # 运算:读取a的指向 → 输出5
print(b)  # 运算:读取b的指向 → 输出6# 方式2:多变量同时赋值
a, b = 11, 12
print(a, b)  # 运算:依次读取a、b → 输出11 12# 方式3:多变量赋同一值
a = b = 77
print(a, b)  # 运算:a和b都指向77 → 输出77 77
1.3 变量命名规则(避坑关键)
# 合法命名
sdf_ = 11
_sdf = 23# 区分大小写(不同变量)
abc = 5
ABC = 6
print(abc)  # 运算:读取abc → 输出5# 查看Python关键字(禁止用作变量名)
import keyword
print(keyword.kwlist)  # 运算:调用keyword模块的kwlist属性 → 输出所有关键字(如False、if、for等)
1.4 变量交换(2种写法)
# 写法1:Python特有(简洁)
a = 13
b = 14
a, b = b, a  # 运算:暂存b=14、a=13 → 赋值后a=14,b=13
print(a, b)  # 输出14 13# 写法2:通用(所有语言适用)
a = 16
b = 17
tmp = None   # 初始化空变量
tmp = a      # 运算:tmp = 16
a = b        # 运算:a = 17
b = tmp      # 运算:b = 16
print(a, b)  # 输出17 16
1.5 伪常量(Python无原生常量)
# 约定:全大写表示“常量”(仅规范,仍可修改)
SHENFENZHENG = "210202200005051234"
print(SHENFENZHENG)  # 运算:读取变量 → 输出身份证号

第二步:数字类型(Number)—— 处理数值计算

2.1 整型(int):多进制支持
# 十进制(默认)
intvar = 15
print(intvar)        # 运算:直接输出 → 15
print(type(intvar))  # 运算:查类型 → <class 'int'># 二进制(0b开头)
intvar = 0b1010      # 运算:1*2³+0*2²+1*2¹+0*2⁰=10
print(intvar)        # 输出10# 八进制(0o开头)
intvar = 0o10        # 运算:1*8¹+0*8⁰=8
print(intvar)        # 输出8# 十六进制(0x/0X开头)
intvar = 0XFF        # 运算:15*16¹+15*16⁰=255
print(intvar)        # 输出255
2.2 浮点型(float):小数+科学计数法
# 普通小数
floatvar = 3.15
print(floatvar)      # 输出3.15# 科学计数法
floatvar = 3.66e-3   # 运算:3.66 * 10^(-3) = 0.00366
print(floatvar)      # 输出0.00366floatvar = 3.66e10   # 运算:3.66 * 10^10 = 36600000000.0
print(floatvar)      # 输出36600000000.0
2.3 布尔型(bool):判断专用
boolvar = True
print(boolvar)       # 输出True
print(type(boolvar)) # <class 'bool'>boolvar = False
print(boolvar)       # 输出False
2.4 复数型(complex):高精度运算
# 方式1:直接定义
complexvar = 3 + 4j
print(complexvar)    # 输出(3+4j)# 方式2:函数定义
complexvar = complex(3, -4)  # 运算:实数3,虚数-4 → 3-4j
print(complexvar)            # 输出(3-4j)

第三步:字符串(str)—— 处理文本数据

3.1 字符串定义(单/双/三引号)
# 单引号
strvar = '吴嘉敏同学非常漂亮'
print(strvar)  # 输出:吴嘉敏同学非常漂亮# 双引号(嵌套/转义)
strvar = "尹棉同学'看起来'憨态可掬"
print(strvar)  # 输出:尹棉同学'看起来'憨态可掬
strvar = "尹棉同学\"看起来\"憨态可掬"
print(strvar)  # 输出:尹棉同学"看起来"憨态可掬# 三引号(跨行)
strvar = """
黑夜给了我黑色的眼睛,
但是我却用它翻白眼
"""
print(strvar)  # 输出跨行文本
3.2 转义字符(r前缀取消转义)
# 转义示例
strvar = "马秀娟同学\n含苞待放"  # \n换行
print(strvar)  # 输出:马秀娟同学(换行)含苞待放# 原型输出(r前缀)
strvar = r"本来\n无一物,何处\r惹尘埃"
print(strvar)  # 输出:本来\n无一物,何处\r惹尘埃
3.3 字符串格式化(%占位符)
# %d:整型(控制位数)
strvar = "李毅买了%d个娃娃" % 6  # 运算:%d替换为6 → 输出:李毅买了6个娃娃
print(strvar)strvar = "弄康平买了%3d个水晶头" % 3  # %3d:占3位居右 → 输出:弄康平买了  3个水晶头
print(strvar)# %f:浮点(控制小数)
strvar = "深圳薪资%.1f元" % 9588.89  # 运算:四舍五入保留1位 → 9588.9 → 输出:深圳薪资9588.9元
print(strvar)# %s:通用占位符
strvar = "%s发薪,花了%.1f元" % ("李杰",9.9)  # 运算:%s→李杰,%.1f→9.9 → 输出:李杰发薪,花了9.9元
print(strvar)
3.4 字符串特性(有序可索引,不可修改)
strvar = "朱万明不告诉我"  # 索引:0=朱,1=万,2=明,3=不,4=告,5=诉,6=我
print(strvar[0])  # 运算:取索引0 → 输出:朱
# strvar[0] = "王"  # 报错!字符串不可修改

第四步:列表(list)与元组(tuple)—— 容器数据

4.1 列表(list):可修改,[]定义
# 定义列表
listvar = [67,False,99-7j,"称号","重汽彩"]  # 正向索引0-4,逆向索引-1到-5# 获取值
res = listvar[2]  # 运算:取索引2 → 99-7j
print(res)        # 输出(99-7j)
res = listvar[-1] # 运算:取最后一个 → 重汽彩
print(res)        # 输出重汽彩# 修改值
listvar[1] = 99898878  # 运算:把索引1的False改为99898878
print(listvar)         # 输出[67, 99898878, (99-7j), '称号', '重汽彩']
4.2 元组(tuple):不可修改,()定义
# 定义元组
tuplevar = (67,False,99-7j,"称号","重汽彩")# 获取值
res = tuplevar[3]  # 运算:取索引3 → 称号
print(res)         # 输出称号# 元组标识符(逗号)
res = (1)          # 整型
print(type(res))   # <class 'int'>
res = (1,)         # 元组(加逗号)
print(type(res))   # <class 'tuple'># tuplevar[0] = "罗康"  # 报错!元组不可修改

应用场景及案例

场景1:变量 —— 临时数据存储与复用

案例:用户信息交换
# 需求:存储2个用户的年龄并交换
# 步骤1:定义变量
name1 = "张三"
age1 = 20
name2 = "李四"
age2 = 25
print(f"交换前:{name1}={age1}岁,{name2}={age2}岁")  # 输出:交换前:张三=20岁,李四=25岁# 步骤2:交换年龄
age1, age2 = age2, age1
# 运算过程:
# 1. 暂存age2=25、age1=20;
# 2. 赋值age1=25,age2=20;
print(f"交换后:{name1}={age1}岁,{name2}={age2}岁")  # 输出:交换后:张三=25岁,李四=20岁

场景2:数字类型 —— 数值计算

案例1:进制转换(库存编码)
# 需求:二进制库存编码转十进制
binary_code = 0b1101  # 二进制编码
decimal_code = binary_code
# 运算过程:0b1101 = 1*2³ + 1*2² + 0*2¹ + 1*2⁰ = 8+4+0+1=13
print(f"二进制{binary_code} → 十进制{decimal_code}")  # 输出:二进制13 → 十进制13
案例2:布尔判断(成年验证)
# 需求:判断用户是否成年
age = 18
is_adult = age >= 18  # 运算:18>=18 → True
print(f"年龄{age} → 是否成年:{is_adult}")  # 输出:年龄18 → 是否成年:Trueage = 17
is_adult = age >= 18  # 运算:17>=18 → False
print(f"年龄{age} → 是否成年:{is_adult}")  # 输出:年龄17 → 是否成年:False

场景3:字符串 —— 格式化输出

案例:生成消费账单
# 需求:格式化输出用户账单
username = "王五"
consume_times = 3
total_money = 89.56
status = "已结清"# 格式化字符串
bill = "用户%s本月消费%d次,总金额%.2f元,状态:%s" % (username, consume_times, total_money, status)
# 运算过程:
# %s → 王五;%d → 3;%.2f → 89.56;%s → 已结清;
# 最终字符串:用户王五本月消费3次,总金额89.56元,状态:已结清
print(bill)  # 输出上述结果

场景4:列表 —— 动态购物车管理

# 需求:修改购物车商品
# 步骤1:初始化购物车
cart = ["苹果", "香蕉", "橙子"]
print(f"初始购物车:{cart}")  # 输出:初始购物车:['苹果', '香蕉', '橙子']# 步骤2:修改商品
cart[2] = "葡萄"
# 运算过程:cart[2]是橙子 → 赋值为葡萄 → cart=['苹果','香蕉','葡萄']
print(f"修改后购物车:{cart}")  # 输出:修改后购物车:['苹果', '香蕉', '葡萄']# 步骤3:获取最后一个商品
last_goods = cart[len(cart)-1]
# 运算过程:len(cart)=3 → 3-1=2 → cart[2]=葡萄
print(f"最后一个商品:{last_goods}")  # 输出:最后一个商品:葡萄

场景5:元组 —— 固定规格存储

# 需求:存储手机固定规格(不可修改)
phone_spec = (6.7, "1080x2400", 5000)  # 尺寸、分辨率、电池容量
print(f"手机尺寸:{phone_spec[0]}英寸")  # 运算:取索引0 → 6.7 → 输出:手机尺寸:6.7英寸
print(f"电池容量:{phone_spec[2]}mAh")  # 运算:取索引2 → 5000 → 输出:电池容量:5000mAh# 验证不可修改(注释掉,执行会报错)
# phone_spec[1] = "2K"  # 报错:元组不支持赋值修改


03、Number与容器类型

全文核心总结

1. Number类型(int/float/bool/complex)转换

  • 自动类型转换:精度从低到高(bool→int→float→complex),低精度数据与高精度数据运算时,低精度会自动转为高精度,最终结果为高精度类型。
  • 强制类型转换:可主动通过int()/float()/complex()/bool()转换类型;仅纯数字字符串可转为Number类型;bool类型有10种为False的情况(0、0.0、False、0j、''、[]、()、{}、set()、None)。

2. 容器类型(set集合/dict字典)

特性 set集合 dict字典
存储形式 无序、自动去重 键值对存储、3.6+字面有序
取值/改值 不可取值、不可改值 可通过键取值、改值
数据要求 集合值必须是可哈希数据 字典键必须是可哈希数据
空值定义 set(){}是空字典) {}
可哈希数据 int/float/bool/complex/str/tuple 同左
不可哈希数据 list/dict/set 同左

3. 容器类型强制转换(str/list/tuple/set/dict)

转换目标 字符串转换规则 其他容器转换规则 字典转换特殊规则
str 所有类型可转,仅在数据两侧套引号 所有类型可转,仅在数据两侧套引号 保留键值对套引号
list 字符拆分为列表元素 仅套[],元素为原容器元素 仅保留键作为元素
tuple 字符拆分为元组元素 仅套(),元素为原容器元素 仅保留键作为元素
set 字符拆分、自动去重、无序 仅套{},元素去重、无序 仅保留键作为元素

4. 变量缓存机制(同一文件内)

数据类型 缓存规则
int -5~正无穷范围,相同值的内存地址(id)一致
float 非负数范围,相同值的内存地址一致
bool 相同值(True/False)的内存地址一致
complex 实数+虚数结构id永不相同;仅纯虚数(如5j)id一致

完整详细讲解

1. Number类型:自动类型转换

核心规则

精度优先级:bool(最低)→ int → float → complex(最高),低精度与高精度运算时,低精度自动转为高精度,结果为高精度类型。

逐例运算过程

  • 例1:bool + int
    var1 = True  # bool自动转int=1
    var2 = 78    # int类型
    res = var1 + var2  # 运算:1 + 78 = 79
    print(res, type(res))  # 输出:79 <class 'int'>
    
  • 例2:bool + float
    var1 = False  # bool转int=0→再转float=0.0
    var2 = 31.56  # float类型
    res = var1 + var2  # 运算:0.0 + 31.56 = 31.56
    print(res)  # 输出:31.56
    
  • 例3:bool + complex
    var1 = True   # bool转int=1→再转complex=1+0j
    var2 = 5-9j   # complex类型
    res = var1 + var2  # 运算:(1+0j) + (5-9j) = 6-9j
    print(res)  # 输出:(6-9j)
    
  • 例4:int + float
    var1 = 3     # int转float=3.0
    var2 = 1.8   # float类型
    res = var1 + var2  # 运算:3.0 + 1.8 = 4.8(内存精度问题可能显示4.799999999999999)
    print(res)  # 输出:4.8
    
  • 例5:int + complex
    var1 = 5     # int转complex=5+0j
    var2 = 3+2j  # complex类型
    res = var1 + var2  # 运算:(5+0j) + (3+2j) = 8+2j
    print(res)  # 输出:(8+2j)
    
  • 例6:float + complex
    var1 = 3.19  # float转complex=3.19+0j
    var2 = 7j    # complex类型=0+7j
    res = var1 + var2  # 运算:(3.19+0j) + (0+7j) = 3.19+7j
    print(res)  # 输出:(3.19+7j)
    

2. Number类型:强制类型转换

核心规则

主动通过int()/float()/complex()/bool()转换类型;非纯数字字符串转换会报错;bool转换仅10种情况为False。

逐例运算过程

(1) 强制转int
var2 = 5.88
res = int(var2)  # 运算:舍弃小数,结果=5
var4 = True
res = int(var4)  # 运算:bool转int,True=1
var5 = False
res = int(var5)  # 运算:bool转int,False=0
var6 = "1234"
res = int(var6)  # 运算:纯数字字符串转int=1234
# var7 = "abcdefg1" → int(var7) 报错(非纯数字)
print(res, type(res))  # 输出:1234 <class 'int'>
(2) 强制转float
var1 = 67
res = float(var1)  # 运算:int转float=67.0
var4 = True
res = float(var4)  # 运算:True=1.0
var5 = False
res = float(var5)  # 运算:False=0.0
var6 = "1234"
res = float(var6)  # 运算:纯数字字符串转float=1234.0
# var7 = "abcdefg1" → float(var7) 报错
print(res)  # 输出:1234.0
(3) 强制转complex
var1 = 67
res = complex(var1)  # 运算:int转complex=67+0j
var2 = 5.88
res = complex(var2)  # 运算:float转complex=5.88+0j
var4 = True
res = complex(var4)  # 运算:True=1+0j
var5 = False
res = complex(var5)  # 运算:False=0j
var6 = "1234"
res = complex(var6)  # 运算:纯数字字符串转complex=1234+0j
print(res)  # 输出:(1234+0j)
(4) 强制转bool
var2 = 5.88
res = bool(var2)  # 运算:非假值→True
var7 = "abcdefg1"
res = bool(var7)  # 运算:非空字符串→True
var3 = 3+6j
res = bool(var3)  # 运算:非0j→True
res = bool(set()) # 运算:空集合(假值)→False
print(res)  # 输出:False
补充:默认空值转换
res = int()     # 运算:默认空int=0
res = float()   # 运算:默认空float=0.0
res = bool()    # 运算:默认空bool=False
res = complex() # 运算:默认空complex=0j
print(res, type(res))  # 输出:0j <class 'complex'>

3. 容器类型:set集合

核心规则

无序、自动去重;值必须是可哈希(不可变)数据;不可取值/改值;空集合用set()定义。

逐例运算过程

# 例1:基础定义
setvar = {'刘德华',"张学友","郭富城","王文"}
print(setvar, type(setvar))  # 输出:{'刘德华', '张学友', '郭富城', '王文'} <class 'set'># 例2:自动去重
setvar = {"王宝强","马蓉","宋哲","小情人","小情人"}
print(setvar, type(setvar))  # 输出:{'王宝强', '马蓉', '宋哲', '小情人'} <class 'set'># 例3:空集合 vs 空字典
setvar = {}
print(setvar, type(setvar))  # 输出:{} <class 'dict'>(空字典)
setvar = set()
print(setvar, type(setvar))  # 输出:set() <class 'set'>(空集合)# 例4:不可取值/改值(以下两行报错,注释掉)
# res = setvar[3]  # 无序无索引,报错
# setvar[0] = 123  # 不可改值,报错# 例5:可哈希验证(以下行报错,注释掉)
# setvar = {1,"a","3",3445,(1,2,3,4),{"a":1}}  # 字典不可哈希,报错

4. 容器类型:dict字典

核心规则

键值对存储、3.6+字面有序;可通过键取值/改值;键必须是可哈希数据;空字典用{}定义。

逐例运算过程

# 例1:基础定义
dictvar = {"top":"夏侯村","middle":"王昭君","bottom":"百里守约","jungle":"韩信","support":"蔡文姬"}
print(dictvar, type(dictvar))  # 输出:{'top': '夏侯村', 'middle': '王昭君', 'bottom': '百里守约', 'jungle': '韩信', 'support': '蔡文姬'} <class 'dict'># 例2:取值
res = dictvar["middle"]
print(res)  # 输出:王昭君# 例3:改值
dictvar['bottom'] = "鲁班七号"
print(dictvar)  # 输出:{'top': '夏侯村', 'middle': '王昭君', 'bottom': '鲁班七号', 'jungle': '韩信', 'support': '蔡文姬'}# 例4:空字典定义
dictvar = {}
print(dictvar, type(dictvar))  # 输出:{} <class 'dict'># 例5:可哈希键验证
dictvar= {1:False,5.78:"你好",False:332244,4-7j:89,"我是大帅锅":"王文",(1,2,3,4,5):"909090"}
print(dictvar)  # 输出:{1: False, 5.78: '你好', False: 332244, (4-7j): 89, '我是大帅锅': '王文', (1, 2, 3, 4, 5): '909090'}# 例6:不可哈希键验证(以下行报错,注释掉)
# dictvar = {"a":1,{"a":3}:3}  # 字典不可哈希,报错

5. 容器类型:强制类型转换

核心规则

字符串拆分为单个字符;字典仅保留键;集合自动去重、无序。

逐例运算过程

# 定义基础变量
var1 = "尹棉真漂亮亮呀呀"
var2 = ["罗康","欧阳换","蘖康亮","张亚军"]
var3 = ("李人称","朱万明","党朝峰")
var4 = {"徐梦薇","呼和金","陈学斌","彭金成"}
var5 = {'cyy':"陈元叶",'lcy':"刘晨宇",'zzc':"重汽彩"}# (1) 强制转str
res = str(var2)  # 运算:列表套引号→"['罗康', '欧阳换', '蘖康亮', '张亚军']"
print(res, type(res))  # 输出:['罗康', '欧阳换', '蘖康亮', '张亚军'] <class 'str'>
print(repr(res))  # 原型化输出:"'['罗康', '欧阳换', '蘖康亮', '张亚军']'"# (2) 强制转list
res = list(var1)  # 运算:字符串拆字符→['尹', '棉', '真', '漂', '亮', '亮', '呀', '呀']
res = list(var5)  # 运算:字典取键→['cyy', 'lcy', 'zzc']
print(res)  # 输出:['cyy', 'lcy', 'zzc']# (3) 强制转tuple
res = tuple(var1) # 运算:字符串拆字符→('尹', '棉', '真', '漂', '亮', '亮', '呀', '呀')
res = tuple(var5) # 运算:字典取键→('cyy', 'lcy', 'zzc')
print(res)  # 输出:('cyy', 'lcy', 'zzc')# (4) 强制转set
res = set(var1)   # 运算:拆字符+去重→{'尹', '棉', '真', '漂', '亮', '呀'}
res = set(var5)   # 运算:字典取键→{'cyy', 'lcy', 'zzc'}
print(res)  # 输出:{'cyy', 'lcy', 'zzc'}# 实战:列表去重
listvar = ["李杰","李杰","李杰","李铮","弄康饼","弄康饼","曾文"]
res1 = set(listvar)  # 步骤1:转集合去重→{'李杰', '李铮', '弄康饼', '曾文'}
res2 = list(res1)    # 步骤2:转回列表→['李杰', '李铮', '弄康饼', '曾文']
print(res2)  # 输出:['李杰', '李铮', '弄康饼', '曾文']

6. 变量缓存机制

核心规则

同一文件内,不同Number类型的相同值,内存地址(id)是否一致有明确规则。

逐例运算过程

# (1) int:-5~正无穷,相同值id一致
var1 = 133
var2 = 133
print(id(var1) == id(var2))  # 输出:True(133≥-5)
var1 = -100
var2 = -100
print(id(var1) == id(var2))  # 输出:False(-100<-5)# (2) float:非负数,相同值id一致
var1 = 3.14
var2 = 3.14
print(id(var1) == id(var2))  # 输出:True(非负数)
var1 = -4.55
var2 = -4.55
print(id(var1) == id(var2))  # 输出:False(负数)# (3) bool:相同值id一致
var1 = True
var2 = True
print(id(var1) == id(var2))  # 输出:True# (4) complex:仅纯虚数id一致
var1 = 5+3j
var2 = 5+3j
print(id(var1) == id(var2))  # 输出:False(实数+虚数)
var1 = 5j
var2 = 5j
print(id(var1) == id(var2))  # 输出:True(仅虚数)

应用场景及案例(带详细运算过程)

1. Number类型转换:数据格式标准化

场景说明

处理用户输入的字符串型数字,转为数值型后进行运算(如金融计算、数据统计)。

案例:计算本息和

# 需求:用户输入字符串型本金和利率,计算一年后本息和
# 步骤1:模拟用户输入
principal_str = "1000"  # 字符串型本金
rate_str = "3.5"        # 字符串型年利率(百分比)# 步骤2:强制转换类型
principal = int(principal_str)  # 运算:"1000"→1000
rate = float(rate_str) / 100    # 运算:"3.5"→3.5→0.035# 步骤3:自动类型转换运算(int×float→float)
interest = principal * (1 + rate)  # 运算:1000 × (1+0.035) = 1035.0# 步骤4:输出结果
print(f"一年后本息和:{interest} 元")  # 输出:一年后本息和:1035.0 元

2. set集合:列表去重

场景说明

处理重复数据(如用户名单、订单编号),快速去重并保留唯一值。

案例:学生名单去重

# 需求:去除重复的学生名单
# 步骤1:定义重复名单
student_list = ["张三","李四","张三","王五","李四","赵六"]# 步骤2:转集合去重(自动去重、无序)
student_set = set(student_list)  # 运算:去重→{'张三','李四','王五','赵六'}# 步骤3:转回列表(统一容器类型)
unique_student = list(student_set)  # 运算:集合转列表→['张三','李四','王五','赵六']# 步骤4:输出结果
print("去重后名单:", unique_student)  # 输出:去重后名单:['张三', '李四', '王五', '赵六']

3. dict字典:配置项管理

场景说明

存储系统/业务配置(如游戏角色、接口参数),快速取值/改值。

案例:修改游戏角色配置

# 需求:定义游戏五路角色,修改下路角色后输出
# 步骤1:定义初始配置
game_role = {"top": "夏侯淳","middle": "王昭君","bottom": "百里守约","jungle": "韩信","support": "蔡文姬"
}# 步骤2:取值验证
middle_role = game_role["middle"]  # 运算:取key=middle的值→王昭君
print("原中路角色:", middle_role)  # 输出:原中路角色:王昭君# 步骤3:修改下路角色
game_role["bottom"] = "鲁班七号"  # 运算:修改key=bottom的值→鲁班七号# 步骤4:输出新配置
print("修改后配置:", game_role)
# 输出:修改后配置:{'top': '夏侯淳', 'middle': '王昭君', 'bottom': '鲁班七号', 'jungle': '韩信', 'support': '蔡文姬'}

4. 容器类型转换:验证码验证

场景说明

拆分验证码字符串为字符列表,验证是否包含数字和字母。

案例:验证码合法性检测

# 需求:验证验证码"8A9s7"是否包含数字和字母
# 步骤1:定义验证码
verify_code = "8A9s7"# 步骤2:转列表拆分字符
code_list = list(verify_code)  # 运算:拆分为→['8','A','9','s','7']# 步骤3:遍历验证
has_digit = False
has_letter = False
for char in code_list:if char.isdigit():has_digit = True  # 检测到数字→Trueelif char.isalpha():has_letter = True # 检测到字母→True# 步骤4:输出结果
print(f"包含数字:{has_digit},包含字母:{has_letter}")  # 输出:包含数字:True,包含字母:True

5. 变量缓存机制:内存优化

场景说明

大量使用重复数值时,利用缓存机制减少内存占用(如循环生成固定值列表)。

案例:生成重复数值列表

# 需求:生成1000个100的列表,验证内存复用
# 步骤1:验证100的缓存(100≥-5,id一致)
a = 100
b = 100
print(f"a和b的id是否一致:{id(a) == id(b)}")  # 输出:True# 步骤2:生成列表(所有100共享同一内存地址)
num_list = [100 for _ in range(1000)]# 步骤3:验证列表元素id
print(f"列表前两个元素id是否一致:{id(num_list[0]) == id(num_list[1])}")  # 输出:True# 说明:若用-10(< -5),id会不同,内存占用更高;用100复用内存,优化开销


04、运算符_二级容器

全文总结

模块 核心作用 关键要点
算术运算符 数值的加减乘除、取余、幂等计算 1. / 返回浮点数,// 地板除返回整数(含小数则补.0);2. % 取余需注意正负号规则;3. ** 是幂运算
比较运算符 比较两个值的大小/相等关系 结果仅为True/False;== 比数值,is 比地址(身份运算符)
赋值运算符 将计算结果赋值给变量 复合赋值(+=/-=等)等价于 变量=变量+值;赋值优先级最低
成员运算符 判断元素是否在容器中 1. in/not in 针对容器;2. 字典默认判断键,非值;3. 字符串需匹配连续片段
身份运算符 判断变量指向值的内存地址是否相同 1. is/is not 比地址,== 比数值;2. int(-5~+∞)地址复用,浮点数/多数容器地址不同
逻辑运算符 布尔值的与/或/非运算 1. and 全真则真,or 一真则真,not 取反;2. 存在逻辑短路;3. 优先级:()>not>and>or
位运算符 对二进制位进行操作 1. &与/`
运算符优先级 确定多运算符混合运算顺序 1. 最高:(),最低:=;2. 一元运算符>二元运算符;3. 算术>位>比较>身份>成员>逻辑
二级容器 存储嵌套的容器数据 1. 容器内元素仍是容器;2. 等长二级容器(元素数=2)可强转字典;3. 集合内层仅推荐元组

完整详细输出

1. 算术运算符(+ - * / // % **)

用于数值计算,核心是理解每种运算的规则:

# 基础运算
var1 = 7
var2 = 4
print(7 + 4)  # 11(加法)
print(7 - 4)  # 3(减法)
print(7 * 4)  # 28(乘法)# 除法:/返回浮点数,//地板除返回整数
print(7 / 4)   # 1.75(非整除)
print(8 / 4)   # 2.0(整除仍为浮点数)
print(7 // 4)  # 1(地板除取整)
print(8.1//4)  # 2.0(含小数补.0)# 取余:注意正负号规则
print(9 % 8)    # 1(正正取余)
print(9 % -8)   # -7(1 + (-8) = -7)
print(-9 % 8)   # 7(-1 + 8 = 7)# 幂运算:n次幂
print(7 ** 2)  # 49(7的2次幂)

2. 比较运算符(> < >= <= == !=)

比较值的关系,结果只有True/False:

var1 = 15
var2 = 13
print(var1 > var2)   # True(15>13)
print(var1 == var2)  # False(值不相等)
print(var1 != var2)  # True(值不相等)
print(13 >= 13)      # True(等于满足>=)

3. 赋值运算符(= += -= *= /= //= %= **=)

将计算结果赋值给变量,复合赋值是简化写法:

var1 = 13
var2 = 9
var1 += var2  # 等价于 var1 = 13+9 → 22
var1 *= var2  # 等价于 var1 = 22×9 → 198
var1 **= var2 # 等价于 var1 = 198⁹(幂赋值)

4. 成员运算符(in /not in)

判断元素是否在容器中,字典默认判断“键”:

# 字符串:需匹配连续片段
strvar = "如果遇到你是一种错"
print("遇到" in strvar)  # True(连续片段)
print("遇你" in strvar)  # False(非连续)# 列表/字典
listvar = ["湖泽","无照"]
print("无照" in listvar)  # Truedictvar = {"鼓上骚":"石阡"}
print("石阡" in dictvar)  # False(判断键,非值)
print("鼓上骚" in dictvar)# True

5. 身份运算符(is/is not)

判断变量指向值的内存地址==比数值,is比地址):

# int(-5~+∞)地址复用
var1 = 67
var2 = 67
print(var1 is var2)  # True(地址相同)# 浮点数地址不同
var1 = 5.67
var2 = 5.67
print(var1 is not var2)  # True(地址不同)# None是单例,地址唯一
print(None is None)  # True

6. 逻辑运算符(and/or/not)

布尔值运算,核心是“短路规则”和优先级:

# 基础规则
print(True and False)  # False(全真则真)
print(True or False)   # True(一真则真)
print(not True)        # False(取反)# 逻辑短路:满足条件跳过后续代码
False and print("短路1")  # 无输出(False and 任意值→False)
True or print("短路2")   # 无输出(True or 任意值→True)# 优先级:() > not > and > or
res = 1>2 or 3<4 and 5>6 or 8<9
# 拆解:False or (True and False) or True → True
print(res)  # True

7. 位运算符(& | ^ << >> ~)

对二进制位操作,先转二进制再计算(以19、15为例):

var1 = 19  # 二进制:000...10011
var2 = 15  # 二进制:000...01111# 按位与:对应位都为1则为1
res = var1 & var2  # 000...00011 → 3
print(res)# 按位或:对应位有1则为1
res = var1 | var2  # 000...11111 → 31
print(res)# 左移:等价于×2ⁿ
res = 5 << 1  # 5×2¹=10(二进制:101→1010)
print(res)# 按位非:~n = -n-1
print(~19)  # -20(19→-19-1=-20)
print(~-19) # 18(-19→19-1=18)

8. 运算符优先级

核心规则:() > 一元运算符 > 算术 > 位 > 比较 > 身份 > 成员 > 逻辑 > =

# 示例拆解
res = 5+5<<6//3 is 40 and True
# 步骤1:算术运算 → 10 << 2 is 40 and True
# 步骤2:位运算 → 40 is 40 and True
# 步骤3:身份运算 → True and True
# 步骤4:逻辑运算 → True
print(res)  # True

9. 二级容器

容器内嵌套容器,支持逐层取值,等长二级容器可强转字典:

# 嵌套取值(四级容器取10)
listvar = [1,2,3,(4,5,6,[7,8,(10,11,12),9])]
res = listvar[-1][-1][-2][0]  # 逐层取:元组→列表→元组→第一个元素
print(res)  # 10# 强转字典(元素数=2的等长二级容器)
listvar = [("a",1),["b",2],"c3"]
res = dict(listvar)
print(res)  # {'a':1, 'b':2, 'c':3}

应用场景及案例(带详细运算过程)

1. 算术运算符:订单金额计算

场景:计算商品总价+税费-优惠券

price = 199  # 单价
count = 3     # 数量
tax_rate = 0.1 # 税率
coupon = 50   # 优惠券# 分步运算
total_price = price * count  # 199×3=597
tax = total_price * tax_rate # 597×0.1=59.7
final_pay = total_price + tax - coupon # 597+59.7-50=606.7print(f"最终支付:{final_pay}")  # 606.7

2. 逻辑运算符:登录验证

场景:用户名、密码、验证码都正确才登录成功

username = "admin"
password = "123456"
verify_code = "8888"# 多条件判断
login_ok = (username=="admin") and (password=="123456") and (verify_code=="8888")
# 拆解:True and True and True → True
print(login_ok)  # True

3. 位运算符:高效交换两个数

场景:无需临时变量交换数值(异或运算)

a = 5  # 二进制:101
b = 7  # 二进制:111# 分步交换
a = a ^ b  # 101^111=010 → a=2
b = a ^ b  # 010^111=101 → b=5
a = a ^ b  # 010^101=111 → a=7print(f"交换后a={a},b={b}")  # a=7,b=5

4. 二级容器:学生成绩查询

场景:存储学生信息,查询指定学生的科目成绩

# 二级列表存储学生信息:[姓名, 年龄, {科目:成绩}]
students = [["张三", 18, {"数学":95, "语文":88}],["李四", 17, {"数学":82, "语文":90}]
]# 查询张三的数学成绩
target = None
for stu in students:if stu[0] == "张三":target = stu
math_score = target[2]["数学"]  # 取内层字典的“数学”值
print(f"张三数学成绩:{math_score}")  # 95

5. 身份运算符:校验None值

场景:判断函数返回值是否为None(None地址唯一,is更高效)

def get_data():return None  # 模拟无数据返回data = get_data()
if data is None:print("未获取到数据")  # 输出:未获取到数据

6. 成员运算符:手机号合法性校验

场景:判断手机号是否仅含数字

phone = "13812345678"
valid_chars = "0123456789"
is_valid = Truefor char in phone:if char not in valid_chars:is_valid = Falsebreakprint(f"手机号合法:{is_valid}")  # True


05、程控制_字符串操作

全文总结

知识点模块 核心内容 关键规则/语法
代码块 以冒号开头,缩进来划分代码作用域;Python中缩进需统一(tab或4个空格),缩进相同则为同一代码块 语法:if 条件:(冒号)+ 缩进代码;缩进不统一会触发缩进错误
分支结构 控制代码执行的分支走向,分4类:
1. 单项分支:仅if判断,满足则执行
2. 双项分支:if+else,二选一执行
3. 多项分支:if+多个elif+可选else,多选一执行
4. 巢状分支:分支内嵌套分支,按缩进层级执行
1. elif可多个/无,else仅0/1个;
2. 多项分支仅执行第一个满足条件的分支;
3. 巢状分支按缩进层级逐层判断
while循环 重复执行代码块,直到条件不成立;核心是“初始化变量→条件判断→自增/减”三要素 语法:while 条件: + 缩进代码;
死循环:while True:(需手动终止);
缺少自增/减会导致死循环
字符串操作 常用操作:拼接(+)、重复(*)、跨行拼接()、索引、切片 1. 索引:正向从0开始,逆向从-1开始;
2. 切片:字符串[开始索引:结束索引:间隔值],结束索引取不到,间隔值为-1时倒序

补充说明

  1. 分支结构核心逻辑:“条件判断→执行对应代码块”,不满足则向下/向外层分支执行;
  2. while循环的“三要素”是避免死循环的关键;
  3. 字符串切片的“结束索引取不到”是高频易错点;
  4. Python通过“冒号+缩进”区分代码块,不同于其他语言的大括号。

完整详细讲解

一、代码块

1. 核心定义

代码块是Python中“以冒号:开头,用缩进来划分作用域”的代码集合,缩进相同的代码属于同一层级,缩进不同则为不同层级。

2. 基础示例+执行过程
# 顶级代码块(无缩进),优先执行
print(1)
print(2)# if分支的代码块(缩进层级1)
if True:print(4)  # 同一缩进层级,属于if的代码块print(5)# 条件不成立的代码块(不执行)
if False:print(6)print(7)

执行过程

  • 第一步:执行顶级代码print(1)→输出1;print(2)→输出2;
  • 第二步:判断if True条件成立→执行其缩进代码:print(4)→输出4,print(5)→输出5;
  • 第三步:判断if False条件不成立→跳过其缩进代码,print(6/7)不执行;
  • 最终输出:1、2、4、5。
3. 易错点:缩进不统一
if True:print(9)print(10)  # 混用tab和4空格→触发IndentationError

执行结果:运行直接报错,代码无法执行(Python对缩进格式严格)。

二、分支结构

1. 单项分支(仅if判断)
语法
if 条件表达式:缩进代码块(满足条件则执行)
示例+执行过程
yinmian = "小仙女"
if yinmian == "小仙女":print("买好吃的")print("买兰博基尼")

执行过程

  • 步骤1:定义变量yinmian = "小仙女"
  • 步骤2:判断yinmian == "小仙女"→结果为True;
  • 步骤3:执行缩进代码→输出“买好吃的”“买兰博基尼”。
2. 双项分支(if+else)
语法
if 条件表达式:真区间代码块
else:假区间代码块
示例(登录验证)+执行过程
user = input("请输入用户名:")  # 输入admin
pwd = input("请输入密码:")     # 输入000
if user == "admin" and pwd == "000":print("恭喜你,登陆成功")
else:print("用户名或者密码错误")

执行过程(输入正确)

  • 步骤1:input获取用户名→user = "admin",密码→pwd = "000"
  • 步骤2:判断user == "admin" and pwd == "000"→True;
  • 步骤3:执行真区间→输出“恭喜你,登陆成功”。
    执行过程(输入错误)
  • 若密码输入123→判断结果为False→执行假区间→输出“用户名或者密码错误”。
3. 多项分支(if+elif+else)
语法
if 条件1:代码块1
elif 条件2:代码块2
elif 条件3:代码块3
else:代码块4
示例(身高判断)+执行过程
height = float(input("请输入身高:"))  # 输入1.75
if height>=1 and height<1.5:print("小强 你在哪里?")
elif height>=1.5 and height<1.7:print("没有安全感~")
elif height>=1.7 and height<1.8:print("帅哥 留个电话")
elif height>=1.8 and height<2:print("帅哥 你建议多一个女朋友吗")
else:print("没有该选项")

执行过程

  • 步骤1:input获取“1.75”→float(1.75)height = 1.75
  • 步骤2:判断height>=1 and height<1.5→1.75不满足→跳过;
  • 步骤3:判断height>=1.5 and height<1.7→1.75不满足→跳过;
  • 步骤4:判断height>=1.7 and height<1.8→1.75满足→执行print("帅哥 留个电话")→输出;
  • 步骤5:后续elif/else不再执行(多项分支仅执行第一个满足的分支)。
4. 巢状分支(分支嵌套)
语法
if 外层条件:外层代码块if 内层条件:内层代码块
else:外层假区间代码块
示例+执行过程
youqian = True
youfang = True
youche = False
if youqian == True:if youfang == True:if youche == True:print("嫁给你")else:print("补一补再来")else:print("改进一下")
else:print("左拐坐公交")

执行过程

  • 步骤1:定义变量youqian=Trueyoufang=Trueyouche=False
  • 步骤2:判断外层条件youqian == True→True→进入外层代码块;
  • 步骤3:判断内层条件1youfang == True→True→进入内层代码块1;
  • 步骤4:判断内层条件2youche == True→False→执行内层else→输出“补一补再来”。

三、while循环

1. 核心语法+三要素
i = 1          # 1. 初始化变量
while i<=100:  # 2. 条件判断print(i)   # 循环体i+=1       # 3. 变量自增(避免死循环)
2. 示例1:打印1~100
i = 1
while i<=100:print(i)i+=1

执行过程(关键步骤)

  • 初始:i=1
  • 第1次循环:1<=100→True→print(1)i=2
  • 第2次循环:2<=100→True→print(2)i=3
  • ...(重复至i=100);
  • 第100次循环:100<=100→True→print(100)i=101
  • 第101次判断:101<=100→False→循环终止。
3. 示例2:1~100累加和
i = 1
total = 0
while i<=100:total += i  # total = total + ii+=1
print(total)  # 输出5050

执行过程(关键步骤)

  • 初始:i=1total=0
  • 第1次循环:total=0+1=1i=2
  • 第2次循环:total=1+2=3i=3
  • ...(重复至i=100);
  • 第100次循环:total=4950+100=5050i=101
  • 循环终止→print(total)→输出5050。

四、字符串操作

1. 拼接(+) & 重复(*)
# 拼接:首尾连接字符串
var1 = "我爱吃,"
var2 = "麻婆豆腐"
res = var1 + var2  # 结果:"我爱吃,麻婆豆腐"# 重复:按次数复制字符串
res1 = "我爱你," * 3  # 结果:"我爱你,我爱你,我爱你,"

执行过程

  • 拼接:直接将两个字符串首尾拼接;
  • 重复:将字符串按指定次数复制后拼接。
2. 索引(取值)
strvar = "黑夜给了我黑色的眼睛"  # 正向索引0-9,逆向-10到-1
print(strvar[8])   # 正向取索引8→"眼"
print(strvar[-2])  # 逆向取倒数第2位→"眼"

索引映射关系

正向索引 0 1 2 3 4 5 6 7 8 9
字符
逆向索引 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
3. 切片(截取)
strvar = "我爱你亲爱的姑凉,见到你我就心慌"
res1 = strvar[3:]        # 从索引3取到最后→"亲爱的姑凉,见到你我就心慌"
res2 = strvar[:8]        # 从开头取到索引7→"我爱你亲爱的姑"
res3 = strvar[1:10:2]    # 索引1/3/5/7/9→"爱亲的凉见"
res4 = strvar[::-1]      # 倒序取所有→"慌心就我你到见,凉姑的爱亲你爱我"

执行规则

  • [开始索引:]:从开始索引取到字符串末尾;
  • [:结束索引]:从开头取到“结束索引-1”;
  • [开始:结束:间隔]:按间隔值跳着取,间隔为-1时倒序。

应用场景及案例(带详细运算过程)

一、分支结构应用场景

场景1:用户登录验证(双项分支)
业务场景

系统登录界面,验证用户名/密码是否正确。

案例代码
# 预设正确账号密码
correct_user = "user001"
correct_pwd = "pass123"# 获取用户输入
user_input = input("请输入用户名:")
pwd_input = input("请输入密码:")# 双项分支判断
if user_input == correct_user and pwd_input == correct_pwd:print("登录成功,欢迎使用!")
else:print("用户名或密码错误,请重试!")
运算过程(输入正确)
  • 步骤1:定义correct_user="user001"correct_pwd="pass123"
  • 步骤2:用户输入user_input="user001"pwd_input="pass123"
  • 步骤3:判断条件→True→输出“登录成功,欢迎使用!”。
场景2:商品价格分级(多项分支)
业务场景

根据价格区间标注商品等级。

案例代码
price = float(input("请输入商品价格(元):"))  # 输入1999
if price < 100:print("低价商品")
elif 100 <= price < 1000:print("中价商品")
elif 1000 <= price < 2000:print("高价商品")
else:print("超高价商品")
运算过程
  • 步骤1:price = 1999
  • 步骤2:判断price < 100→False→跳过;
  • 步骤3:判断100 <= price < 1000→False→跳过;
  • 步骤4:判断1000 <= price < 2000→True→输出“高价商品”。

二、while循环应用场景

场景1:生成6位数字验证码
业务场景

批量生成6位随机数字验证码。

案例代码
import random
i = 0
code = ""
while i < 6:num = str(random.randint(0,9))code += numi += 1
print("生成的验证码:", code)  # 示例输出:859274
运算过程(生成859274)
  • 步骤1:初始化i=0code=""
  • 第1次循环:生成8→code="8"i=1
  • 第2次循环:生成5→code="85"i=2
  • 第3次循环:生成9→code="859"i=3
  • 第4次循环:生成2→code="8592"i=4
  • 第5次循环:生成7→code="85927"i=5
  • 第6次循环:生成4→code="859274"i=6
  • 循环终止→输出验证码。
场景2:计算1~N的累加和
业务场景

用户输入N,计算1+2+...+N的和。

案例代码
n = int(input("请输入正整数N:"))  # 输入10
i = 1
total = 0
while i <= n:total += ii += 1
print(f"1到{n}的和:{total}")  # 输出55
运算过程(N=10)
  • 步骤1:n=10i=1total=0
  • 第1次循环:total=1i=2
  • 第2次循环:total=3i=3
  • ...(重复至i=10);
  • 第10次循环:total=55i=11
  • 循环终止→输出55。

三、字符串操作应用场景

场景1:手机号脱敏(切片)
业务场景

隐藏手机号中间4位(13812345678→138****5678)。

案例代码
phone = input("请输入11位手机号:")  # 输入13812345678
hide_phone = phone[:3] + "****" + phone[-4:]
print("脱敏手机号:", hide_phone)  # 输出138****5678
运算过程
  • 步骤1:phone="13812345678"
  • 步骤2:phone[:3]→"138",phone[-4:]→"5678";
  • 步骤3:拼接→"138"+""+"5678"→"1385678"。
场景2:字符串逆序(切片)
业务场景

将输入字符串逆序输出(如Python→nohtyP)。

案例代码
str_input = input("请输入字符串:")  # 输入Python
reverse_str = str_input[::-1]
print("逆序结果:", reverse_str)  # 输出nohtyP
运算过程
  • 步骤1:str_input="Python"(索引0:P,1:y,2:t,3:h,4:o,5:n);
  • 步骤2:[::-1]倒序取→n→o→h→t→y→P→"nohtyP";
  • 步骤3:输出逆序结果。


06、循环_pass_break_continue_for

一、全文总结

1.1 核心知识点总览(表格)

知识点分类 核心内容 关键特点
for循环 遍历容器(列表/集合/字典/元组/字符串)、range生成可迭代对象、变量解包 更适合遍历数据,自动迭代无需手动控制索引;字典默认遍历键
while循环 基于条件的循环,需手动初始化/更新循环变量(如i+=1) 更适合复杂逻辑,需避免死循环(忘记更新变量)
循环控制关键字 pass(占位)、break(终止当前循环)、continue(跳过当前循环) break仅终止当前层循环;continue需先更新变量,否则会死循环
双层循环 外层控制行、内层控制列,用于打印多行多列图案 外层执行1次,内层执行全部次数;可通过%///实现隔行/隔列样式变化
循环实用技巧 %(取余)判断奇偶/整除、//(地板除)提取高位、end=""取消换行 %用于隔列变色,//用于隔行变色;end=""实现同行打印,print()实现换行

1.2 核心逻辑总结(分段)

  1. 循环本质:重复执行代码直到满足终止条件,for是“遍历式”(适合数据遍历),while是“条件式”(适合复杂逻辑)。
  2. 容器遍历:for...in可直接取容器元素;二级容器可通过“解包”(等长)或“嵌套循环”(不等长)遍历。
  3. range规则:range(start, end, step)生成整数序列,end取不到,step为负时逆向生成(如range(10,0,-1))。
  4. 图案打印:外层循环控行数,内层控列数;通过%判断列奇偶、//提取行号,实现隔行/隔列变色。
  5. 循环控制:pass仅占位;break终止当前循环;continue跳过当前轮次,需先更新循环变量。

二、完整详细讲解

2.1 for循环(从基础到进阶)

2.1.1 核心语法与基础遍历

for循环核心是“逐个取出容器元素”,语法:

for 变量 in 容器类型数据:执行代码
  • 案例1:遍历列表(逐行拆解运算)
listvar = ["李人称","陈宇","称号"]
for i in listvar:print(i)

运算过程:
① 第一次循环:i = 列表第1个元素“李人称” → 打印“李人称”;
② 第二次循环:i = 列表第2个元素“陈宇” → 打印“陈宇”;
③ 第三次循环:i = 列表第3个元素“称号” → 打印“称号”;
④ 列表无更多元素,循环终止。

  • 案例2:遍历字典(默认遍历键)
dictvar = {"top":"程咬金","middle":"甄姬"}
for i in dictvar:print(i)

运算过程:
① 第一次循环:i = 字典键“top” → 打印“top”;
② 第二次循环:i = 字典键“middle” → 打印“middle”;
③ 字典无更多键,循环终止。

2.1.2 range函数(生成整数序列)

range(start, end, step)start默认0,step默认1,end始终取不到。

  • 案例1:单参数(range(10))
for i in range(10):print(i)

运算过程:生成序列[0,1,2,3,4,5,6,7,8,9] → 循环10次,依次打印0~9。

  • 案例2:三参数(逆向,range(10,0,-1))
for i in range(10,0,-1):print(i)

运算过程:step=-1(逆向)→ 生成序列[10,9,8,...,1] → 循环10次,依次打印10~1。

2.1.3 二级容器遍历
  • 等长二级容器(解包)
listvar = [("王健林","王思聪"),("马云","马化腾")]
for a,b in listvar:print(a,b)

运算过程:
① 第一次循环:a,b = ("王健林","王思聪") → 打印“王健林 王思聪”;
② 第二次循环:a,b = ("马云","马化腾") → 打印“马云 马化腾”;
③ 循环终止。

  • 不等长二级容器(嵌套循环)
listvar = [("王健林","王思聪"),("马云",)]
for i in listvar:for j in i:print(j)

运算过程:
① 外层第1次:i = ("王健林","王思聪") → 内层循环:

  • 内层第1次:j=王健林 → 打印;
  • 内层第2次:j=王思聪 → 打印;
    ② 外层第2次:i = ("马云",) → 内层循环:
  • 内层第1次:j=马云 → 打印;
    ③ 循环终止。

2.2 while循环(条件式循环)

2.2.1 核心语法
初始化循环变量
while 条件:执行代码更新循环变量(避免死循环)
  • 案例:打印1~4(遇到5终止)
i = 1
while i<=10:if i == 5:breakprint(i)i+=1

运算过程:
i=1 → 条件成立 → i≠5 → 打印1 → i=2
i=2 → 条件成立 → i≠5 → 打印2 → i=3
i=3 → 条件成立 → i≠5 → 打印3 → i=4
i=4 → 条件成立 → i≠5 → 打印4 → i=5
i=5 → 条件成立 → i=5 → 执行break → 循环终止;
最终输出:1 2 3 4。

2.2.2 循环控制关键字
  • continue(跳过当前循环,需先更新变量)
i = 1
while i<=10:if i == 5:i+=1  # 必须先自增,否则死循环continueprint(i)i+=1

运算过程(关键步骤):
i=5 → 执行i+=1(i=6)→ continue(跳过打印);
i=6 → 条件成立 → 打印6 → i=7
...(依次到i=10)→ 最终输出:1 2 3 4 6 7 8 9 10。

  • pass:仅占位,无实际逻辑
if True:pass  # 暂时不写逻辑,避免语法错误

2.3 双层循环(打印图案)

2.3.1 十行十列小星星
j = 0  # 外层控行
while j<10:i = 0  # 内层控列while i<10:print("*",end="")  # 同行打印i+=1print()  # 换行j+=1

运算过程:
① 外层j=0 → 内层i从0~9 → 打印10个* → 换行 → j=1
② 外层j=1 → 内层重复 → 打印10个* → 换行 → j=2
...(外层j从0~9)→ 最终打印10行,每行10个*。

2.3.2 隔列变色小星星
j = 0
while j<10:i = 0while i<10:if i % 2 == 0:  # 列数偶数→★,奇数→☆print("★",end="")else:print("☆",end="")i+=1print()j+=1

运算过程(第1行):
i=0→★,i=1→☆,i=2→★...i=9→☆ → 第1行输出:★☆★☆★☆★☆★☆;
外层循环执行10次 → 10行均为隔列变色。

三、应用场景及案例(带详细运算过程)

3.1 场景1:数据筛选/遍历(日常数据处理)

3.1.1 案例:筛选1~100中不含数字4的数
i = 1
while i<=100:num = str(i)if '4' in num:i+=1continueprint(i)i+=1

运算过程(关键步骤):
i=4num="4" → 含4 → i=5continue(跳过打印);
i=14num="14" → 含4 → i=15continue
i=40num="40" → 含4 → i=41continue
i=99num="99" → 不含4 → 打印99 → i=100
i=100num="100" → 不含4 → 打印100 → i=101
i=101 → 条件不成立 → 循环终止;
最终输出:1~100中所有不含4的数字。

3.1.2 案例:遍历字典提取键值对
dictvar = {"top":"程咬金","middle":"甄姬","bottom":"孙尚香"}
for key in dictvar:print(f"位置{key}的英雄:{dictvar[key]}")

运算过程:
① 第一次循环:key="top" → 打印“位置top的英雄:程咬金”;
② 第二次循环:key="middle" → 打印“位置middle的英雄:甄姬”;
③ 第三次循环:key="bottom" → 打印“位置bottom的英雄:孙尚香”;
④ 循环终止。

3.2 场景2:自定义图案打印(可视化输出)

3.2.1 案例:单层循环实现十行十列隔行变色星星
i = 0
while i<100:if i // 10 % 2 == 0:  # i//10提取行号(0~9),偶数行→★print("★",end="")else:print("☆",end="")if i % 10 == 9:  # 每10个字符换行print()i+=1

运算逻辑拆解:

  • i//10:地板除10 → 提取行号(如i=0~9→0i=10~19→1,...i=90~99→9);
  • i%10:取余10 → 判断是否到列尾(i=9/19/.../99时换行);
    运算过程(第1行):
    i=0~9 → 行号0(偶数)→ 全打印★ → i=9时换行;
    第2行:i=10~19 → 行号1(奇数)→ 全打印☆ → i=19时换行;
    ...(依次到第10行)→ 最终输出:偶数行全★,奇数行全☆。

3.3 场景3:批量计算(自动化运算)

3.3.1 案例:计算1~100的累加和
sum_num = 0
i = 1
while i<=100:sum_num += ii+=1
print(f"1~100累加和:{sum_num}")

运算过程:
i=1sum_num=0+1=1i=2
i=2sum_num=1+2=3i=3
...(持续累加);
i=100sum_num=前99数和+100=5050i=101
i=101 → 条件不成立 → 打印“1~100累加和:5050”;
(验证:1~n累加和公式n*(n+1)/2100*101/2=5050,结果正确)。



07、字符串函数_菱形小星星

全文总结

表格版核心知识点汇总

模块名称 核心知识点 关键逻辑/方法
菱形小星星(双层循环) 双层while循环嵌套、行数/空格/星星数量的数学关系、上下半部分循环控制 1. 总行数:n//2+1;2. 空格数=总行数-当前行;3. 星星数=当前行×2-1;4. 分上下半部分循环打印
字符串相关函数 字符串大小写/查找/统计/判断/分割拼接/替换/填充去除空白等操作 1. 大小写:capitalize/upper/lower/swapcase;2. 查找:find/index;3. 分割拼接:split/join;4. 替换:replace等
双层循环经典程序 三位数吉利数字筛选、99乘法表(多方向)、百钱买百鸡(穷举法) 1. 吉利数字:拆解个位/十位/百位判断;2. 乘法表:双层循环+空格控制方向;3. 百钱买百鸡:三层循环穷举满足条件的组合

文字版补充总结

  1. 循环类模块(菱形、吉利数字、乘法表、百钱买百鸡):核心是多层循环嵌套,外层控制“行/主维度”,内层控制“列/子维度”;结合数学逻辑(如数字位数拆解、行列数量关系)或穷举法(遍历所有可能值筛选结果),实现格式化输出/条件筛选,是批量处理、规律生成的核心技巧。
  2. 字符串处理模块:围绕字符串“查、改、判、分/合”四大核心展开,不同函数对应不同文本处理场景;需重点关注函数参数(如find的起止索引、replace的替换次数)和返回值特性(如find找不到返回-1,index找不到报错),是文本清洗、解析的基础。

完整详细输出及详细运算过程

一、菱形小星星(双层循环实现)

1. 核心逻辑拆解(以n=11为例)

目标:打印对称菱形,最大宽度11。

  • 总行数(上半部分):hang = n//2 +1 = 11//2+1=6(上半6行,下半反向打印6行);
  • 空格数:当前行i的空格数 = hang -i(空格让星星居中);
  • 星星数:当前行i的星星数 = i×2-1(行数越多,星星越多)。
2. 基础版代码+逐行运算
# 步骤1:定义基础参数
n = 11
hang = n // 2 + 1  # 计算上半行数,结果=6
print("上半部分总行数:", hang)  # 输出6# 步骤2:打印上半部分(i从1到6)
i = 1
while i <= hang:# 子步骤2.1:打印空格kongge = hang - i  # i=1→5个空格;i=2→4个;…i=6→0个while kongge > 0:print(" ", end="")  # 不换行,连续打印空格kongge -= 1  # 空格数减1至0# 子步骤2.2:打印星星j = 1while j <= i*2 -1:  # i=1→1个;i=2→3个;…i=6→11个print("*", end="")j += 1# 子步骤2.3:换行(完成一行)print()i += 1  # 行号+1# 步骤3:打印下半部分(i从6到1)
i = hang
while i > 0:# 子步骤3.1:打印空格(逻辑同上)kongge = hang - i  # i=6→0个;i=5→1个;…i=1→5个while kongge > 0:print(" ", end="")kongge -= 1# 子步骤3.2:打印星星(逻辑同上)j = 1while j <= i*2 -1:print("*", end="")j += 1# 子步骤3.3:换行print()i -= 1  # 行号-1至0
3. 关键行运算示例
  • i=1(上半第1行):空格=6-1=5 → 打印5个空格;星星=1×2-1=1 → 打印1个* → 输出: *
  • i=6(上半第6行):空格=6-6=0 → 无空格;星星=6×2-1=11 → 输出:***********
  • i=5(下半第1行):空格=6-5=1 → 1个空格;星星=5×2-1=9 → 输出: *********
4. 简化版代码(字符串乘法)
i = 1
while i <= hang:kongge = hang - iprint(" " * kongge, end="")  # 空格=字符×数量,替代内层循环print("*" * (i*2-1), end="")  # 星星=字符×数量print()i += 1i = hang
while i > 0:kongge = hang - iprint(" " * kongge, end="")print("*" * (i*2-1), end="")print()i -= 1

二、字符串相关函数(分类解析+运算示例)

函数 功能 示例代码 运算过程&结果
capitalize 首字母大写,其余小写 strvar = "we are FamilY"
res = strvar.capitalize()
原字符串→首字母w大写,其余小写 → We are family
upper 全大写 res = strvar.upper() 所有字母转大写 → WE ARE FAMILY
lower 全小写 res = strvar.lower() 所有字母转小写 → we are family
len 字符串长度 res = len(strvar) 字符数:13(含空格)→ 结果=13
count 统计元素次数 res = strvar.count("a") "a"出现2次 → 结果=2
find 查找首次索引(找不到返回-1) strvar = "oh Father"
res = strvar.find("Father")
"Father"首字符F在索引3 → 结果=3
split 分割为列表 strvar = "you,can"
res = strvar.split(",",1)
按","分割1次 → ["you","can"]
join 列表拼接为字符串 lst = ["you","can"]
res = "&".join(lst)
用"&"连接 → you&can
replace 替换字符 strvar = "有没有,有没有"
res = strvar.replace("有没有","真没有",1)
替换1次 → 真没有,有没有
strip 去除首尾字符 strvar = "@zhangsan"
res = strvar.strip("@")
去除首尾@ → zhangsan

三、双层循环经典程序

1. 吉利数字(100~999)
核心逻辑:拆解三位数的个位/十位/百位
  • 个位:i % 10;十位:i//10%10;百位:i//100
代码+运算示例
i = 100
while i <= 999:ge = i % 10    # 个位shi = i//10%10 # 十位bai = i//100   # 百位# 条件1:三个数字相同(如111)if shi == ge and shi == bai:print(i)# 条件2:连续递增(如123)if shi == ge-1 and shi == bai+1:print(i)# 条件3:连续递减(如321)if shi == ge+1 and shi == bai-1:print(i)i += 1

运算示例(i=123):

  • 个位=3,十位=2,百位=1;
  • 条件2:2=3-1 且 2=1+1 → 满足,打印123。
2. 99乘法表(右对齐版)
i = 1
while i <= 9:# 步骤1:打印空格(控制右对齐)k = 9 - i  # i=1→8个空格块;i=2→7个while k > 0:print("       ", end="")  # 每个空格块占7字符k -= 1# 步骤2:打印乘法表达式j = 1while j <= i:print("%d*%d=%2d " % (i,j,i*j), end="")  # %2d:占2字符对齐j += 1print()i += 1

运算示例(i=3):

  • 空格数=9-3=6 → 6×7=42个空格;
  • j=1→31= 3;j=2→32= 6;j=3→3*3= 9;
  • 该行输出:(42个空格)3*1= 3 3*2= 6 3*3= 9
3. 百钱买百鸡(穷举法)
核心逻辑:x(公鸡)+y(母鸡)+z(小鸡)=100;x+3y+0.5z=100。
x = 0
while x <= 100:y = 0while y <= 33:  # 母鸡最多33只(3×33=99)z = 0while z <= 100:if (x+y+z==100) and (x+3*y+0.5*z==100):print(f"公鸡{x},母鸡{y},小鸡{z}")z += 1y += 1x += 1

运算示例(有效组合:x=25,y=0,z=75):

  • 总数:25+0+75=100 → 满足;
  • 金额:25+0+75×0.5=62.5 → 不满足;
  • 正确组合(如x=0,y=20,z=80):
    总数=0+20+80=100;金额=0+60+40=100 → 满足,打印该组合。

应用场景及案例、详细运算过程

一、循环类应用场景

应用场景 场景说明 案例+运算过程
格式化图形输出 生成控制台装饰/报表边框 案例:打印菱形星星
运算过程:
1. 确定总行数hang = n//2+1
2. 外层循环控制行i,内层循环打印空格(hang-i个)和星星(2i-1个);
3. 上半部分i从1到hang,下半部分ihang到1,最终形成对称菱形。适用于控制台海报、日志装饰。
数据穷举筛选 资源分配/组合筛选 案例:100元买100件商品(单价1/3/0.5元)
运算过程:
1. 定义变量x/y/z代表三种商品数量;
2. 三层循环遍历x(0100)、y(033)、z(0~100);
3. 筛选满足x+y+z=100x+3y+0.5z=100的组合,适用于促销活动的商品组合计算。
数学规律生成 生成练习题/计算表格 案例:99乘法表(右对齐)
运算过程:
1. 外层循环i控制被乘数(1~9);
2. 先打印9-i个空格块(每个7字符)实现右对齐;
3. 内层循环j控制乘数(1~i),打印i*j的结果,适用于小学生乘法练习题生成。

二、字符串函数应用场景

应用场景 场景说明 案例+运算过程
文本清洗 用户输入格式统一 案例:清洗用户名
代码:
username = " @LiSi123 "
clean_name = username.strip().strip("@").lower()
运算过程:
1. strip() → 去除首尾空格 → @LiSi123
2. strip("@") → 去除@ → LiSi123
3. lower() → 转小写 → lisi123
适用于用户注册时的格式校验。
文本替换 文案敏感词批量修改 案例:替换文案中的“假货”为“仿品”
代码:
content = "这款不是假货,不是假货!"
new_content = content.replace("假货", "仿品", 1)
运算过程:
原内容→替换1次“假货”→这款不是仿品,不是假货!
适用于电商文案审核、批量修改文档。
文本解析 解析CSV/日志数据 案例:解析CSV用户数据
代码:
csv_str = "王五,30,13900139000"
user_info = csv_str.split(",")
info_str = "-".join(user_info)
运算过程:
1. split(",") → 分割为列表["王五","30","13900139000"]
2. join → 拼接为王五-30-13900139000
适用于日志分析、CSV数据导入。
合法性校验 表单输入校验 案例:校验11位纯数字手机号
代码:
phone = "13800138000"
is_valid = phone.isdecimal() and len(phone)==11
运算过程:
1. isdecimal() → 纯数字→True;
2. len(phone) → 11→True;
3. 逻辑与→is_valid=True
适用于手机号/验证码校验。


08、列表相关操作_深浅拷贝_字符串格式化

全文总结

一、核心模块总结(表格版)

模块 核心知识点 关键说明
字符串格式化(format) 1. 传参方式:顺序、索引、关键字、容器(列表/元组/字典)
2. 填充字符:^(居中)、>(居右)、<(居左),配合填充符+长度控制格式
3. 特殊占位符::d(整型)、:f(浮点型)、:s(字符串)、:,(金钱格式)
替代传统字符串拼接,灵活控制输出格式;填充字符可美化对齐,特殊占位符适配不同数据类型
列表基础操作 1. 拼接(+)、重复(*
2. 切片:[开始索引:结束索引:间隔值](左闭右开,支持正向/逆向索引)
3. 获取:索引/len()
4. 修改:单索引/切片(需赋值可迭代数据,带间隔切片需匹配元素个数)
5. 删除:del + 索引/切片
列表是可变序列,支持增删改查;切片是核心操作,逆向切片需设置负间隔
列表相关函数 增:append()(末尾加)、insert()(指定索引前加)、extend()(迭代追加)
删:pop()(按索引删,返回值)、remove()(按值删)、clear()(清空)
查:index()(找索引)、count()(统计次数)
排序/反转:sort()(正/倒序)、reverse()(反转)
函数化操作提升效率;sort默认升序,reverse=True降序;index找不到值会报错
浅拷贝与深拷贝 1. 直接赋值:新旧列表共用内存,修改联动
2. 浅拷贝(copy.copy()/列表.copy()):仅拷贝一级元素,二级容器共用
3. 深拷贝(copy.deepcopy()):所有层级独立拷贝,互不影响
解决“赋值后联动修改”问题;深拷贝适配嵌套容器(列表套列表/字典)
元组特殊修改 一级元组不可变;若元组嵌套列表(二级容器),可修改列表内的值 元组是不可变序列,但嵌套可变类型时,可变类型内部可修改

二、核心逻辑总结(分段版)

  1. 字符串格式化:核心是通过format灵活传递参数并控制输出格式,相比直接拼接更易维护,适配多场景的字符串展示需求。
  2. 列表操作:列表作为可变序列,支持基础的拼接/重复/切片,也支持函数化的增删改查;切片是“左闭右开”规则,修改/删除时切片赋值需满足可迭代/元素个数匹配要求。
  3. 拷贝机制:直接赋值仅传内存地址,浅拷贝只拆一级容器,深拷贝完全独立所有层级;实际开发中需根据是否嵌套容器选择拷贝方式。
  4. 元组特性:一级不可变,二级可变(嵌套列表),兼顾“不可变”的稳定性和“嵌套可变”的灵活性。

完整详细讲解

1. 字符串格式化(format)

1.1 基础传参方式
  • 顺序传参{}按顺序匹配format内的参数
    strvar = "{}给{}一个大大的拥抱"
    res = strvar.format("蔡松松","尹棉")
    # 运算过程:第一个{}匹配"蔡松松",第二个{}匹配"尹棉"
    print(res)  # 输出:蔡松松给尹棉一个大大的拥抱
    
  • 索引传参{索引}指定匹配format内的参数位置
    strvar = "{1}向{0}开了一枪"
    res = strvar.format("重汽彩","徐云波")
    # 运算过程:{1}匹配索引1的"徐云波",{0}匹配索引0的"重汽彩"
    print(res)  # 输出:徐云波向重汽彩开了一枪
    
  • 关键字传参{关键字}匹配format内的关键字参数
    strvar = "{wangwei}给{lizeng}抛媚眼"
    res = strvar.format(lizeng="李增",wangwei="王维")
    # 运算过程:{wangwei}匹配"王维",{lizeng}匹配"李增"
    print(res)  # 输出:王维给李增抛媚眼
    
  • 容器传参:支持列表/元组({索引[子索引]})、字典({关键字[键名]},键名不加引号)
    # 列表+元组
    strvar = "{0[1]}向{1[1]}扫射"
    res = strvar.format(["吴家豪","刘欢"],("李毅","蔡文君"))
    # 运算过程:0[1]取列表索引1的"刘欢",1[1]取元组索引1的"蔡文君"
    print(res)  # 输出:刘欢向蔡文君扫射# 字典
    strvar = "{group2[wjm]}向{group1[2]}扫射"
    res = strvar.format(group1=["吴家豪","刘欢","弄康品"],group2={"wjm":"吴嘉敏"})
    # 运算过程:group2[wjm]取字典键wjm的"吴嘉敏",group1[2]取列表索引2的"弄康品"
    print(res)  # 输出:吴嘉敏向弄康品扫射
    
1.2 填充字符与特殊占位符
  • 填充字符{值:填充符^/>/<长度}控制对齐和补位
    strvar = "{who:*^10}在医院{something:>>10}"
    res = strvar.format(who="陈学斌",something="喝疫苗")
    # 运算过程:
    # who:*^10 → "陈学斌"居中,总长度10,补* → ***陈学斌****
    # something:>>10 → "喝疫苗"居右,总长度10,补> → >>>>>>>喝疫苗
    print(res)  # 输出:***陈学斌****在医院>>>>>>>喝疫苗
    
  • 特殊占位符
    # :d 整型占位符
    strvar = "买了{:^5d}个娃娃"
    res = strvar.format(2)
    # 运算过程:2按整型居中,总长度5 →  2(前后各两个空格)
    print(res)  # 输出:买了  2   个娃娃# :.2f 浮点型(保留2位小数,四舍五入)
    strvar = "工资{:.2f}元"
    res = strvar.format(9.9999)
    # 运算过程:9.9999四舍五入保留2位 → 10.00
    print(res)  # 输出:工资10.00元# :, 金钱占位符
    strvar = "金额{:,}"
    res = strvar.format(123456789)
    # 运算过程:按千分位分隔 → 123,456,789
    print(res)  # 输出:金额123,456,789
    

2. 列表基础操作

2.1 拼接与重复
# 拼接(+):合并两个列表/元组
lst1 = ["欧阳欢","聂康亮"]
lst2 = ["张亚军","李人称"]
res = lst1 + lst2
# 运算过程:lst1的元素 + lst2的元素 → 新列表
print(res)  # 输出:['欧阳欢', '聂康亮', '张亚军', '李人称']# 重复(*):列表元素重复n次
lst = [1,2,3]
res = lst * 3
# 运算过程:[1,2,3] ×3 → [1,2,3,1,2,3,1,2,3]
print(res)  # 输出:[1,2,3,1,2,3,1,2,3]
2.2 切片(核心)

语法:列表[开始索引:结束索引:间隔值](左闭右开,索引从0开始,逆向索引从-1开始)

listvar = ["朱万明","党朝飞","徐梦薇","呼和金","陈学斌","彭金成","晨光要","陈原液","刘晨宇","擦松松"]# 从开始索引截取到末尾
res = listvar[3:]
# 运算过程:索引3(呼和金)到最后 → ['呼和金','陈学斌','彭金成','晨光要','陈原液','刘晨宇','擦松松']
print(res)# 从开头截取到结束索引-1
res = listvar[:7]
# 运算过程:索引0到6(晨光要) → ['朱万明','党朝飞','徐梦薇','呼和金','陈学斌','彭金成','晨光要']
print(res)# 正向间隔切片
res = listvar[::3]
# 运算过程:索引0→3→6→9 → ['朱万明','呼和金','晨光要','擦松松']
print(res)# 逆向切片(间隔-1)
res = listvar[::-1]
# 运算过程:从最后一个元素(-1)倒序取所有 → ['擦松松','刘晨宇','陈原液','晨光要','彭金成','陈学斌','呼和金','徐梦薇','党朝飞','朱万明']
print(res)
2.3 获取、修改、删除
# 获取:通过索引/len()
listvar = ["王青","为陈雄","曹建峰","吴家豪","重汽彩"]
res = listvar[-1]  # 逆向索引-1取最后一个元素
res = listvar[len(listvar)-1]  # len=5 → 5-1=4 → 索引4的"重汽彩"
print(res)  # 输出:重汽彩# 修改:单索引/切片
listvar[3] = "李杰"  # 索引3的"吴家豪"改为"李杰"
# 运算后:['王青','为陈雄','曹建峰','李杰','重汽彩']listvar[3:5] = (1,2)  # 切片3-5(左闭右开,取索引3、4)替换为(1,2)
# 运算后:['王青','为陈雄','曹建峰',1,2]# 带间隔的切片修改(元素个数需匹配)
listvar[::2] = ["徐云波","刘欢","曾文"]  # 切片0,2,4 → 替换为3个值
# 运算后:['徐云波','为陈雄','刘欢',1,'曾文']# 删除:del + 索引/切片
del listvar[-2]  # 删除索引-2的元素(1)
# 运算后:['徐云波','为陈雄','刘欢','曾文']
del listvar[1:3]  # 删除索引1-2的元素
# 运算后:['徐云波','曾文']

3. 列表相关函数

3.1 增加元素
listvar = ["曾文","李毅","银民"]# append:末尾添加单个元素
listvar.append("吴嘉敏")
# 运算过程:末尾追加 → ['曾文','李毅','银民','吴嘉敏']# insert:指定索引前插入
listvar.insert(1,"无照")
# 运算过程:索引1前插入 → ['曾文','无照','李毅','银民','吴嘉敏']# extend:迭代追加(可迭代对象拆分为单个元素)
listvar.extend(["猪八戒","唐僧"])
# 运算过程:拆分为"猪八戒""唐僧"追加 → ['曾文','无照','李毅','银民','吴嘉敏','猪八戒','唐僧']
3.2 删除元素
listvar = ["曾文","李毅","曾文","银民"]# pop:按索引删(默认最后一个),返回删除值
res = listvar.pop(2)  # 删除索引2的"曾文"
# 运算过程:删除后列表→['曾文','李毅','银民'],res→"曾文"# remove:按值删(默认第一个匹配值)
listvar.remove("曾文")
# 运算过程:删除第一个"曾文" → ['李毅','银民']# clear:清空列表
listvar.clear()
# 运算过程:列表变为空 → []
3.3 其他操作(查/排序/反转)
listvar = ["曾文","李毅","陈宇","陈宇","蔡文姬"]# index:找值的索引(可指定起始/结束范围)
res = listvar.index("陈宇",3)  # 从索引3开始找"陈宇"
# 运算过程:索引3的"陈宇" → res=3# count:统计值出现次数
res = listvar.count("陈宇")
# 运算过程:"陈宇"出现2次 → res=2# sort:排序(默认升序,reverse=True降序)
listvar = [99,0,-1,100]
listvar.sort()  # 升序 → [-1,0,99,100]
listvar.sort(reverse=True)  # 降序 → [100,99,0,-1]# reverse:反转列表
listvar = [1,2,3]
listvar.reverse()
# 运算过程:反转 → [3,2,1]

4. 浅拷贝与深拷贝

import copy# 直接赋值:共用内存,修改联动
lst1 = [1,2,3]
lst2 = lst1
lst1.append(4)
# 运算过程:lst1和lst2指向同一内存 → lst2=[1,2,3,4]# 浅拷贝:仅拷贝一级元素
lst1 = [1,2,3,[4,5]]
lst2 = copy.copy(lst1)
lst1[-1].append(6)  # 修改二级列表
# 运算过程:一级元素独立,二级列表共用 → lst2=[1,2,3,[4,5,6]]# 深拷贝:所有层级独立
lst1 = [1,2,3,[4,5]]
lst2 = copy.deepcopy(lst1)
lst1[-1].append(6)
# 运算过程:所有层级独立 → lst2=[1,2,3,[4,5]]

5. 元组特殊修改

# 一级元组不可改,二级列表可改
tuplevar = (1,2,(3,[9,"aa",11]))
tuplevar[2][1][1] = "bb"
# 运算过程:
# 1. 取tuplevar[2] → (3,[9,"aa",11])
# 2. 取[1] → [9,"aa",11]
# 3. 改[1]为"bb" → 最终元组:(1,2,(3,[9,"bb",11]))
print(tuplevar)

应用场景及案例

1. 字符串格式化:用户信息展示

场景:格式化输出用户的姓名、年龄、薪资(带千分位)

# 需求:展示"姓名:XXX(居中,补*),年龄:XX岁,薪资:XXX,XXX元"
def show_user_info(name, age, salary):strvar = "姓名:{:*^8},年龄:{:d}岁,薪资:{:,}元"res = strvar.format(name, age, salary)# 运算过程(示例:name="张三", age=25, salary=12345):# {:*^8} → ***张三***(居中,总长度8)# {:d} → 25(整型)# {:,} → 12,345(千分位)print(res)show_user_info("张三",25,12345)
# 输出:姓名:***张三***,年龄:25岁,薪资:12,345元

2. 列表操作:商品购物车管理

场景:添加商品、删除商品、统计商品数量

# 购物车管理
cart = ["苹果","香蕉","苹果","橙子"]# 1. 添加商品(append)
cart.append("葡萄")
# 运算:cart → ['苹果','香蕉','苹果','橙子','葡萄']# 2. 删除指定商品(remove)
cart.remove("香蕉")
# 运算:cart → ['苹果','苹果','橙子','葡萄']# 3. 统计某商品数量(count)
apple_count = cart.count("苹果")
# 运算:apple_count → 2# 4. 清空购物车(clear)
cart.clear()
# 运算:cart → []print(f"苹果数量:{apple_count},最终购物车:{cart}")
# 输出:苹果数量:2,最终购物车:[]

3. 拷贝机制:数据备份

场景:备份用户数据(嵌套字典),修改原数据不影响备份

import copy# 原用户数据(嵌套字典)
user_data = {"name":"李四","info":{"age":30,"salary":50000}}# 浅拷贝(仅一级,修改二级会联动)
backup1 = copy.copy(user_data)
user_data["info"]["salary"] = 60000
# 运算:backup1["info"]["salary"] → 60000(联动修改)# 深拷贝(完全独立)
backup2 = copy.deepcopy(user_data)
user_data["info"]["salary"] = 70000
# 运算:backup2["info"]["salary"] → 60000(不受影响)print(f"浅拷贝备份:{backup1}")
print(f"深拷贝备份:{backup2}")
# 输出:
# 浅拷贝备份:{'name':'李四','info':{'age':30,'salary':70000}}
# 深拷贝备份:{'name':'李四','info':{'age':30,'salary':60000}}

4. 元组+列表:固定模板动态修改

场景:考试模板(固定题目,动态修改答案)

# 考试模板(元组:固定题目,列表:动态答案)
exam = ("1+1=?", ["2"],"2+3=?", ["5"])# 修改第二题答案
exam[3][0] = "8"  # 模拟改错答案
# 运算过程:
# exam[3] → ["5"]
# exam[3][0] = "8" → ["8"]
# 最终exam → ("1+1=?", ["2"],"2+3=?", ["8"])print(f"考试题目:{exam[0]} 答案:{exam[1][0]}")
print(f"考试题目:{exam[2]} 答案:{exam[3][0]}")
# 输出:
# 考试题目:1+1=? 答案:2
# 考试题目:2+3=? 答案:8


09、文件操作_集合_字典_相关函数_文件函数

全文总结

模块 核心知识点 关键说明
文件操作 1. 打开/关闭文件(open/close、with语法)
2. 文件模式(r/w/a/r+/w+/a+/rb/wb)
3. 核心函数(read/write/seek/tell/readline/readlines/writelines/truncate/flush)
4. 编码转换(encode/decode)
1. 文本模式(r/w/a等)需指定encoding,二进制模式(rb/wb)无需
2. 指针操作(seek/tell)按字节,读写函数(read/readline)按字符
3. with语法自动关闭文件,推荐使用
字典操作 1. 增([]赋值、fromkeys)
2. 删(pop/popitem/clear)
3. 改(update)
4. 查(get/keys/values/items)
1. pop/get可设置默认值避免报错
2. fromkeys创建字典时,可变默认值(如列表)会被所有键共享
3. items()返回键值对元组迭代对象
集合操作 1. 交差并补(intersection/difference/union/symmetric_difference)
2. 增(add/update)
3. 删(clear/pop/remove/discard)
4. 冰冻集合(frozenset)
1. 集合无序、去重,无改/查操作
2. discard删除不存在元素不报错,remove会报错
3. 冰冻集合不可修改,仅支持交差并补

完整详细讲解

一、文件操作

文件操作核心是“打开-操作-关闭”,Python通过open()获取文件句柄,完成操作后需关闭(或用with自动关闭)。

1. 基础读写(文本模式)
  • 写操作(w模式):覆盖原有内容,无文件则创建

    # 步骤1:打开文件(创建文件句柄fp)
    fp = open("0621.txt",mode="w",encoding="utf-8")
    # 步骤2:写入内容
    fp.write("把大象塞进冰箱里")
    # 步骤3:关闭文件(刷新缓冲区,写入硬盘)
    fp.close()
    

    运算结果:生成0621.txt,内容为“把大象塞进冰箱里”。

  • 读操作(r模式):读取文件内容,文件不存在则报错

    # 步骤1:打开文件
    fp = open("0621.txt",mode="r",encoding="utf-8")
    # 步骤2:读取全部内容
    res = fp.read()
    # 步骤3:关闭文件
    fp.close()
    print(res)  # 运算结果:把大象塞进冰箱里
    
2. 二进制模式(读写图片/视频)

二进制模式无需指定encoding,内容以字节流(bytes)处理:

  • 写操作(wb)
    fp = open("0621_1.txt",mode="wb")
    # 字符串转字节流(utf-8编码,中文占3字节)
    res = "吴嘉敏真漂亮".encode("utf-8")
    fp.write(res)
    fp.close()
    # 运算结果:文件内容为 b'\xe5\x90\xb4\xe5\x98\x89\xe6\x95\x8f\xe7\x9c\x9f\xe6\xbc\x82\xe4\xb8\x87'
    
  • 读操作(rb)
    fp = open("0621_1.txt",mode="rb")
    res = fp.read()
    fp.close()
    print(res)  # 运算结果:b'\xe5\x90\xb4\xe5\x98\x89\xe6\x95\x8f\xe7\x9c\x9f\xe6\xbc\x82\xe4\xb8\x87'
    # 字节流转字符串(解码)
    res2 = res.decode("utf-8")
    print(res2)  # 运算结果:吴嘉敏真漂亮
    
3. 可读可写模式(r+/w+/a+)
模式 核心特点
r+ 先读后写,指针默认在开头;先写会覆盖字符,需用seek(0,2)移到末尾写
w+ 先清空文件再写,读取需先seek(0)移到开头
a+ 强制在末尾追加写,读取需先seek(0)

示例(r+先写后读):

fp = open("0621_4.txt",mode="r+",encoding="utf-8")
fp.seek(0,2)  # 步骤1:指针移到文件末尾
fp.write("123")  # 步骤2:追加写入
fp.seek(0)  # 步骤3:指针移回开头
res = fp.read()  # 步骤4:读取全部内容
fp.close()
print(res)  # 运算结果:原有内容+123(如原内容为abc,结果为abc123)
4. 核心函数
  • seek(字节数):调整指针位置(utf-8中中文3字节、英文1字节)
    fp = open("0621_7.txt",mode="r+",encoding="utf-8")
    fp.seek(3)  # 指针移到第3字节
    res = fp.tell()  # 获取当前指针左侧字节数
    print(res)  # 运算结果:3
    fp.close()
    
  • readline(字符数):读取一行内容,参数为字符数
    with open("0621_12",mode="r",encoding="utf-8") as fp:res = fp.readline(5)  # 读取当前行前5个字符print(res)  # 运算结果:若行内容为"1sdfsdaf",输出"1sdfs"
    
  • readlines():按行读取到列表,去除换行符
    with open("0621_12",mode="r",encoding="utf-8") as fp:listvar = fp.readlines()print(listvar)  # 运算结果:['1sdfsdaf\n', '2sdafsadfsdafasdf\n', ...]lst = [i.strip() for i in listvar]print(lst)  # 运算结果:['1sdfsdaf', '2sdafsadfsdafasdf', ...]
    
  • writelines():写入可迭代的字符串
    with open("0621_13",mode="w",encoding="utf-8") as fp:listvar = ["李杰大帅锅\n","王维大美女\n"]fp.writelines(listvar)  # 运算结果:文件写入两行内容
    
  • truncate(字节数):截取指定字节数并覆盖文件
    with open("0621_13",mode="r+",encoding="utf-8") as fp:fp.truncate(6)  # 截取前6字节(utf-8中6字节=2个中文/6个英文)# 运算结果:文件仅保留前6字节内容
    
  • flush():手动刷新缓冲区,立即写入硬盘
    fp = open("0621_10.txt",mode="w",encoding="utf-8")
    fp.write("abc")
    fp.flush()  # 无需close,内容已写入文件
    
5. with语法(自动关闭文件)
# 单文件操作
with open("0621_8.txt",mode="w",encoding="utf-8") as fp:fp.write("abcdefg")  # 运算结果:生成文件,内容为abcdefg# 多文件操作(复制图片)
with open("交叉并补.png",mode="rb") as fp1, open("fuzhi22.png",mode="wb") as fp2:res = fp1.read()  # 读取原图片字节流fp2.write(res)    # 写入新图片
# 运算结果:生成fuzhi22.png,与原图片一致

二、字典操作

字典是{key:value}键值对结构,key唯一且不可变,value可任意。

1. 增操作
  • []赋值:直接给新key赋值
    dictvar = {}
    dictvar["a"] = 10
    print(dictvar)  # 运算结果:{'a': 10}
    
  • fromkeys():批量创建字典(注意可变默认值共享)
    listvar = ["a","b"]
    res = {}.fromkeys(listvar,[])  # 默认值为列表(可变)
    res["a"].append(10)
    print(res)  # 运算结果:{'a': [10], 'b': [10]}(a/b共享列表)
    
2. 删操作
  • pop(key, 默认值):删除指定key,返回value
    dic = {"top":"亚瑟","middle":"上官婉儿"}
    res = dic.pop("middle")
    print(res)  # 运算结果:上官婉儿
    print(dic)  # 运算结果:{'top': '亚瑟'}
    # key不存在时返回默认值
    res = dic.pop("abcd","该键不存在")
    print(res)  # 运算结果:该键不存在
    
  • popitem():删除最后一个键值对,返回元组
    dic = {"top":"亚瑟","middle":"上官婉儿"}
    res = dic.popitem()
    print(res)  # 运算结果:('middle', '上官婉儿')
    print(dic)  # 运算结果:{'top': '亚瑟'}
    
  • clear():清空字典
    dic.clear()
    print(dic)  # 运算结果:{}
    
3. 改操作
  • update():批量更新(有key则改,无key则加)
    dictvar = {"gsz":"石阡","zzs":"鲁智深"}
    dic1 = {"ww":"xboyww","css":"猥琐骚男"}
    dictvar.update(dic1)
    print(dictvar)  # 运算结果:{'gsz': '石阡', 'zzs': '鲁智深', 'ww': 'xboyww', 'css': '猥琐骚男'}
    # 直接传键值对
    dictvar.update(cxb="渣男",hhj="备胎")
    print(dictvar)  # 运算结果:新增cxb、hhj键值对
    
4. 查操作
  • get(key, 默认值):获取value,key不存在返回默认值
    dictvar = {"gsz":"石阡","zzs":"鲁智深"}
    res = dictvar.get("wy","该键不存在")
    print(res)  # 运算结果:该键不存在
    
  • keys()/values()/items():返回可迭代对象
    dictvar = {"gsz":"石阡","zzs":"鲁智深"}
    print(dictvar.keys())  # 运算结果:dict_keys(['gsz', 'zzs'])
    print(dictvar.values())  # 运算结果:dict_values(['石阡', '鲁智深'])
    # 遍历键值对
    for k,v in dictvar.items():print(k,v)  # 运算结果:gsz 石阡;zzs 鲁智深
    

三、集合操作

集合是无序、去重的可变容器,无索引(无改/查操作),核心用于交差并补。

1. 交差并补(核心运算)
setvar1 = {"王文","刘德华","张学友"}
setvar2 = {"王宝强","马蓉","张学友"}
# 交集(共同元素)
res = setvar1 & setvar2  # 等价于 setvar1.intersection(setvar2)
print(res)  # 运算结果:{'张学友'}
# 差集(setvar1有,setvar2无)
res = setvar1 - setvar2  # 等价于 setvar1.difference(setvar2)
print(res)  # 运算结果:{'王文', '刘德华'}
# 并集(所有元素,去重)
res = setvar1 | setvar2  # 等价于 setvar1.union(setvar2)
print(res)  # 运算结果:{'王文', '刘德华', '张学友', '王宝强', '马蓉'}
# 对称差集(互不相同的元素)
res = setvar1 ^ setvar2  # 等价于 setvar1.symmetric_difference(setvar2)
print(res)  # 运算结果:{'王文', '刘德华', '王宝强', '马蓉'}
2. 增操作
  • add():添加单个元素
    setvar = {"蔡文君","陈宇"}
    setvar.add("李毅")
    print(setvar)  # 运算结果:{'蔡文君', '陈宇', '李毅'}
    
  • update():迭代添加
    setvar = {"蔡文君","陈宇"}
    setvar.update(["尹棉","李争"])
    print(setvar)  # 运算结果:{'蔡文君', '陈宇', '尹棉', '李争'}
    setvar.update("abc")  # 迭代字符串
    print(setvar)  # 运算结果:新增'a','b','c'
    
3. 删操作
  • pop():随机删除一个元素
    setvar = {"蔡文君","陈宇","李毅"}
    res = setvar.pop()
    print(res)  # 运算结果:随机(如'蔡文君')
    print(setvar)  # 运算结果:{'陈宇', '李毅'}
    
  • remove():删除指定元素(不存在则报错)
    setvar.remove("陈宇")
    print(setvar)  # 运算结果:{'李毅'}
    
  • discard():删除指定元素(不存在不报错)
    setvar.discard("李毅")
    print(setvar)  # 运算结果:set()
    setvar.discard("不存在")  # 无报错
    
  • clear():清空集合
    setvar.clear()
    print(setvar)  # 运算结果:set()
    
4. 冰冻集合(frozenset)

不可修改,仅支持交差并补:

fz1 = frozenset(["王伟","李杰","张学友"])
fz2 = frozenset(["张学友","曹建峰"])
res = fz1 & fz2
print(res)  # 运算结果:frozenset({'张学友'})
# fz1.add("ddd")  # 报错:AttributeError(不可修改)

应用场景及案例

一、文件操作应用场景

场景1:批量复制图片

需求:复制原图.png副本.png
案例代码

# 步骤1:读取原图片字节流
with open("原图.png",mode="rb") as fp1:img_data = fp1.read()
# 步骤2:写入新文件
with open("副本.png",mode="wb") as fp2:fp2.write(img_data)

运算结果:生成副本.png,与原图一致。

场景2:逐行读取大日志文件

需求:读取10GB日志文件,逐行处理
案例代码

with open("超大日志.txt",mode="r",encoding="utf-8") as fp:line = fp.readline()while line:print(line.strip())  # 去除换行符并打印line = fp.readline()

运算逻辑:逐行读取,仅加载一行到内存,避免内存溢出。

场景3:追加写入运行日志

需求:向运行日志.txt追加当日操作记录
案例代码

import datetime
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
log_content = f"{now}:用户登录成功\n"with open("运行日志.txt",mode="a+",encoding="utf-8") as fp:fp.write(log_content)fp.seek(0)print(fp.read())  # 运算结果:原有日志 + 新记录

二、字典操作应用场景

场景1:统计列表元素出现次数

需求:统计["苹果","香蕉","苹果","橙子","香蕉","苹果"]中水果次数
案例代码

fruits = ["苹果","香蕉","苹果","橙子","香蕉","苹果"]
count_dict = {}
for fruit in fruits:count_dict[fruit] = count_dict.get(fruit, 0) + 1
print(count_dict)  # 运算结果:{'苹果': 3, '香蕉': 2, '橙子': 1}

运算过程

  • 第1次循环:fruit=苹果 → count_dict["苹果"]=1
  • 第2次循环:fruit=香蕉 → count_dict["香蕉"]=1
  • 第3次循环:fruit=苹果 → count_dict["苹果"]=2
  • 最终完成统计。
场景2:批量更新用户信息

需求:更新用户字典,新增/修改属性
案例代码

user = {"name":"张三","age":20}
user.update(age=21, gender="男", address="北京")
print(user)  # 运算结果:{'name': '张三', 'age': 21, 'gender': '男', 'address': '北京'}

三、集合操作应用场景

场景1:列表去重

需求:去除[1,2,3,2,1,5,6,5]重复元素
案例代码

lst = [1,2,3,2,1,5,6,5]
new_lst = list(set(lst))
print(new_lst)  # 运算结果:[1,2,3,5,6](顺序随机)
场景2:筛选两个班级的共同参赛学生

需求:找出班级A和B都参加运动会的学生
案例代码

class_a = {"张三","李四","王五","赵六"}
class_b = {"王五","赵六","孙七","周八"}
common_students = class_a & class_b
print(common_students)  # 运算结果:{'王五', '赵六'}
场景3:筛选仅单班级参赛的学生

需求:找出仅在A或仅在B班参赛的学生
案例代码

only_one_class = class_a ^ class_b
print(only_one_class)  # 运算结果:{'张三', '李四', '孙七', '周八'}


10、函数_普通_默认_收集参数

全文总结

模块 核心知识点 关键规则
函数基础 定义(def 函数名():)、调用(函数名())、命名规范 命名用字母/数字/下划线,首字符非数字;可重复调用提升复用性
形参分类 普通形参、默认形参、普通收集形参(*args)、命名关键字形参、关键字收集形参(**kwargs) 默认形参需在普通形参后;命名关键字需用关键字实参调用;*args打包元组,**kwargs打包字典
实参分类 普通实参(位置实参)、关键字实参 关键字实参顺序可随意;普通形参+关键字实参混合时,关键字实参需在后
*/**魔术用法 定义处:打包;调用处:解包 调用时*解包容器为普通实参,**解包字典为关键字实参
参数定义顺序 普通形参 → 默认形参 → 普通收集形参 → 命名关键字形参 → 关键字收集形参 func(*args, **kwargs)可接收所有类型参数

补充分段总结

  1. 函数基础:函数是封装特定功能的代码块,通过def定义、函数名调用,核心价值是复用性。命名推荐下划线分割(如cheng_fa_biao_99),避免关键字和中文。
  2. 参数核心逻辑:形参是函数定义时的“占位符”,实参是调用时传入的“实际值”,需遵循“匹配规则”(位置/关键字)。
  3. 收集参数特性*args收集多余普通实参为元组,**kwargs收集多余关键字实参为字典,解决“参数个数不确定”问题;命名关键字参数强制使用关键字传参,提升代码可读性。
  4. */**解包/打包:定义时“打包”(把多参数整合为容器),调用时“解包”(把容器拆分给参数),灵活适配不同参数形式。

完整详细讲解

1. 函数基础:定义、调用、命名

核心语法
# 定义:def 函数名(): 封装功能代码
def func():print("文哥真帅")# 调用:函数名() 执行封装的代码
func()
运算过程
  1. 执行def func(): ...:在内存中创建名为func的函数对象,存储代码块print("文哥真帅")
  2. 执行func():调用函数,执行内部print语句,控制台输出:文哥真帅
命名规范示例(正确/错误)
# 正确:下划线分割、有意义
def cheng_fa_biao_99():  # 九九乘法表功能pass# 错误示例(不可运行)
# def 99chengfa():  # 首字符为数字
# def 乘法表():     # 包含中文
# def def():        # 使用关键字

2. 函数参数:形参 vs 实参

核心概念
  • 形参:函数定义处的参数(占位符),如def star(hang, lie):中的hang/lie
  • 实参:函数调用处的参数(实际值),如star(3,5)中的3/5
2.1 普通参数(位置参数)
# 定义:普通形参(hang/lie)
def star(hang, lie):i = 1while i <= hang:j = 1while j <= lie:print("*", end="")j += 1print()i += 1# 调用:普通实参(3,5)
star(3,5)
运算过程
  1. 调用star(3,5):实参3匹配形参hang5匹配lie
  2. 进入循环逻辑:
    • i=1j从1到5 → 打印***** → 换行。
    • i=2j从1到5 → 打印***** → 换行。
    • i=3j从1到5 → 打印***** → 换行。
  3. 控制台最终输出:
*****
*****
*****
2.2 默认形参
# 定义:给形参赋初始值(hang=10, lie=10)
def star(hang=10, lie=10):i = 1while i <= hang:j = 1while j <= lie:print("*", end="")j += 1print()i += 1# 调用:传实参覆盖默认值
star(12,14)
运算过程
  1. 实参12覆盖hang=1014覆盖lie=10
  2. 循环执行12次(i从1到12),每次打印14个*,最终输出12行14列的*矩阵。
2.3 普通形参 + 默认形参(规则:默认形参在后)
def star(hang, lie=10):  # 正确:默认形参lie在普通形参hang后i = 1while i <= hang:j = 1while j <= lie:print("*", end="")j += 1print()i += 1star(5,6)  # hang=5, lie=6 → 5行6列*
star(7)    # hang=7, lie=10 → 7行10列*
# star()   # 错误:普通形参hang无传入值
2.4 关键字实参(调用处,顺序可随意)
def star(hang,a0,a1=30,a2=20,lie=10):i = 1while i<=hang:j = 1while j<=lie:print("*",end="")j+=1print()i+=1# 调用:关键字实参(顺序随意)
star(a2 = 13,lie=8,a1 = 100,hang = 6,a0=9)
运算过程
  1. 关键字实参匹配形参:hang=6a0=9a1=100a2=13lie=8
  2. 循环执行6次(i从1到6),每次打印8个*,最终输出6行8列的*矩阵。

3. 收集参数

3.1 普通收集参数(*args
  • 功能:收集多余普通实参,打包为元组
# 示例:任意个数累加和
def mysum(*args):total = 0for i in args:total += iprint(total)mysum(1,2,3,4,4,5,5,6,7834,234,23423)
运算过程
  1. 调用mysum(...):所有实参被*args打包为元组:(1,2,3,4,4,5,5,6,7834,234,23423)
  2. 初始化total=0,遍历元组累加:
    • 0+1=1+2=3+3=6+4=10+4=14+5=19+5=24+6=30+7834=7864+234=8098+23423=31521
  3. 控制台输出:31521
3.2 关键字收集参数(**kwargs
  • 功能:收集多余关键字实参,打包为字典
# 示例:任意字符串拼接
def func(**kwargs):dictvar = {"big_boy":"阳光大男孩","small_girl":"娇弱小女孩"}strvar1 = ""strvar2 = ""for k,v in kwargs.items():if k in dictvar:strvar1 += dictvar[k] + ":" + v + '\n'else:strvar2 += v + " "print("{}情深深,雨蒙蒙,多少楼台都在烟雨中,{}猛然怼了两口狗粮 压压惊".format(strvar1,strvar2))func(big_boy="蔡松松",small_girl="王维",eat_gua1 = "陈学斌",eat_gua2="胡河金")
运算过程
  1. 调用func(...):关键字实参被**kwargs打包为字典:{'big_boy':'蔡松松','small_girl':'王维','eat_gua1':'陈学斌','eat_gua2':'胡河金'}
  2. 遍历字典键值对:
    • k=big_boy,v=蔡松松 → 匹配dictvarstrvar1 = "阳光大男孩:蔡松松\n"
    • k=small_girl,v=王维 → 匹配dictvarstrvar1 = "阳光大男孩:蔡松松\n娇弱小女孩:王维\n"
    • k=eat_gua1,v=陈学斌 → 不匹配 → strvar2 = "陈学斌 "
    • k=eat_gua2,v=胡河金 → 不匹配 → strvar2 = "陈学斌 胡河金 "
  3. 格式化输出最终字符串:
阳光大男孩:蔡松松
娇弱小女孩:王维
情深深,雨蒙蒙,多少楼台都在烟雨中,陈学斌 胡河金 猛然怼了两口狗粮 压压惊

4. 命名关键字参数

  • 规则:必须用关键字实参调用,两种定义方式:
# 方式1:*后直接定义
def func(a,b,c,*,d,e):print(a,b,c)print(d)print(e)
func(1,2,3,d=4,e=90)  # 必须传d/e的关键字实参# 方式2:*args和**kwargs之间定义
def func(*args,d,**kwargs):print(args)   # (1, 1, 3, 4, 5)print(d)      # 99print(kwargs) # {'a': 1, 'b': 2, 'c': 3}
func(1,1,3,4,5,a=1,b=2,c=3,d=99)
运算过程(方式2)
  1. 调用func(...)
    • 普通实参1,1,3,4,5*args打包为元组(1,1,3,4,5)
    • 关键字实参d=99匹配命名关键字参数d
    • 剩余关键字实参a=1,b=2,c=3**kwargs打包为字典{'a':1,'b':2,'c':3}
  2. 控制台输出:
(1, 1, 3, 4, 5)
99
{'a': 1, 'b': 2, 'c': 3}

5. ***的魔术用法(解包)

5.1 *解包(列表/元组 → 普通实参)
def func(a,b,c,*,d):print(a,b,c)print(d)
listvar = [3,4,5]
func(*listvar,d=6)  # 等价于func(3,4,5,d=6)
运算过程
  1. *listvar解包列表[3,4,5]为普通实参3,4,5,匹配形参a=3,b=4,c=5
  2. d=6匹配命名关键字参数d
  3. 控制台输出:
3 4 5
6
5.2 **解包(字典 → 关键字实参)
def func(a,b,c,*,d,e,f):print(a,b,c)print(d,e,f)
dictvar = {"d":11,"e":12,"f":13}
func(1,2,3,**dictvar)  # 等价于func(1,2,3,d=11,e=12,f=13)
运算过程
  1. 普通实参1,2,3匹配a=1,b=2,c=3
  2. **dictvar解包字典为d=11,e=12,f=13,匹配命名关键字参数。
  3. 控制台输出:
1 2 3
11 12 13

6. 参数定义顺序(规范)

# 普通形参 → 默认形参 → 普通收集形参 → 命名关键字形参 → 关键字收集形参
def f1(a, b, c=0, *args, d, **kw):print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'd=',d, 'kw =', kw)f1(1,2,3, 'a', 'b',d=67, x=99,y=77)
运算过程
  1. 实参匹配逻辑:
    • 1→a2→b3→c(覆盖默认值0)。
    • 'a','b'→*args → 元组('a','b')
    • d=67→命名关键字d
    • x=99,y=77→**kw → 字典{'x':99,'y':77}
  2. 控制台输出:
a = 1 b = 2 c = 3 args = ('a', 'b') d= 67 kw = {'x': 99, 'y': 77}

应用场景及案例

场景1:任意个数数值计算(累加/累乘)

案例:任意个数的累乘
def mymul(*args):result = 1for i in args:result *= iprint(f"累乘结果:{result}")mymul(2,3,4,5)
运算过程
  1. *args收集实参为元组(2,3,4,5)
  2. 初始化result=1,遍历累乘:
    • 1×2=2×3=6×4=24×5=120
  3. 输出结果:累乘结果:120
适用场景:购物车多商品价格计算、批量数值统计(参数个数不固定)。

场景2:动态拼接个性化文案

案例:生成用户信息卡片
def user_card(**kwargs):# 基础字段模板base_fields = {"name":"姓名","age":"年龄","phone":"手机号"}card = "【用户信息】\n"other = "【扩展信息】\n"for k,v in kwargs.items():if k in base_fields:card += f"{base_fields[k]}:{v}\n"else:other += f"{k}:{v}\n"print(card + other)# 调用:传入基础字段+扩展字段
user_card(name="张三",age=25,phone="13800138000",hobby="篮球",address="北京")
运算过程
  1. **kwargs收集为字典:{'name':'张三','age':25,'phone':'13800138000','hobby':'篮球','address':'北京'}
  2. 遍历键值对:
    • name/age/phone匹配base_fields → 拼入card【用户信息】\n姓名:张三\n年龄:25\n手机号:13800138000\n
    • hobby/address不匹配 → 拼入other【扩展信息】\nhobby:篮球\naddress:北京\n
  3. 最终输出:
【用户信息】
姓名:张三
年龄:25
手机号:13800138000
【扩展信息】
hobby:篮球
address:北京
适用场景:用户信息收集、商品详情拼接(字段数量不固定)。

场景3:动态生成重复内容(如打印自定义图案)

案例:自定义行数/列数打印三角形
def print_triangle(hang, lie=None):# 默认列数=行数(等边三角形)if lie is None:lie = hangi = 1while i <= hang:# 打印空格for _ in range(hang - i):print(" ", end="")# 打印*for _ in range(i * 2 -1):print("*", end="")print()i += 1# 调用:默认列数
print_triangle(5)
运算过程
  1. hang=5lie=None → 赋值lie=5
  2. 循环i从1到5:
    • i=1:空格数5-1=4 → 打印4个空格;*1×2-1=1 → 输出 * → 换行。
    • i=2:空格数3 → 打印3个空格;*3 → 输出 *** → 换行。
    • i=3:空格数2 → 打印2个空格;*5 → 输出 ***** → 换行。
    • i=4:空格数1 → 打印1个空格;*7 → 输出 ******* → 换行。
    • i=5:空格数0*9 → 输出********* → 换行。
  3. 最终输出:
    ****************
*********
适用场景:报表边框生成、图案打印(动态调整尺寸)。

场景4:固定格式的配置项(命名关键字参数强制规范)

案例:游戏角色创建(强制指定职业/等级)
def create_role(name,*,job,level=1):print(f"角色名:{name},职业:{job},等级:{level}")# 正确调用(必须用关键字传job)
create_role("苍云",job="坦克",level=80)
# 错误调用(job未用关键字,不可运行)
# create_role("七秀","治疗",80)
运算过程
  1. 实参"苍云"匹配普通形参name
  2. 关键字实参job="坦克"匹配命名关键字参数joblevel=80覆盖默认值1。
  3. 输出结果:角色名:苍云,职业:坦克,等级:80
适用场景:接口参数规范(强制关键字传参,避免参数顺序错误)。

场景5:灵活接收多类型参数(*args+**kwargs

案例:通用数据处理函数
def data_process(*args,**kwargs):# 处理普通参数(数值累加)num_sum = sum(args)# 处理关键字参数(筛选配置项)config = {k:v for k,v in kwargs.items() if k.startswith("cfg_")}print(f"数值累加:{num_sum},配置项:{config}")# 调用:传入普通数值+配置项
data_process(10,20,30,cfg_mode="debug",cfg_timeout=30,user="admin")
运算过程
  1. *args收集10,20,30 → 累加和60
  2. **kwargs收集{'cfg_mode':'debug','cfg_timeout':30,'user':'admin'} → 筛选出cfg_开头的配置:{'cfg_mode':'debug','cfg_timeout':30}
  3. 输出结果:数值累加:60,配置项:{'cfg_mode': 'debug', 'cfg_timeout': 30}
适用场景:通用工具函数(兼容多类型/多数量参数,如日志记录、数据清洗)。


11、闭包函数_LEGB_全局_局部

全文总结

知识点 核心概念 关键规则/语法
return 语句 自定义函数返回值,控制函数执行流程 1. 可返回任意Python数据类型(含函数/类);2. 执行后函数立即终止;3. 无return默认返回None
函数名的使用 函数名是第一类对象,可像变量一样操作 1. 赋值给变量;2. 作为容器元素;3. 作为函数参数/返回值;4. __doc__查看函数文档
全局/局部变量 变量的作用域划分(局部:函数内;全局:函数外/global声明) 1. 局部变量仅函数内有效;2. global可修改/定义全局变量;3. 全局变量横跨整个文件
函数的嵌套 函数内部定义其他函数(外函数/内函数),遵循LEGB查找规则 1. 内函数仅外函数内可调用;2. 变量查找遵循LEGB(局部→嵌套→全局→内置);3. 先定义后调用
nonlocal关键字 修饰局部变量,修改上一级嵌套作用域的局部变量 1. 找上一级嵌套局部变量,找不到则向上找;2. 不找全局变量;3. 无匹配变量则报错
闭包函数 内函数使用外函数局部变量,外函数返回内函数 1. 外函数变量与内函数绑定,延长生命周期;2. __closure__可查看绑定的变量;3. 实现数据封装

完整详细讲解

1. return 自定义返回值

核心逻辑

return用于指定函数返回值,执行后函数立即终止;无return时函数默认返回None。

分步讲解+运算过程
  • 步骤1:返回任意数据类型

    def func():return {"a":1,"b":2}  # 返回字典类型
    res = func()
    print(res)  # 运算:调用func()返回字典,赋值给res后打印
    

    输出:{'a': 1, 'b': 2}

  • 步骤2:return终止函数执行

    def func():print("111执行了")for i in range(10):print(i)return  # 执行return,函数直接终止print("333不会执行")
    res = func()
    print(res)  # 无返回值,输出None
    

    运算过程:

    1. 调用func(),先打印"111执行了";
    2. 进入for循环,打印i=0;
    3. 执行return,函数终止,后续代码不执行;
    4. res无值,打印None。
      输出:
    111执行了
    0
    None
    
  • 步骤3:实战(计算器)

    def calc(sign,num1,num2):if sign == "/":if num2 == 0:return "除数不能为0"  # 提前返回错误提示res = num1 / num2return res
    res = calc("/",3,0)
    print(res)
    

    运算过程:

    1. 调用calc("/",3,0),判断num2=0,执行return返回错误提示;
    2. 打印res,输出"除数不能为0"。
      输出:除数不能为0

2. 函数名的使用

核心逻辑

Python中函数是“第一类对象”,函数名可像变量一样赋值、传参、存容器。

分步讲解+运算过程
  • 步骤1:函数名赋值给变量

    def func():return 5
    func2 = func  # 函数名赋值给变量
    res = func2()  # 调用func2等价于调用func
    print(res)
    

    运算:func2指向func的函数体,调用后返回5,输出5。
    输出:5

  • 步骤2:函数名作为容器元素

    def func1():print(1)
    def func2():print(2)
    lst = [func1,func2]
    for i in lst:i()  # 遍历调用每个函数
    

    运算:列表存储函数名,遍历后依次调用func1、func2,输出1、2。
    输出:

    1
    2
    
  • 步骤3:查看函数文档(doc

    def eat(something):"""功能:吃东西;参数:要吃的东西"""return f"吃了{something}"
    print(eat.__doc__)  # 打印函数文档
    

    输出:功能:吃东西;参数:要吃的东西

3. 全局变量与局部变量

核心逻辑
  • 局部变量:函数内定义,仅函数内有效;
  • 全局变量:函数外定义/global声明,全局生效;
  • global:函数内修改/定义全局变量。
分步讲解+运算过程
  • 步骤1:局部变量(仅函数内有效)

    def func():a = 15  # 局部变量a = 16print(a)
    func()
    

    运算:函数内修改局部变量a为16,打印16。
    输出:16

  • 步骤2:global修改全局变量

    abc = 17  # 全局变量
    def func():global abc  # 声明修改全局变量abc = 19print(abc)
    func()
    print(abc)  # 全局变量已被修改为19
    

    运算:

    1. 调用func(),修改全局变量abc=19,打印19;
    2. 函数外打印abc,输出19。
      输出:
    19
    19
    

4. 函数的嵌套

核心逻辑

外函数包含内函数,内函数仅外函数内可调用;变量查找遵循LEGB原则。

分步讲解+运算过程
  • 步骤1:基本嵌套调用

    def outer():print("我是外函数")def inner():print("我是内函数")inner()  # 外函数内调用内函数
    outer()
    

    运算:调用outer()→执行inner(),依次打印对应字符串。
    输出:

    我是外函数
    我是内函数
    
  • 步骤2:LEGB变量查找

    def outer():def inner():def smaller():print(type)  # 找内置作用域的type函数smaller()inner()
    outer()
    

    运算:smaller内无type→inner/outer无→全局无→找内置type,打印内置函数对象。
    输出:<class 'type'>

5. nonlocal关键字

核心逻辑

修改上一级嵌套作用域的局部变量,找不到则向上找,无则报错(不找全局)。

分步讲解+运算过程
  • 步骤1:修改上一级局部变量

    def outer():a = 13def inner():nonlocal a  # 声明修改outer的aa = 15inner()print(a)
    outer()
    

    运算:inner修改outer的a为15,outer打印15。
    输出:15

  • 步骤2:可变类型无需nonlocal

    def outer():lst = [1,2]def inner():lst[0] += 10  # 列表是可变类型,直接修改inner()print(lst)
    outer()
    

    运算:inner修改列表第一个元素为11,打印[11,2]。
    输出:[11, 2]

6. 闭包函数

核心逻辑

内函数使用外函数局部变量,外函数返回内函数;外函数变量与内函数绑定,延长生命周期。

分步讲解+运算过程
  • 步骤1:闭包基本用法

    def outer():name = "陈浩南"def inner():print(f"我是{name}")return inner
    func = outer()  # func指向inner
    func()  # 调用inner,使用绑定的name
    

    运算:outer返回inner,func调用inner时,使用绑定的name="陈浩南",打印对应字符串。
    输出:我是陈浩南

  • 步骤2:闭包共享变量

    def outer():money = 1000def sub500():nonlocal moneymoney -= 500print(money)return sub500
    func = outer()
    func()  # money=500
    func()  # money=0
    

    运算:

    1. 第一次调用func,money=1000-500=500,打印500;
    2. 第二次调用func,money=500-500=0,打印0。
      输出:
    500
    0
    

应用场景及案例

1. 全局变量:跨函数共享配置

场景

多个函数共享数据库地址,修改时只需改全局变量。

案例代码+运算过程
DB_ADDR = "127.0.0.1"  # 全局配置def connect():print(f"连接{DB_ADDR}")def modify_addr():global DB_ADDRDB_ADDR = "192.168.1.1"# 执行
connect()      # 打印连接127.0.0.1
modify_addr()  # 修改全局变量
connect()      # 打印连接192.168.1.1

运算过程:

  1. 初始DB_ADDR=127.0.0.1,connect打印对应地址;
  2. modify_addr修改全局变量为192.168.1.1;
  3. 再次调用connect,打印新地址。
    输出:
连接127.0.0.1
连接192.168.1.1

2. nonlocal:嵌套函数实现计数器

场景

嵌套函数中持续统计调用次数,保留计数器状态。

案例代码+运算过程
def counter():count = 0def add():nonlocal countcount += 1return countreturn addfunc = counter()
print(func())  # count=1
print(func())  # count=2

运算过程:

  1. func绑定count=0,第一次调用add,count=1,返回1;
  2. 第二次调用add,count=2,返回2。
    输出:
1
2

3. 函数名使用:批量执行业务函数

场景

批量执行登录、注册、退出等业务函数。

案例代码+运算过程
def login():return "登录成功"
def register():return "注册成功"func_list = [login, register]
for f in func_list:print(f())

运算过程:遍历函数列表,依次调用login、register,打印返回值。
输出:

登录成功
注册成功

4. 闭包:无类实现数据封装

场景

无需定义类,用闭包封装计算器状态。

案例代码+运算过程
def calculator(init):def add(num):nonlocal initinit += numreturn initreturn addcalc = calculator(10)
print(calc(5))  # 10+5=15
print(calc(3))  # 15+3=18

运算过程:

  1. calc绑定init=10,调用calc(5),init=15,返回15;
  2. 调用calc(3),init=18,返回18。
    输出:
15
18

5. return:通用数据类型判断工具

场景

编写工具函数,返回数据的值和类型,便于调试。

案例代码+运算过程
def check_type(data):return (data, type(data).__name__)print(check_type(123))    # (123, 'int')
print(check_type([1,2]))  # ([1,2], 'list')

运算过程:

  1. 传入123,返回(123, 'int')并打印;
  2. 传入列表,返回([1,2], 'list')并打印。
    输出:
(123, 'int')
([1, 2], 'list')


12、递归_locals_闭包特点_尾递归

全文总结

表格版核心知识点总结

知识点 核心定义 关键特性/注意点
locals() 获取当前作用域的变量字典(函数外=全局变量,函数内=调用前局部变量) 仅获取调用前的变量;作用域隔离,函数内只拿局部
globals() 无论内外,仅获取全局变量字典;可动态创建/修改全局变量 全局作用域;通过字典操作可动态生成全局变量(如dic["a1"]=1
递归函数 函数自己调用自己,分“递(去)”和“归(回)”两个阶段 必须有跳出条件;递归层数过多易内存溢出;本质是栈帧空间的开辟与释放
闭包 内函数使用外函数的局部变量,变量与内函数绑定,延长生命周期 封装保护变量(外部无法直接修改);用nonlocal声明修改外函数局部变量
匿名函数(lambda) 用一句话表达只有返回值的简单函数,语法:lambda 参数: 返回值 仅支持简单逻辑;可结合三目运算符实现条件分支;功能单一但代码简洁
阶乘/斐波那契 阶乘:n! = n*(n-1)*...*1;斐波那契:1,1,2,3,5...(n≤2返回1,否则n-1+n-2) 普通递归阶乘/斐波那契易栈溢出;尾递归仅开辟一个栈帧(CPython不支持尾递归优化)
尾递归 递归调用是函数最后一步(非表达式),仅占用一个栈帧 需解释器支持(CPython不支持);适合大数递归计算,避免栈溢出

分段版补充总结

1. 作用域相关(locals/globals)
  • locals() 是“当前作用域快照”,调用时只包含此前定义的变量,函数内外作用域严格隔离;
  • globals() 是“全局作用域总览”,全程指向全局变量字典,支持通过字典操作动态增删改全局变量,突破普通变量定义的语法限制。
2. 函数进阶(递归/闭包/匿名函数)
  • 递归函数:核心是“有去有回”,必须先定义终止条件(否则无限递归);执行过程是先逐层调用(递),触底后逐层返回(归);
  • 闭包:核心是“变量绑定+封装”,外函数返回内函数,内函数持有外函数变量,既复用变量又避免全局变量被随意修改;
  • 匿名函数:极简版函数,仅用于简单返回值场景,替代单行普通函数,提升代码简洁度。
3. 递归实战(阶乘/斐波那契)
  • 普通递归阶乘/斐波那契:逻辑直观但层数受限(约1000层);
  • 尾递归:优化递归栈帧占用,但CPython无原生支持,实际中大数计算优先用循环。

完整详细解析

1. locals() 和 globals() 详解

1.1 基础铺垫
  • 全局作用域:函数外的代码区域,变量全局可用;
  • 局部作用域:函数内的代码区域,变量仅函数内可用。
1.2 locals():当前作用域的变量快照
场景1:函数外使用locals()
a = 10
b = 20
res = locals()  # 调用locals(),仅包含此前定义的a、b
c = 30
print(res)      # 输出包含a=10、b=20,无c

运算过程

  1. 定义a=10b=20 → 全局作用域已有这两个变量;
  2. 执行res=locals() → 打包“调用前”的全局变量为字典,存入res
  3. 定义c=30 → 这是locals()调用后的操作,因此res中无c
  4. 打印res → 能看到ab,看不到c
场景2:函数内使用locals()
e = 50  # 全局变量
def func():a = 10b = 20res = locals()  # 仅包含调用前的局部变量a、bc = 30print(res)      # 输出{'a':10, 'b':20},无e、c
func()

运算过程

  1. 定义e=50 → 全局变量;
  2. 调用func() → 进入函数局部作用域,定义a=10b=20
  3. 执行res=locals() → 打包“函数内调用前”的局部变量,不包含全局变量e
  4. 定义c=30 → 调用后操作,res中无c
  5. 打印res → 仅包含ab
1.3 globals():全局变量的“总控字典”
场景1:函数外使用globals()
a = 10
b = 20
res = globals()  # 打包调用前的全局变量
d = 40
print(res)       # 输出包含a=10、b=20,无d

运算过程

  1. 定义a=10b=20 → 全局变量;
  2. res=globals() → 打包“调用前”的全局变量字典;
  3. 定义d=40 → 调用后操作,res中无d
  4. 打印res → 能看到ab,看不到d
场景2:函数内使用globals()
a = 10
def func():b = 20  # 局部变量res = globals()  # 仅获取全局变量(a)print(res)       # 输出包含a,无b
f = 90
func()

运算过程

  1. 定义a=10 → 全局变量;
  2. 调用func() → 进入局部作用域,定义b=20(局部);
  3. res=globals() → 忽略局部变量b,仅获取全局变量(a、后续定义的f);
  4. 打印res → 能看到af,无b
场景3:动态创建全局变量(核心应用)
# 单个全局变量
dic = globals()
dic["wangwen"] = "风流倜傥"
print(wangwen)  # 输出:风流倜傥# 批量创建(a1-a5,值1-5)
def func():dic = globals()for i in range(1,6):dic["a%d" % i] = i
func()
print(a1)  # 1
print(a2)  # 2

批量创建运算过程

  1. 调用func()dic=globals()(绑定全局变量字典);
  2. 循环i=15
    • i=1dic["a1"]=1 → 全局字典新增a1=1
    • i=2dic["a2"]=2 → 全局字典新增a2=2
    • ...直到i=5dic["a5"]=5
  3. 函数执行完毕,全局变量a1-a5已创建,打印对应值。

2. 递归函数详解

2.1 核心概念
  • 递:函数逐层调用自己,直到触发终止条件(“去”的过程);
  • 归:触发终止后,函数逐层返回,执行剩余代码(“回”的过程);
  • 栈帧:每个函数调用开辟一块内存空间,调用结束释放。
2.2 基础案例(带完整运算过程)
def digui(n):print("<===1==>",n)if n>0:digui(n-1)  print("<===2==>",n)digui(5)

运算过程(分“递”和“归”)

递(去)的过程(逐层调用,添加阻塞)
调用层级 n值 执行操作 状态
第1层 5 打印<=1>5 → 5>0 → 调用digui(4) → 阻塞,等待返回 等待归
第2层 4 打印<=1>4 → 4>0 → 调用digui(3) → 阻塞,等待返回 等待归
第3层 3 打印<=1>3 → 3>0 → 调用digui(2) → 阻塞,等待返回 等待归
第4层 2 打印<=1>2 → 2>0 → 调用digui(1) → 阻塞,等待返回 等待归
第5层 1 打印<=1>1 → 1>0 → 调用digui(0) → 阻塞,等待返回 等待归
第6层 0 打印<=1>0 → 0>0不成立 → 打印<=2>0 → 触底反弹,开始归 终止递,启动归
归(回)的过程(逐层返回,执行剩余代码)
调用层级 n值 执行操作 状态
第5层 1 从digui(0)返回 → 打印<=2>1 → 函数结束,返回上一层 继续归
第4层 2 从digui(1)返回 → 打印<=2>2 → 函数结束,返回上一层 继续归
第3层 3 从digui(2)返回 → 打印<=2>3 → 函数结束,返回上一层 继续归
第2层 4 从digui(3)返回 → 打印<=2>4 → 函数结束,返回上一层 继续归
第1层 5 从digui(4)返回 → 打印<=2>5 → 函数结束,释放所有栈帧 归完成
最终输出
<===1==>5
<===1==>4
<===1==>3
<===1==>2
<===1==>1
<===1==>0
<===2==>0
<===2==>1
<===2==>2
<===2==>3
<===2==>4
<===2==>5
2.3 注意点
  • 必须加终止条件(如n>0),否则无限递归(报错RecursionError);
  • Python默认递归最大层数约1000层,层数过多用循环替代。

3. 闭包详解

3.1 核心概念
  • 外函数定义局部变量,内函数使用该变量;
  • 外函数返回内函数,变量与内函数绑定,延长生命周期;
  • nonlocal声明内函数可修改外函数局部变量。
3.2 基础案例
def outer(num):def inner(val):return num + valreturn innerfunc = outer(5)  # 接收inner函数
res = func(4)    # 调用inner(4)
print(res)       # 输出9

运算过程

  1. 调用outer(5) → 外函数执行,num=5(局部变量);
  2. outer定义innerinner使用num
  3. outer返回innerfunc = innernuminner绑定,不销毁);
  4. 调用func(4) → 等价于inner(4)num保留5 → 返回5+4=9
  5. 打印res=9
3.3 闭包封装变量(鼠标点击计数)
反面案例(全局变量易被修改)
num = 0  # 全局变量
def clicknum():global numnum += 1print(num)clicknum()  # 1
clicknum()  # 2
num = 100   # 随意修改全局变量
clicknum()  # 101

运算过程

  1. num=0(全局);
  2. 第一次clicknum()global numnum=0+1=1 → 打印1;
  3. 第二次clicknum()num=1+1=2 → 打印2;
  4. 直接修改num=100(无保护);
  5. 第三次clicknum()num=100+1=101 → 打印101。
闭包优化案例(封装保护)
def outer():num = 0  # 外函数局部变量,外部不可修改def inner():nonlocal num  # 声明修改外函数变量num += 1print(num)return innerclicknum = outer()
clicknum()  # 1
clicknum()  # 2
num = 2000  # 全局num,与闭包内num无关
clicknum()  # 3

运算过程

  1. 调用outer()num=0,定义inner,返回innerclicknum=inner
  2. 第一次clicknum()nonlocal numnum=0+1=1 → 打印1;
  3. 第二次clicknum()num=1+1=2 → 打印2;
  4. 定义全局num=2000 → 与闭包内num无关;
  5. 第三次clicknum()num=2+1=3 → 打印3。

4. 匿名函数(lambda)详解

4.1 核心语法

lambda 参数 : 返回值 → 仅包含返回值,无复杂逻辑。

4.2 基础案例
案例1:无参数lambda
func = lambda : "开挂的人生,不需要解释"
res = func()
print(res)  # 输出对应字符串

运算过程

  1. func绑定无参数lambda函数;
  2. 调用func() → lambda返回指定字符串 → 打印。
案例2:带参数lambda(判断类型)
func = lambda n : type(n)
res = func("abc")
print(res)  # 输出<class 'str'>

运算过程

  1. func绑定参数为n的lambda;
  2. 调用func("abc")n="abc" → 返回type(n)=str → 打印。
案例3:带条件分支(判断奇偶)
func = lambda n : "偶数" if n % 2 == 0 else "奇数"
res = func(15)
print(res)  # 输出奇数

运算过程

  1. func绑定lambda,结合三目运算符;
  2. 调用func(15)15%2=1 → 条件不成立 → 返回“奇数” → 打印。
案例4:比较最大值
func = lambda x,y : x if x>y else y
res = func(5,16)
print(res)  # 输出16

运算过程

  1. func绑定lambda,参数x=5y=16
  2. 5>16不成立 → 返回y=16 → 打印。

5. 阶乘&斐波那契(递归+尾递归)详解

5.1 阶乘(n!)
定义:n! = n × (n-1) × ... × 1(0!和1!都=1)。
案例1:循环实现阶乘
def jiecheng(n):total = 1for i in range(1,n+1):total *= ireturn totalres = jiecheng(5)
print(res)  # 输出120

运算过程

  1. n=5total=1
  2. i=1total=1×1=1
  3. i=2total=1×2=2
  4. i=3total=2×3=6
  5. i=4total=6×4=24
  6. i=5total=24×5=120 → 打印。
案例2:普通递归实现阶乘
def jiecheng(n):if n <= 1:return 1return n * jiecheng(n-1)res = jiecheng(5)
print(res)  # 输出120

运算过程

  • 递:5→4→3→2→1n=1返回1,触底);
  • 归:1×2=2 → 2×3=6 → 6×4=24 → 24×5=120 → 打印。
案例3:尾递归实现阶乘
def jiecheng(n,endval):if n<=1:return endvalreturn jiecheng(n-1,n*endval)def jiecheng2(n):return jiecheng(n,1)res = jiecheng2(5)
print(res)  # 输出120

运算过程

  1. jiecheng2(5)jiecheng(5,1)
  2. n=5jiecheng(4,5×1=5)
  3. n=4jiecheng(3,4×5=20)
  4. n=3jiecheng(2,3×20=60)
  5. n=2jiecheng(1,2×60=120)
  6. n=1 → 返回120 → 打印。
5.2 斐波那契数列(递归)
定义:第1/2项=1,第n项=第n-1项+第n-2项(n≥3)。
def fib(n):if n == 1 or n ==2:return 1return fib(n-1) + fib(n-2)res = fib(5)
print(res)  # 输出5

运算过程

  1. fib(5) = fib(4)+fib(3)
  2. fib(4)=fib(3)+fib(2)=2+1=3
  3. fib(3)=fib(2)+fib(1)=1+1=2
  4. fib(5)=3+2=5 → 打印。

应用场景及案例

1. locals()/globals() 应用场景

场景1:动态生成批量测试变量
案例:生成test1-test10,值1-10
def create_test_vars():dic = globals()for i in range(1,11):dic[f"test{i}"] = icreate_test_vars()
print(test1)  # 1
print(test5)  # 5

运算过程

  1. 调用create_test_vars()dic=globals()
  2. 循环i=1-10 → 逐个创建test1=1test2=2test10=10
  3. 打印test1=1test5=5
场景2:调试时打印当前变量
案例:函数内调试,查看局部变量
def debug_func(a, b):c = a + bprint("当前局部变量:", locals())  # 调试用d = c * 2return ddebug_func(2,3)  # 输出:当前局部变量: {'a': 2, 'b': 3, 'c': 5}

运算过程

  1. 调用debug_func(2,3)a=2b=3
  2. c=2+3=5
  3. locals()打包当前局部变量 → 打印{'a':2, 'b':3, 'c':5}
  4. d=5×2=10 → 返回。

2. 递归函数应用场景

场景1:遍历多级目录(模拟)
案例:递归遍历目录结构
def traverse_dir(dir_name, level=0):dir_struct = {"dir1": {"dir2": ["file1"]}}if isinstance(dir_struct.get(dir_name), list):print("  "*level + f"文件:{dir_name}下的{dir_struct[dir_name]}")returnfor sub_dir in dir_struct[dir_name].keys():print("  "*level + f"目录:{sub_dir}")traverse_dir(sub_dir, level+1)traverse_dir("dir1")

输出

目录:dir2文件:dir2下的['file1']

运算过程

  1. traverse_dir("dir1",0)dir1是字典 → 遍历子目录dir2
  2. 打印“目录:dir2”(无缩进);
  3. traverse_dir("dir2",1)dir2是列表(终止条件)→ 打印“ 文件:dir2下的['file1']”;
  4. 函数返回,递归结束。
场景2:斐波那契预测兔子繁殖
案例:计算第8项斐波那契数(1,1,2,3,5,8,13,21)
def fib(n):if n ==1 or n==2:return 1return fib(n-1)+fib(n-2)res = fib(8)
print(res)  # 输出21

运算过程

  1. fib(8)=fib(7)+fib(6)
  2. fib(7)=fib(6)+fib(5)=8+5=13
  3. fib(6)=fib(5)+fib(4)=5+3=8
  4. fib(8)=13+8=21 → 打印。

3. 闭包应用场景

场景1:接口调用次数统计
案例:统计接口调用次数,防止外部修改
def api_counter():count = 0def call_api(api_name):nonlocal countcount +=1print(f"接口{api_name}已调用{count}次")return call_apiuser_api = api_counter()
user_api("登录接口")  # 1次
user_api("支付接口")  # 2次

运算过程

  1. api_counter()count=0,返回call_apiuser_api=call_api
  2. 第一次user_api("登录接口")count=0+1=1 → 打印1次;
  3. 第二次user_api("支付接口")count=1+1=2 → 打印2次。
场景2:固定折扣的价格计算
案例:生成9折价格计算器
def discount_func(discount):def calc_price(price):return price * discountreturn calc_pricediscount_9 = discount_func(0.9)
print(discount_9(100))  # 90
print(discount_9(200))  # 180

运算过程

  1. discount_func(0.9)discount=0.9,返回calc_pricediscount_9=calc_price
  2. discount_9(100)100×0.9=90 → 打印;
  3. discount_9(200)200×0.9=180 → 打印。

4. 匿名函数(lambda)应用场景

场景1:列表按元组第二个元素排序
案例:按元组第二个元素升序
lst = [(1,3), (4,1), (2,2)]
lst.sort(key=lambda x: x[1])
print(lst)  # 输出[(4, 1), (2, 2), (1, 3)]

运算过程

  1. lst.sortkey参数指定lambda x: x[1](按元组第二个元素排序);
  2. 原列表第二个元素:3、1、2;
  3. 按1、2、3排序 → 对应元素(4,1)(2,2)(1,3) → 打印。
场景2:map映射实现列表平方
案例:列表元素平方
lst = [1,2,3,4]
res = list(map(lambda x: x*x, lst))
print(res)  # 输出[1,4,9,16]

运算过程

  1. map遍历lst,每个元素传入lambda x: x*x
  2. x=1→1x=2→4x=3→9x=4→16
  3. list(map(...))转为列表 → 打印[1,4,9,16]

5. 阶乘应用场景(大数计算)

场景:1000的阶乘(循环替代递归)
def jiecheng_big(n):total = 1for i in range(1, n+1):total *= ireturn totalres = jiecheng_big(1000)
print(str(res)[:10])  # 输出4023872600

运算过程

  1. total=1,循环i=1-1000
  2. 每次循环total = total × i,逐步累积;
  3. 循环结束后total=1000!,转字符串取前10位 → 打印4023872600



13、迭代器 + 高阶函数

整体总结

工具 核心功能 关键输出
迭代器 省内存取值 惰性序列
map 批量处理数据 迭代器
reduce 累积计算 单个结果
filter 筛选数据 迭代器
sorted 排序数据 新列表

1.1 可迭代对象(能被遍历的“容器”)

通俗定义

能被for循环遍历的对象(比如列表、集合、字典、range、字符串等)。

技术判断

内部包含__iter__方法(用dir()可查看)。

实操案例(一步步验证)

# 案例:判断集合是否是可迭代对象
setvar = {1,"a",2,"c"}# 步骤1:查看内部方法,找__iter__
res = dir(setvar)
print("__iter__" in res)  # 输出True → 是可迭代对象# 步骤2:验证遍历(可迭代对象的核心特征)
for i in setvar:print(i)  # 能正常输出1、a、2、c → 验证成立

1.2 迭代器(可迭代对象的“省内存版”)

通俗定义

能被next()调用、一次只拿一个值 的对象(拿完就没,方向不可逆)。

核心特征

  • 惰性序列:用的时候才计算值,不一次性把所有数据加载到内存(比如100万条数据,迭代器只占1条数据的内存);
  • 迭代器一定是可迭代对象,但可迭代对象不一定是迭代器。

两步上手迭代器:创建 → 调用

(1)创建迭代器(2种方式,推荐第1种)
setvar = {1,"a",2,"c"}# 方式1:iter(可迭代对象)(推荐,简洁)
it = iter(setvar)
print(it)  # 输出<set_iterator object at 0x...> → 迭代器对象# 方式2:可迭代对象.__iter__()(效果和方式1一致,写法麻烦)
it2 = setvar.__iter__()
(2)调用迭代器(2种方式,推荐第1种)
it = iter({1,"a",2,"c"})# 方式1:next(迭代器)(推荐)
res1 = next(it)
print(res1)  # 输出1(第一个值)
res2 = next(it)
print(res2)  # 输出a(第二个值)
res3 = next(it)
print(res3)  # 输出2(第三个值)
res4 = next(it)
print(res4)  # 输出c(第四个值)
# res5 = next(it) → 报错StopIteration(值已拿完)# 方式2:迭代器.__next__()(和方式1等价)
res = it2.__next__()
print(res)  # 输出1
(3)判断迭代器(工具版)

collections模块的Iterator(迭代器)和Iterable(可迭代对象)快速判断:

from collections import Iterator, Iterablesetvar = {1,"a",2,"c"}
it = iter(setvar)# 判断原集合(可迭代对象)
print(isinstance(setvar, Iterable))  # True(是可迭代对象)
print(isinstance(setvar, Iterator))  # False(不是迭代器)# 判断迭代器
print(isinstance(it, Iterable))  # True(迭代器一定是可迭代对象)
print(isinstance(it, Iterator))  # True(是迭代器)

1.3 迭代器的3种遍历方式

it = iter(range(10))  # 生成0-9的迭代器# 方式1:多次next(适合取少量值)
print(next(it))  # 0
print(next(it))  # 1
print(next(it))  # 2# 方式2:for循环(自动处理“值拿完”的报错,适合遍历所有值)
print("====for遍历剩余值====")
for i in it:print(i)  # 输出3-9(前面已拿0-2)# 方式3:for+next(适合取前N个值,极致省内存)
it = iter(range(100000))  # 10万个值,迭代器仅占极小内存
for i in range(5):  # 只取前5个print(next(it))  # 输出0、1、2、3、4

1.4 迭代器总结

核心特点 通俗解释
省内存 用的时候才生成值,不一次性加载所有数据(处理超大文件/数据集必备)
不可逆 只能往后拿值,想重新拿需重置迭代器(it = iter(可迭代对象)
遍历无限数据 比如生成所有偶数,迭代器可一直next,不会卡内存

1.5 迭代器应用场景

  • 处理超大文件:比如100G日志文件,用迭代器逐行读取,不用一次性加载到内存;
  • 生成无限序列:比如生成所有质数,迭代器按需生成,不占满内存;
  • 高阶函数返回值:map/filter等高阶函数都返回迭代器,天然省内存。

2.1 高阶函数1:map(批量处理数据)

定义

把可迭代对象里的每个值,挨个扔进函数处理,结果返回迭代器。

语法

map(处理函数, 可迭代对象)

案例:字符串列表转数字列表(手动→map→优化)

步骤1:手动实现(先懂逻辑)
# 需求:["1","2","3","4"] → [1,2,3,4]
lst = ["1","2","3","4"]
lst_new = []
for i in lst:res = int(i)  # 逐个转数字lst_new.append(res)
print(lst_new)  # 输出[1,2,3,4]
步骤2:用map简化(替代for循环)
lst = ["1","2","3","4"]
it = map(int, lst)  # int是内置函数,批量转换
print(list(it))  # 输出[1,2,3,4](迭代器转列表看结果)
步骤3:自定义函数(比如给所有值平方)
# 需求:[1,2,3,4] → [1,4,9,16]
def func(n):return n ** 2  # 定义平方函数lst = [1,2,3,4]
it = map(func, lst)  # 批量平方
print(list(it))  # 输出[1,4,9,16]
步骤4:优化(lambda匿名函数,一行搞定)
lst = [1,2,3,4]
it = map(lambda x: x**2, lst)  # lambda替代自定义func
print(list(it))  # 输出[1,4,9,16]

map总结

核心作用 输入 输出
批量处理数据 处理函数 + 可迭代对象 迭代器(处理后的结果)

map应用场景

  • 批量类型转换(比如字符串转数字、数字转字符串);
  • 批量计算(比如所有值乘10、所有值取绝对值);
  • 批量映射(比如把字母转成对应的ASCII码)。

2.2 高阶函数2:reduce(累积计算)

定义

把可迭代对象里的值两个两个扔进函数计算,结果和下一个值继续算,直到所有值算完,返回最终结果。

语法

reduce(计算函数, 可迭代对象)(需从functools导入)

案例:列表[5,4,8,8]转数字5488(手动→reduce→优化)

步骤1:手动实现(先懂累积逻辑)
lst = [5,4,8,8]
# 逻辑:5*10+4=54 → 54*10+8=548 → 548*10+8=5488
it = iter(lst)
num1 = next(it)  # 5
num2 = next(it)  # 4
total = num1 * 10 + num2  # 54
# 剩余值继续计算
for i in it:total = total * 10 + i
print(total)  # 输出5488
步骤2:用reduce简化
from functools import reducelst = [5,4,8,8]
def func(x, y):return x * 10 + y  # 定义累积规则res = reduce(func, lst)
print(res)  # 输出5488
步骤3:进阶案例(字符串"765"转数字765,不用int)
from functools import reducestrvar = "765"
# 步骤1:把字符串转成数字迭代器(map)
def char2num(n):dic = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9}return dic[n]
it = map(char2num, strvar)  # 转成[7,6,5]的迭代器# 步骤2:累积计算(reduce)
def func(x, y):return x*10 + y
res = reduce(func, it)
print(res)  # 输出765(int类型)

reduce总结

核心作用 输入 输出
累积计算 二元计算函数 + 可迭代对象 单个最终结果(比如和、乘积、拼接值)

reduce应用场景

  • 列表求和/乘积(比如[1,2,3]求和→6,乘积→6);
  • 拼接数字/字符串(比如[5,4,8]→548,["a","b"]→"ab");
  • 计算阶乘(比如5! = 5×4×3×2×1)。

2.3 高阶函数3:filter(过滤数据)

定义

把可迭代对象里的每个值扔进函数判断:返回True保留,返回False丢弃,结果返回迭代器。

语法

filter(判断函数, 可迭代对象)

案例:筛选列表里的偶数(手动→filter→优化)

步骤1:手动实现(先懂逻辑)
# 需求:[1,2,3,4,5,6,7,8,9] → 保留偶数,去掉奇数
listvar = [1,2,3,4,5,6,7,8,9]
lst_new = []
for i in listvar:if i % 2 == 0:  # 判断偶数lst_new.append(i)
print(lst_new)  # 输出[2,4,6,8]
步骤2:用filter简化
listvar = [1,2,3,4,5,6,7,8,9]
def func(x):if x % 2 == 0:return True  # 保留else:return False  # 丢弃it = filter(func, listvar)
print(list(it))  # 输出[2,4,6,8]
步骤3:优化(lambda简化)
listvar = [1,2,3,4,5,6,7,8,9]
it = filter(lambda x: x%2 == 0, listvar)  # 一行判断偶数
print(list(it))  # 输出[2,4,6,8]

filter总结

核心作用 输入 输出
筛选数据 判断函数(返回True/False) + 可迭代对象 迭代器(符合条件的结果)

filter应用场景

  • 筛选符合条件的数据(比如成绩≥60的学生、年龄≥18的用户);
  • 过滤无效数据(比如去掉列表里的空字符串、None值);
  • 复杂筛选(比如筛选字典列表中“薪资>10k”的字典)。

2.4 高阶函数4:sorted(排序数据)

定义

对可迭代对象排序,返回新列表(不修改原数据),支持自定义排序规则。

语法

sorted(可迭代对象, reverse=False, key=排序函数)

  • reverse:False正序(默认),True倒序;
  • key:排序依据(比如按绝对值、按字符串长度)。

案例1:基础排序(正序/倒序)

# 正序(从小到大)
tup = (100,3,-3,0)
res = sorted(tup)
print(res)  # 输出[-3, 0, 3, 100]# 倒序(从大到小)
setvar = {99,1,2}
res = sorted(setvar, reverse=True)
print(res)  # 输出[99, 2, 1]

案例2:按自定义规则排序(按绝对值)

# 需求:(19,-5,-9,14)按绝对值从小到大排序
tup = (19,-5,-9,14)
res = sorted(tup, key=abs)  # key=abs:按绝对值排序
print(res)  # 输出[-5, -9, 14, 19](绝对值:5、9、14、19)

案例3:自定义函数排序(按个位数字)

# 需求:[53,19,21,38,42]按个位数字从小到大排序
lst = [53,19,21,38,42]
def func(n):return n % 10  # 返回个位数字(排序依据)res = sorted(lst, key=func)
print(res)  # 输出[21,42,53,38,19](个位:1、2、3、8、9)

sorted总结

核心作用 输入 输出
灵活排序 可迭代对象 + 可选(倒序/排序函数) 新列表(排序后的结果)

sorted应用场景

  • 基础数值排序(比如成绩、销量、薪资排序);
  • 自定义规则排序(比如按字符串长度、按字典的某个键值排序);
  • 复杂数据排序(比如列表里的元组,按第二个元素排序)。

三、综合应用场景(落地案例)

场景1:数据清洗(filter+map)

# 需求:清洗用户年龄数据(去掉空值→转数字→筛选≥18岁)
age_str = ["20","","17","30","","25"]# 步骤1:过滤空值
it1 = filter(lambda x: x != "", age_str)
# 步骤2:转数字
it2 = map(int, it1)
# 步骤3:筛选≥18岁
it3 = filter(lambda x: x >= 18, it2)print(list(it3))  # 输出[20,30,25]

场景2:数据计算(filter+reduce)

from functools import reduce# 需求:计算列表中所有偶数的和
lst = [1,2,3,4,5,6]# 步骤1:筛选偶数
it1 = filter(lambda x: x%2==0, lst)
# 步骤2:累积求和
res = reduce(lambda x,y: x+y, it1)print(res)  # 输出12(2+4+6)

场景3:数据排序(sorted+lambda)

# 需求:按字符串长度排序
lst = ["apple","banana","cat","dog"]
res = sorted(lst, key=lambda x: len(x))print(res)  # 输出['cat', 'dog', 'apple', 'banana']

四、新人学习小贴士

  1. 先学迭代器:map/filter都返回迭代器,会用next()list()取结果是基础;
  2. 先手动实现:写for循环懂逻辑,再用高阶函数简化,更容易理解;
  3. 善用lambda:简化自定义函数,新手先记常用场景(比如lambda x: x%2==0判断偶数);
  4. 验证结果:迭代器转列表(list(it))能直观看到结果,方便调试。



14、推导式、迭代器、生成器

三者核心对比(秒选工具)

特性 推导式 迭代器 生成器
核心作用 快速创建容器 惰性遍历数据(底层协议) 惰性生成数据(简化迭代器)
数据加载方式 一次性加载,占内存 惰性加载,逐个生成 惰性加载,逐个生成
编写难度 极简(一行代码) 复杂(需手写方法) 简单(yield/表达式)
性能/内存 小数据快,大数据占内存 内存极致优化 内存极致优化
使用频率 极高(日常开发) 低(底层原理) 极高(大数据场景)

推导式与生成器 核心总结

一、推导式核心总结

  1. 本质:用一行代码替代多行for循环,快速完成遍历+数据加工+条件筛选,直接生成列表、集合、字典三类容器。
  2. 语法通用结构数据加工结果 for 变量 in 可迭代对象 [if 筛选条件]
  3. 三类推导式核心差异
    • 列表推导式[]:生成有序、可重复列表,一次性加载所有数据
    • 集合推导式{}:生成无序容器,自动去重,支持if...else三元表达式
    • 字典推导式{k:v}:生成键值对,常搭配enumerate(索引)、zip(列表配对)使用
  4. 适用场景:数据量较小,需要快速简洁生成容器,追求代码精简。

二、生成器核心总结

  1. 本质:自定义惰性迭代器,用到一个数据才生成一个,不一次性加载,极致节省内存
  2. 两种创建方式
    • 生成器表达式():把列表推导式的[]换成(),极简创建
    • 生成器函数def+yield:用函数自定义逻辑,yield替代return
  3. 核心关键字特性
    • yield:返回数据并暂停函数,下次调用从暂停位置继续执行
    • yield from:直接将可迭代对象转为迭代器返回,简化代码
    • send:既能取值,又能给生成器传值,第一次必须传None
  4. 取值方式next()逐次取值,for循环自动遍历(避免越界报错)
  5. 适用场景:大数据量、无限序列、内存优化,需要自定义迭代逻辑。

三、快速选择口诀

  1. 数据小、要简洁、快速造容器 → 用推导式
  2. 数据大、要省内存、无限/流式数据 → 用生成器
  3. 简单过滤/转换/建表 → 推导式
  4. 大文件/百万数据/自定义迭代 → 生成器

一、推导式概述

1. 核心作用

一行代码代替多行for循环,快速生成列表、集合、字典,不用写append、循环嵌套。

2. 通用公式(所有推导式都能用)

加工后的数据 for 变量 in 可迭代对象 [if 筛选条件]


二、列表推导式(最常用,从最简单开始学)

1. 基础用法(只循环,不筛选)

  • 语法:[加工值 for 变量 in 可迭代对象]
  • 执行:遍历→加工→直接生成列表
# 生成1-5
[i for i in range(1,6)]
# 执行步骤:取1→取2→取3→取4→取5 → [1,2,3,4,5]# 生成1-5的立方
[i**3 for i in range(1,6)]
# 执行步骤:1³=1→2³=8→3³=27→4³=64→5³=125 → [1,8,27,64,125]

2. 带条件筛选(只留想要的数据)

  • 语法:[值 for 变量 in 可迭代对象 if 条件]
  • 执行:遍历→判断→满足条件才保留
listvar = [1,2,3,4,4,5,6,7,78,8]
[i for i in listvar if i%2==0]
# 执行步骤:1(不保留)→2(保留)→3(不保留)→4(保留)→4(保留)→5(不保留)→6(保留)→7(不保留)→78(保留)→8(保留)
# 结果:[2,4,4,6,78,8]

3. 多循环嵌套(两个列表两两组合)

  • 语法:[值 for i in 列表1 for j in 列表2]
  • 执行:外层循环慢,内层循环快,两两配对
lst1 = ["称好","陈雪斌","李杰"]
lst2 = ["吴嘉敏","王维","尹棉"]
[i+"❥♥♥♥"+j for i in lst1 for j in lst2]
# 执行步骤:
# 称好+吴嘉敏 → 称好+王维 → 称好+尹棉
# 陈雪斌+吴嘉敏 → 陈雪斌+王维 → 陈雪斌+尹棉
# 李杰+吴嘉敏 → 李杰+王维 → 李杰+尹棉
# 共9组结果

4. 多循环+条件(只保留同索引组合)

  • 执行:只有索引相同的才保留
[i+"❥♥♥♥"+j for i in lst1 for j in lst2 if lst1.index(i)==lst2.index(j)]
# 执行步骤:0配0 → 1配1 → 2配2 → 只保留3组

5. 矩阵元素乘积

M = [[1,2,3],[4,5,6],[7,8,9]]
N = [[2,2,2],[3,3,3],[4,4,4]]# 平铺成一维列表
[M[i][j]*N[i][j] for i in range(3) for j in range(3)]
# 执行步骤:逐行逐列相乘 → [2,4,6,12,15,18,28,32,36]# 保持二维矩阵结构
[[M[i][j]*N[i][j] for j in range(3)] for i in range(3)]
# 执行步骤:按行生成子列表 → [[2,4,6],[12,15,18],[28,32,36]]

三、集合推导式(比列表多1个功能:自动去重)

1. 核心特点

  • 语法:{值 for 变量 in 可迭代对象}
  • 关键:自动去重,支持if...else三元表达式

2. 基础用法

listvar = [{"name":"王家辉","age":18,"money":10000},...]
{"尊贵VIP卡老"+i["name"][0] if 18<=i["age"]<=21 and 5000<i["money"]<=5500 else "抠脚大汉卡老"+i["name"][0] for i in listvar}
# 执行步骤:按条件生成类型 → 自动去重 → 输出4种卡类型

四、字典推导式(生成键值对,2个常用工具)

1. 配合enumerate(索引当键)

  • 执行:索引做键,元素做值
listvar = ["重汽彩","李杰","陈雪妮"]
{k:v for k,v in enumerate(listvar)}
# 执行步骤:0→重汽彩,1→李杰,2→陈雪妮 → {0:"重汽彩",1:"李杰",2:"陈雪妮"}

2. 配合zip(两个列表配对成字典)

  • 执行:两个列表一一对应,打包成键值对
lst1 = ["彭金成","讯云波","朱洪根"]
lst2 = ["韦陈熊","吴家豪","吴嘉敏"]
{k:v for k,v in zip(lst1,lst2)}
# 执行步骤:彭金成→韦陈熊,讯云波→吴家豪,朱洪根→吴嘉敏 → 生成字典

五、推导式经典例题(跟着练,一步到位)

1. 字典转key=value列表

dic = {'x':'A','y':'B','z':'C'}
[k+"="+v for k,v in dic.items()]
# 执行步骤:x=A→y=B→z=C → ["x=A","y=B","z=C"]

2. 字符串大小写转换

lst = ["ADDD","dddDD","DDaa","sss"]
[i.lower() for i in lst] # 执行:全部转小写
[i.upper() for i in lst] # 执行:全部转大写

3. 奇偶组合元组

[(i,j) for i in range(6) if i%2==0 for j in range(6) if j%2==1]
# 执行步骤:i取0/2/4,j取1/3/5 → 两两组合成元组

4. 99乘法表生成

["%d*%d=%2d" % (i,j,i*j) for i in range(1,10) for j in range(1,i+1)]
# 执行步骤:i从1到9,j从1到i → 生成所有乘法算式

六、生成器(省内存神器,分步学)

1. 生成器概述

  • 核心:惰性计算,用一个生成一个,不占大量内存
  • 本质:自定义迭代器,适合大数据/无限数据

2. 生成器表达式(最简单,改个符号)

  • 语法:(值 for 变量 in 可迭代对象)(列表推导式[]换())
  • 执行:用next()或for循环取值
gen = (i<<2 for i in range(5))
# 取值步骤:
next(gen) → 0
next(gen) → 4
next(gen) → 8

3. 生成器函数(def+yield,暂停执行)

  • yield:返回值并暂停,下次从暂停处继续
  • return:直接终止函数
def mygen():print("one")yield 1print("two")yield 2print("three")yield 3gen = mygen()
# 执行步骤:
next(gen) → 打印one,返回1(暂停)
next(gen) → 打印two,返回2(暂停)
next(gen) → 打印three,返回3(暂停)

4. send方法(取值+传值)

  • 规则:第一次必须send(None)
def mygen():res = yield 1print(res)res = yield 2gen = mygen()
gen.send(None) → 返回1
gen.send(1111) → 打印1111,返回2

5. yield from(简化写法)

  • 作用:直接把可迭代对象转成迭代器返回
def mygen():yield from ["重汽彩","张亚军","罗塘"]
# 取值步骤:重汽彩→张亚军→罗塘

6. 实战:斐波那契数列

def fib(n):a,b = 0,1i=0while i<n:yield ba,b = b,a+bi+=1
# 执行步骤:1→1→2→3→5(前5项)

七、最终总结(速记)

  1. 小数据、快速造容器 → 用推导式
  2. 大数据、省内存、分步生成 → 用生成器
  3. 列表[]、集合{}、字典{k:v}、生成器()
  4. yield=暂停并返回,return=终止函数


八、应用场景

一、推导式 应用场景

1. 快速生成小型测试数据
  • 场景:需要造一组简单列表/集合/字典做测试
  • 示例:生成数字列表、平方列表、测试字典
# 造测试用数字列表
[i for i in range(1,11)]
# 造平方数测试数据
[i**2 for i in range(10)]
2. 简单数据过滤与清洗
  • 场景:从列表里筛选符合条件的数据(偶数、正数、指定规则)
  • 示例:筛选偶数、过滤空值、提取有效数据
# 筛选列表偶数
[i for i in [1,2,3,4,5] if i%2==0]
# 字符串转小写并过滤空字符串
[s.lower() for s in ["A","B","","C"] if s]
3. 快速数据格式转换
  • 场景:把数据统一改成目标格式(拼接字符串、转元组、字典转列表)
  • 示例:字典转key=value列表、拼接文本、生成元组列表
# 字典转指定格式列表
[k+"="+v for k,v in {"x":"A","y":"B"}.items()]
# 生成奇偶元组列表
[(i,j) for i in range(6) for j in range(6) if i%2==0 and j%2==1]
4. 快速构建字典/集合
  • 场景:列表加索引转字典、两个列表配对转字典、列表去重
  • 示例:枚举索引建字典、zip配对建字典、集合自动去重
# 列表+索引生成字典
{k:v for k,v in enumerate(["name","age"])}
# 两个列表配对生成字典
{k:v for k,v in zip(["a","b"],[1,2])}
# 列表快速去重
{i for i in [1,2,2,3,3,3]}
5. 简单嵌套结构生成
  • 场景:生成二维列表、矩阵、小型嵌套数据
  • 示例:矩阵元素计算、生成嵌套列表
# 生成二维矩阵
[[i*j for j in range(3)] for i in range(3)]

二、生成器 应用场景

1. 超大数据量遍历(百万/千万级)
  • 场景:数据量太大,用列表会占满内存、卡顿
  • 优势:生成器用一个算一个,不一次性加载所有数据
# 百万级数据,列表会占大量内存
# big_list = [i for i in range(1000000)]
# 生成器几乎不占内存
big_gen = (i for i in range(1000000))
2. 读取超大文件/日志流
  • 场景:打开几GB的大文件,不能一次性读进内存
  • 优势:逐行生成、逐行处理,内存占用极小
# 逐行读取超大文件(生成器逻辑)
def read_big_file(file_path):with open(file_path,"r",encoding="utf-8") as f:for line in f:yield line.strip()
3. 无限序列生成
  • 场景:需要无限生成数据(自增ID、自然数、斐波那契数列)
  • 优势:列表无法存无限数据,生成器可以按需生成
# 无限生成自增ID(生成器)
def create_id():num = 1while True:yield numnum += 1
4. 流式数据处理(管道式加工)
  • 场景:数据一步一步加工,不存储中间结果
  • 优势:链式处理、内存占用低
# 流式:先过滤→再平方→再拼接(全程不存大列表)
gen = (str(i**2) for i in range(100) if i%2==0)
5. 自定义迭代节奏(按需取值)
  • 场景:适用于分步任务执行、流程化数据处理、交互式操作、分页数据获取等需要手动控制执行进度的场景,不一次性执行全部逻辑,每调用一次仅完成一个步骤并返回结果。
  • 优势:yield可暂停函数执行,通过next()精准控制每一步的执行时机,灵活适配分步处理、状态反馈类业务。
# 分步生成任务结果
def task():yield "步骤1完成"yield "步骤2完成"yield "步骤3完成"
# 分步处理数据任务(清洗→转换→统计)
def data_process_step(data):# 步骤1:数据清洗,过滤负数cleaned = [i for i in data if i > 0]yield f"步骤1:数据清洗完成,有效数据:{cleaned}"# 步骤2:数据转换,数值翻倍converted = [i * 2 for i in cleaned]yield f"步骤2:数据转换完成,翻倍后数据:{converted}"# 步骤3:数据统计,计算总和total = sum(converted)yield f"步骤3:数据统计完成,数据总和:{total}"# 手动控制执行节奏
task = data_process_step([1, -2, 3, -4, 5])
# 分步调用,每次执行一步
print(next(task))
print(next(task))
print(next(task))

执行结果:

步骤1:数据清洗完成,有效数据:[1, 3, 5]
步骤2:数据转换完成,翻倍后数据:[2, 6, 10]
步骤3:数据统计完成,数据总和:18



15、4 道经典面试题

全文总结(表格速记)

题号 核心考点 最终结果 关键易错点
1 滑动序列分组(切片+zip) 按n个元素分组,丢弃不足n的尾部 忘记*解包、切片步长错误
2 函数默认参数(可变对象) list1=[10]、list2=[123]、list3=[10,'a'] 可变默认参数只初始化1次,会累积数据
3 lambda闭包延迟绑定 res=[6,6,6,6] lambda调用时才取变量最终值,非定义时
4 生成器表达式延迟计算 输出[20,21,22,23] 生成器仅遍历时执行,循环变量取最终值

1. 滑动序列(按n个元素分组)

核心原理

列表切片拆分原序列,再通过zip(*)打包成n个元素一组,自动丢弃不足n个的尾部元素。

分步运算过程

原列表:listvar = [1,2,3,4,5,6,7,8,9]

  1. 生成n个切片:从索引i开始,步长为n取元素(i从0到n-1)
  2. *解包所有切片,传给zip打包
  3. 把打包结果转成列表,得到最终分组

完整代码

# 滑动序列函数
def slide_seq(lst, n):# 1. 生成n个切片slice_list = [lst[i::n] for i in range(n)]# 2. zip打包 + 转列表return [list(item) for item in zip(*slice_list)]# 测试
listvar = [1,2,3,4,5,6,7,8,9]
print(slide_seq(listvar, 2))  # [[1,2],[3,4],[5,6],[7,8]]
print(slide_seq(listvar, 3))  # [[1,2,3],[4,5,6],[7,8,9]]
print(slide_seq(listvar, 4))  # [[1,2,3,4],[5,6,7,8]]

2. 函数默认参数陷阱(可变对象)

核心原理

Python函数的默认参数仅在定义时初始化1次,可变对象(列表/字典)会被多次调用复用,数据会累积。

分步运算过程

def extendList(val, list=[]):list.append(val)return list
  1. 函数定义时:默认列表list=[]在内存中创建(唯一不变)
  2. list1 = extendList(10):使用默认列表,添加10 → [10]
  3. list2 = extendList(123, []):传入新列表,添加123 → [123]
  4. list3 = extendList('a'):复用默认列表,添加'a' → [10, 'a']

避坑写法

# 推荐:默认参数用None,函数内新建列表
def extendList(val, list=None):if list is None:list = []list.append(val)return list

3. lambda闭包延迟绑定

核心原理

循环中定义的lambda函数,调用时才读取外部变量i的最终值,而非定义时的循环值。

分步运算过程

def func():return [lambda x : i*x for i in range(4)]
res = [m(2) for m in func()]
  1. 执行func():循环i=0/1/2/3,生成4个lambda函数(未执行
  2. 循环结束:i最终值=3
  3. 调用m(2):每个lambda计算3*2=6
  4. 最终结果:res = [6,6,6,6]

修正写法

# 用参数默认值绑定当前i
def func():return [lambda x, i=i: i*x for i in range(4)]
res = [m(2) for m in func()]  # [0,2,4,6]

4. 生成器表达式延迟计算

核心原理

生成器表达式仅在遍历(如list())时执行,循环变量取最终值,而非定义时的值。

分步运算过程

def add(a,b): return a + b
def test(): yield from range(4)  # 生成 0,1,2,3g = test()
for n in [2,10]:g = (add(n,i) for i in g)
print(list(g))
  1. 初始g:test() → 生成器0,1,2,3
  2. 循环n=2:生成新生成器(未执行)
  3. 循环n=10:生成最终生成器(未执行)
  4. 执行list(g)开始计算:
    • 第一层:add(10, 0/1/2/3)10,11,12,13
    • 第二层:add(10, 10/11/12/13)20,21,22,23
  5. 最终输出:[20,21,22,23]

应用场景+案例+详细运算过程

1. 滑动序列应用场景

  • 场景:数据分块、批量处理、滑动窗口统计
  • 案例:把100个用户数据按10个一组批量提交
# 数据
users = list(range(1, 101))
# 分组
batch_list = slide_seq(users, 10)
# 运算:每10个一组,共10组
print(batch_list[0])  # [1,2,...,10]
print(batch_list[1])  # [11,12,...,20]

2. 默认参数应用场景

  • 场景:函数参数缺省值、列表/字典初始化
  • 案例:安全的添加用户函数
def add_user(user, user_list=None):if user_list is None:user_list = []user_list.append(user)return user_list# 运算:每次调用新建列表,无数据累积
print(add_user("张三"))  # ["张三"]
print(add_user("李四"))  # ["李四"]

3. lambda闭包应用场景

  • 场景:循环生成回调函数、批量计算函数
  • 案例:循环生成乘法函数
# 正确绑定循环值
mul_funcs = [lambda x, i=i: x*i for i in range(5)]
# 运算:每个函数绑定对应i值
print([f(2) for f in mul_funcs])  # [0,2,4,6,8]

4. 生成器应用场景

  • 场景:大数据流式计算、惰性求值、节省内存
  • 案例:流式数据二次累加
# 流式数据
data = (i for i in range(10))
# 两次累加
for n in [3,5]:data = (x + n for x in data)
# 运算:最终每个数+3+5=+8
print(list(data))  # [8,9,10,...,17]


16、内置函数_数学模块_随机模块_序列化模块_时间模块_日历模块

全文总结

模块/类别 核心功能 关键方法/函数
内置函数 基础数值计算、数据处理、编码转换、代码执行等 abs(绝对值)、round(四舍五入)、sum(求和)、max/min(最值)、pow(次方)、range(范围)、chr/ord(ASCII转换)、eval/exec(代码执行)、hash(哈希)
数学模块(math) 高精度数值计算(取整、次方、开方、绝对值、求和等) ceil(向上取整)、floor(向下取整)、pow(次方)、sqrt(开平方)、fabs(绝对值)、modf(拆分整数小数)、copysign(拷贝符号)、fsum(浮点求和)、pi(圆周率)
随机模块(random) 生成随机数、随机选择序列元素、打乱序列 random(0-1小数)、randrange(指定范围整数)、randint(指定范围整数)、uniform(指定范围小数)、choice(序列选1)、sample(序列选多)、shuffle(打乱序列)
序列化模块(pickle) 将Python对象转换为字节/文件存储,或反向还原 dumps(对象转bytes)、loads(bytes转对象)、dump(对象序列化写入文件)、load(文件反序列化读对象)
时间模块(time) 时间戳、时间元组、时间字符串的转换与处理 time(时间戳)、localtime(时间戳转时间元组)、ctime(时间戳转字符串)、strftime(时间元组转格式化字符串)、strptime(字符串转时间元组)、sleep(程序休眠)
日历模块(calendar) 日历生成、闰年判断、日期星期计算(了解级) calendar(年日历)、month(月日历)、isleap(闰年判断)、weekday(日期转星期)

补充分段总结

  1. 内置函数:Python自带的基础工具,无需导入模块即可使用,覆盖数值计算(abs、round、pow)、数据统计(sum、max/min)、序列生成(range)、编码转换(chr/ord)、代码执行(eval/exec)等场景,满足日常基础开发需求。
  2. math模块:针对数学运算的扩展模块,需导入后使用,提供比内置函数更精准的数值计算能力(如浮点型的取整、求和、开方),还包含圆周率(pi)等数学常数,适用于高精度计算场景。
  3. random模块:用于生成随机数和随机操作序列,是实现“随机性”需求的核心模块,如验证码、随机抽奖、随机排序等场景都依赖该模块。
  4. pickle模块:专用于Python对象的序列化/反序列化,可将列表、字典、类实例等复杂对象保存为字节或文件,适用于数据持久化、跨程序传输Python对象的场景。
  5. time模块:处理时间相关操作的核心模块,实现时间戳、时间元组、格式化时间字符串的相互转换,还可控制程序休眠,适用于日志记录、定时任务等场景。
  6. calendar模块:以日历为核心的辅助模块,可生成年月日历、判断闰年、计算日期对应的星期,属于了解级模块,日常开发使用频率较低。

完整详细讲解

一、内置函数(无需导入,直接使用)

1. abs() - 绝对值函数
  • 定义:返回数值的绝对值
  • 语法:abs(数值)
  • 运算过程:若输入数值≥0,返回自身;若数值<0,返回其相反数
  • 示例
    res = abs(-18)
    print(res)  # 运算过程:-18是负数,取相反数,输出18
    
2. round() - 四舍五入(奇进偶不进规则:n.5时,偶数舍去,奇数进1)
  • 定义:对数值进行四舍五入,特殊规则:当小数部分为0.5时,看整数部分奇偶性
  • 语法:round(数值)
  • 运算过程
    • round(2.66):小数部分0.66>0.5,进1 → 3
    • round(2.5):整数部分2是偶数,舍去0.5 → 2
    • round(3.5):整数部分3是奇数,进1 → 4
    • round(16.51):小数部分0.51>0.5,进1 → 17
  • 示例
    print(round(2.66))  # 输出3
    print(round(2.5))   # 输出2
    print(round(3.5))   # 输出4
    print(round(16.51)) # 输出17
    
3. sum() - 序列求和
  • 定义:计算列表/元组等序列中所有元素的和
  • 语法:sum(序列)
  • 运算过程:遍历序列,累加所有元素
  • 示例
    listvar = [234,23,4,24,3,42]
    res = sum(listvar)  # 运算:234+23=257 → 257+4=261 → 261+24=285 → 285+3=288 → 288+42=330
    print(res)  # 输出330
    
4. max()/min() - 序列最值(基础用法+高阶用法)
  • 基础定义:返回序列中的最大值/最小值

  • 基础语法:max(序列) / min(序列)

  • 基础运算过程:遍历序列,比较所有元素大小,返回最值

  • 基础示例

    listvar = [234,23,4,249,2]
    res_max = max(listvar)  # 运算:234>23>4,249>234,2最小 → 最大值249
    res_min = min(listvar)  # 最小值2
    print(res_max, res_min) # 输出249 2
    
  • 高阶定义:按自定义规则(key函数)找最值

  • 高阶语法:max(可迭代对象, key=函数)

  • 高阶运算过程

    1. 遍历可迭代对象,将每个元素传入key函数;
    2. 根据key函数的返回值比较大小;
    3. 返回原可迭代对象中对应返回值最大的元素。
  • 高阶示例(元组)

    def func(n):return n[-1]  # 取元组最后一个元素作为比较依据
    listvar = [("a",1),("b",2),("c",3),("d",4)]
    res = max(listvar, key=func)  # 运算:func返回值1/2/3/4 → 4最大 → 对应元组("d",4)
    print(res)  # 输出('d', 4)
    
  • 高阶示例(字典)

    dic = {"a":-3,"b":2,"c":1}
    def func2(n):return abs(dic[n])  # 取字典值的绝对值作为比较依据
    res = max(dic, key=func2)  # 运算:abs(-3)=3、abs(2)=2、abs(1)=1 → 3最大 → 对应键"a"
    print(res)  # 输出a
    
5. pow() - 次方运算(可选取余)
  • 定义:计算x的y次方,可选对z取余
  • 语法:pow(x, y) / pow(x, y, z)
  • 运算过程
    • pow(2,3):2×2×2=8
    • pow(2,3,3):先算2³=8,再8%3=2
  • 示例
    print(pow(2,3))    # 输出8
    print(pow(2,3,3))  # 输出2
    
6. range() - 生成整数序列
  • 定义:生成指定范围的整数可迭代对象,语法:range(结束) / range(开始,结束) / range(开始,结束,步长)
  • 运算过程
    • range(3):从0开始,到3结束(不含3)→ 0,1,2
    • range(3,8):从3开始,到8结束(不含8)→ 3,4,5,6,7
    • range(13,0,-2):从13开始,步长-2(递减),到0结束(不含0)→13,11,9,7,5,3,1
  • 示例
    for i in range(3):print(i)  # 输出0、1、2
    
7. 进制转换(bin/oct/hex)
  • 定义
    • bin():十进制转二进制
    • oct():十进制转八进制
    • hex():十进制转十六进制
  • 运算过程
    • bin(15):15的二进制是1111 → 输出0b1111(0b是二进制标识)
    • oct(8):8的八进制是10 → 输出0o10(0o是八进制标识)
    • hex(16):16的十六进制是10 → 输出0x10(0x是十六进制标识)
  • 示例
    print(bin(15))  # 输出0b1111
    print(oct(8))   # 输出0o10
    print(hex(16))  # 输出0x10
    
8. ASCII转换(chr/ord)
  • 定义
    • chr():ASCII码转字符(大写65-90,小写97-122)
    • ord():字符转ASCII码
  • 运算过程
    • chr(90):ASCII码90对应大写Z → 输出Z
    • ord("a"):字符a对应ASCII码97 → 输出97
  • 示例
    print(chr(90))  # 输出Z
    print(ord("a")) # 输出97
    
9. 代码执行(eval/exec)
  • 定义
    • eval():执行简单字符串代码(无法定义变量)
    • exec():执行复杂字符串代码(可定义变量、循环等)
  • 运算过程
    • eval("print(123)"):执行print(123) → 输出123
    • exec("a=5"):执行赋值语句 → 变量a=5
  • 示例
    eval("print(123)")  # 输出123
    exec("a=5")
    print(a)            # 输出5
    
10. hash() - 生成哈希值
  • 定义:相同内容生成相同哈希值,不同内容(即使微小差异)生成不同值
  • 运算过程
    • 两次传入相同字符串,哈希值相等
  • 示例
    strvar = "test"
    res1 = hash(strvar)
    res2 = hash(strvar)
    print(res1 == res2)  # 输出True
    

二、数学模块math(需导入:import math)

1. ceil() - 向上取整
  • 定义:无论小数部分是多少,向大的整数进1
  • 语法:math.ceil(数值)
  • 运算过程
    • math.ceil(5.0000001):小数部分>0,进1 → 6
    • math.ceil(5.99):进1 → 6
  • 示例
    import math
    res = math.ceil(5.0000001)
    print(res)  # 输出6
    
2. floor() - 向下取整
  • 定义:无论小数部分是多少,向小的整数舍去
  • 语法:math.floor(数值)
  • 运算过程
    • math.floor(5.99):舍去小数部分 → 5
    • math.floor(5.0001):舍去小数部分 → 5
  • 示例
    res = math.floor(5.99)
    print(res)  # 输出5
    
3. pow() - 次方(浮点结果)
  • 定义:计算x的y次方,结果为浮点数(区别于内置pow的整型)
  • 语法:math.pow(x, y)
  • 运算过程
    • math.pow(3,3):3³=27 → 输出27.0(浮点型)
  • 示例
    res = math.pow(3,3)
    print(res)  # 输出27.0
    
4. sqrt() - 开平方
  • 定义:计算数值的平方根,结果为浮点数
  • 语法:math.sqrt(数值)
  • 运算过程
    • math.sqrt(9):9的平方根是3 → 输出3.0
  • 示例
    res = math.sqrt(9)
    print(res)  # 输出3.0
    
5. fabs() - 浮点绝对值
  • 定义:返回数值的绝对值,结果为浮点数(区别于内置abs的整型)
  • 语法:math.fabs(数值)
  • 运算过程
    • math.fabs(-89):-89的绝对值是89 → 输出89.0
  • 示例
    res = math.fabs(-89)
    print(res)  # 输出89.0
    
6. modf() - 拆分整数和小数
  • 定义:将数值拆分为(小数部分,整数部分)的元组
  • 语法:math.modf(数值)
  • 运算过程
    • math.modf(14.789):小数部分0.789,整数部分14 → 输出(0.789, 14.0)
  • 示例
    res = math.modf(14.789)
    print(res)  # 输出(0.7890000000000001, 14.0)(浮点精度问题)
    
7. copysign() - 拷贝符号
  • 定义:将第二个参数的正负号拷贝给第一个参数
  • 语法:math.copysign(数值1, 数值2)
  • 运算过程
    • math.copysign(-18.332, -78):第二个参数是负号 → 第一个参数变为负 → 输出-18.332
    • math.copysign(18.332, -78):第二个参数负号 → 输出-18.332
  • 示例
    res = math.copysign(-18.332,-78)
    print(res)  # 输出-18.332
    
8. fsum() - 浮点求和
  • 定义:计算序列和,结果为浮点数(区别于内置sum的整型)
  • 语法:math.fsum(序列)
  • 运算过程
    • math.fsum([1,2,3]):1+2+3=6 → 输出6.0
  • 示例
    listvar = [1,2,3]
    res = math.fsum(listvar)
    print(res)  # 输出6.0
    
9. pi - 圆周率常数
  • 定义:math模块内置的圆周率常量(≈3.141592653589793)
  • 示例
    print(math.pi)  # 输出3.141592653589793
    

三、随机模块random(需导入:import random)

1. random() - 0-1随机小数
  • 定义:生成0≤x<1的随机小数
  • 语法:random.random()
  • 运算过程:随机生成0到1之间的小数(如0.5678)
  • 示例
    import random
    res = random.random()
    print(res)  # 示例输出0.5678901234
    
2. randrange() - 指定范围整数
  • 定义:生成[开始, 结束)范围内的整数,可选步长(推荐使用)
  • 语法:random.randrange(结束) / random.randrange(开始,结束) / random.randrange(开始,结束,步长)
  • 运算过程
    • random.randrange(3):0、1、2中随机选1个 → 示例输出2
    • random.randrange(2,10):2-9中随机选1个 → 示例输出5
    • random.randrange(2,10,3):2、5、8中随机选1个 → 示例输出8
  • 示例
    res = random.randrange(2,10,3)
    print(res)  # 示例输出8
    
3. randint() - 指定范围整数(闭区间)
  • 定义:生成[开始, 结束]范围内的整数(区别于randrange的左闭右开)
  • 语法:random.randint(开始, 结束)
  • 运算过程
    • random.randint(4,7):4、5、6、7中随机选1个 → 示例输出6
  • 示例
    res = random.randint(4,7)
    print(res)  # 示例输出6
    
4. uniform() - 指定范围随机小数
  • 定义:生成[开始, 结束)(或[结束, 开始))的随机小数
  • 语法:random.uniform(数值1, 数值2)
  • 运算过程
    • random.uniform(3,5):3≤x<5的随机小数 → 示例输出4.234
    • random.uniform(2,-1):-1<x≤2的随机小数(公式:a + (b-a)random() → 2 + (-3)0~1 → 结果在-1到2之间)
  • 示例
    res = random.uniform(2,-1)
    print(res)  # 示例输出0.897
    
5. choice() - 序列随机选1个
  • 定义:从列表/元组等序列中随机选1个元素
  • 语法:random.choice(序列)
  • 运算过程
    • random.choice(["朱洪根","王新","李毅","曾文"]):4个名字中随机选1个 → 示例输出"王新"
  • 示例
    listvar = ["朱洪根","王新","李毅","曾文"]
    res = random.choice(listvar)
    print(res)  # 示例输出王新
    
6. sample() - 序列随机选多个
  • 定义:从序列中随机选N个元素,返回列表(不重复)
  • 语法:random.sample(序列, 选几个)
  • 运算过程
    • random.sample(["肿起来","徐云波","陈浩","为陈雄"],3):4个元素中选3个 → 示例输出["徐云波","陈浩","为陈雄"]
  • 示例
    listvar = ["肿起来","徐云波","陈浩","为陈雄"]
    res = random.sample(listvar,3)
    print(res)  # 示例输出['徐云波', '陈浩', '为陈雄']
    
7. shuffle() - 打乱序列(修改原序列)
  • 定义:随机打乱列表的元素顺序(直接修改原列表,无返回值)
  • 语法:random.shuffle(序列)
  • 运算过程
    • 原列表["肿起来","徐云波","陈浩","为陈雄"] → 打乱后示例:["陈浩","肿起来","为陈雄","徐云波"]
  • 示例
    listvar = ["肿起来","徐云波","陈浩","为陈雄"]
    random.shuffle(listvar)
    print(listvar)  # 示例输出['陈浩', '肿起来', '为陈雄', '徐云波']
    

四、序列化模块pickle(需导入:import pickle)

1. 核心功能
  • dumps:将Python对象(列表、字典、类等)序列化为bytes类型
  • loads:将bytes类型反序列化为原Python对象
  • dump:将对象序列化后写入文件
  • load:从文件中读取序列化内容,反序列化为原对象
2. 运算过程(以列表为例)
import pickle# 1. dumps + loads
lst = [1,2,3]
# 序列化:列表→bytes
bytes_data = pickle.dumps(lst)
print(bytes_data)  # 输出序列化后的bytes(如b'\x80\x04\x95\x0b\x00\x00\x00\x00\x00\x00\x00]\x94(K\x01K\x02K\x03e.')
# 反序列化:bytes→列表
new_lst = pickle.loads(bytes_data)
print(new_lst)     # 输出[1,2,3]# 2. dump + load
# 序列化写入文件
with open("data.pkl", "wb") as f:pickle.dump(lst, f)
# 从文件反序列化
with open("data.pkl", "rb") as f:new_lst2 = pickle.load(f)
print(new_lst2)    # 输出[1,2,3]

五、时间模块time(需导入:import time)

1. 核心概念
  • 时间戳:1970-01-01 00:00:00到指定时间的秒数(float类型)
  • 时间元组:9个元素的元组(年、月、日、时、分、秒、周几、年中第几天、是否夏令时)
  • 格式化字符串:通过%Y/%m/%d等符号自定义时间格式
2. 核心方法
方法 功能 运算过程示例
time.time() 获取当前时间戳 time.time() → 示例输出1718999999.123456
time.localtime() 时间戳转本地时间元组 time.localtime(1718999999.123456) → 输出time.struct_time(tm_year=2024,...)
time.ctime() 时间戳转时间字符串 time.ctime(1718999999.123456) → 示例输出"Thu Jun 20 12:59:59 2024"
time.strftime() 时间元组转格式化字符串 time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) → 输出"2024-06-20 13:00:00"
time.strptime() 格式化字符串转时间元组 time.strptime("2024-06-20", "%Y-%m-%d") → 输出time.struct_time(tm_year=2024,...)
time.sleep() 程序休眠N秒 time.sleep(2) → 程序暂停2秒后继续
3. 示例代码
import time# 1. 获取时间戳
timestamp = time.time()
print(timestamp)  # 示例输出1718999999.123456# 2. 时间戳转时间元组
time_tuple = time.localtime(timestamp)
print(time_tuple)  # 输出time.struct_time(tm_year=2024, tm_mon=6, tm_mday=20, tm_hour=12, tm_min=59, tm_sec=59, tm_wday=3, tm_yday=172, tm_isdst=0)# 3. 时间元组转格式化字符串
format_str = time.strftime("%Y-%m-%d %H:%M:%S", time_tuple)
print(format_str)  # 运算:按%Y(年)、%m(月)、%d(日)等拼接 → 输出2024-06-20 12:59:59# 4. 格式化字符串转时间元组
new_time_tuple = time.strptime(format_str, "%Y-%m-%d %H:%M:%S")
print(new_time_tuple)  # 解析字符串,还原时间元组 → 输出和time_tuple一致# 5. 程序休眠
print("开始休眠")
time.sleep(2)  # 程序暂停2秒
print("休眠结束")

六、日历模块calendar(了解,需导入:import calendar)

1. 核心方法
  • calendar.calendar(2024):生成2024年的完整日历字符串
  • calendar.month(2024,6):生成2024年6月的日历字符串
  • calendar.isleap(2024):判断2024是否是闰年 → 输出True(2024÷4=506,能被4整除且不被100整除)
  • calendar.weekday(2024,6,20):计算2024-06-20是星期几(周一=0,周日=6)→ 输出3(周四)
2. 示例代码
import calendar
print(calendar.isleap(2024))  # 输出True
print(calendar.weekday(2024,6,20))  # 输出3

应用场景及案例

场景1:生成4位随机验证码(random模块)

1. 适用场景

网站/APP登录、注册、找回密码时的验证码验证,需要随机生成字母+数字的组合,防止机器批量操作。

2. 案例代码
import randomdef yanzhengma():strvar = ""for i in range(4):  # 循环4次,生成4位字符# 步骤1:生成随机大写字母(ASCII 65-90)b_c = chr(random.randrange(65,91))  # 如randrange(65,91)返回66 → chr(66)=B# 步骤2:生成随机小写字母(ASCII 97-122)s_c = chr(random.randrange(97,123))  # 如randrange(97,123)返回98 → chr(98)=b# 步骤3:生成随机数字(0-9)num = str(random.randrange(0,10))    # 如randrange(0,10)返回5 → str(5)="5"# 步骤4:从大写、小写、数字中随机选1个lst = [b_c,s_c,num]strvar += random.choice(lst)  # 如选到num → strvar="5"(第一次循环)return strvar# 调用函数生成验证码
res = yanzhengma()
print(res)  # 示例输出:B89s
3. 详细运算过程(以生成"B89s"为例)
  • 第1次循环:
    • randrange(65,91) → 66 → chr(66)=B
    • randrange(97,123) → 98 → chr(98)=


17、os模块_os.path模块_time模块_pickle模块_shutil压缩模块_文件夹大小计算

全文总结

模块 核心功能 关键方法/属性
pickle 实现Python对象的序列化(转bytes)和反序列化(恢复原对象) dumps/loads(内存操作)、dump/load(文件操作)
time 时间戳、时间元组、时间字符串的相互转换,程序计时/休眠 time()、localtime()、ctime()、strftime()、strptime()、sleep()、perf_counter()
os 执行系统命令、操作文件/目录、获取系统属性、环境变量 system()、popen()、listdir()、getcwd()、chdir()、environ、name/sep/linesep
os.path 路径处理、文件属性检测(类型/大小/时间) abspath()、basename()、getsize()、isfile()/isdir()、exists()、getmtime()等
shutil 文件/目录的复制、移动、递归删除 copyfile()、copy2()、copytree()、rmtree()、move()
zipfile/tarfile 压缩/解压文件(zip/tar/tar.gz/tar.bz2格式) ZipFile()/TarFile()、write()/add()、extractall()/extract()
文件夹大小计算 递归遍历目录,累加所有文件的大小 结合os.listdir()、os.path.join()、os.path.isfile()/isdir()、os.path.getsize()

1. pickle模块总结

  • 序列化:将列表、函数、迭代器等Python对象转换为bytes类型,解决“非字符串对象无法直接存文件”的问题;
  • 反序列化:将bytes类型恢复为原Python对象;
  • 两种操作方式:内存操作(dumps/loads)、文件操作(dump/load),支持绝大多数Python对象。

2. time模块总结

  • 时间的三种形态:时间戳(浮点数,秒数)、时间元组(struct_time,9个字段)、时间字符串(易读格式);
  • 核心转换逻辑:时间戳↔时间元组↔时间字符串;
  • 辅助功能:程序休眠(sleep)、精准计时(perf_counter)。

3. os & os.path模块总结

  • os:偏向“系统级操作”(执行命令、切换目录、获取系统标识);
  • os.path:偏向“路径和文件属性操作”(路径拼接/拆分、检测文件类型、获取文件大小/时间);
  • 两者结合是Python操作文件/目录的基础。

4. 压缩/文件操作扩展(shutil/zipfile/tarfile)

  • shutil:补充os的不足,实现文件/目录的复制、移动、递归删除;
  • zipfile/tarfile:实现不同格式的压缩包创建、追加、解压,适配不同场景的文件打包需求。

5. 文件夹大小计算总结

  • 核心逻辑:递归遍历目标目录,区分文件/子目录,文件直接累加大小,子目录递归计算后累加;
  • 关键方法:os.listdir()遍历目录、os.path.join()拼接路径、os.path.isfile()/isdir()判断类型、os.path.getsize()获取文件大小。

完整详细讲解(带运算过程)

一、pickle模块(序列化与反序列化)

1. 核心概念
  • 序列化:把无法直接存储的Python对象(列表、函数、迭代器等)转成bytes类型,让其可存储/传输;
  • 反序列化:把bytes类型恢复为原Python对象。
2. 内存操作(dumps/loads)
import pickle# 步骤1:定义待序列化的对象(列表)
listvar = ["刘晨宇","呼和金","精心开"]# 步骤2:dumps序列化 → 转bytes
res = pickle.dumps(listvar)
print("序列化结果(bytes):", res)
# 运算过程:pickle将列表的结构和内容编码为bytes,输出类似:b'\x80\x04\x95\x1e\x00\x00\x00\x00\x00\x00\x00]\x94(\x8c\x05刘晨宇\x94\x8c\x05呼和金\x94\x8c\x04精心开\x94e.'# 步骤3:loads反序列化 → 恢复原对象
res2 = pickle.loads(res)
print("反序列化结果:", res2, "类型:", type(res2))
# 运算过程:pickle解析bytes,还原列表结构和内容,输出:['刘晨宇', '呼和金', '精心开'] <class 'list'>
3. 函数/迭代器的序列化(扩展)
# 函数序列化
def func():print("12345")res_func = pickle.dumps(func)  # 序列化函数(仅存函数引用,不存代码,但本地可恢复)
res_func2 = pickle.loads(res_func)
res_func2()  # 运算过程:反序列化后调用函数,输出:12345# 迭代器序列化
from collections import Iterator
it = iter(range(10))  # 创建0-9的迭代器
print("是否是迭代器:", isinstance(it, Iterator))  # 输出:True
res_it = pickle.dumps(it)
res_it2 = pickle.loads(res_it)
for i in res_it2:print(i, end=" ")  # 运算过程:反序列化迭代器,遍历输出:0 1 2 3 4 5 6 7 8 9
4. 文件操作(dump/load)
# 步骤1:dump → 序列化并写入文件(二进制模式)
listvar = ["刘晨宇","呼和金","精心开"]
with open("ceshi002", mode="wb") as fp:pickle.dump(listvar, fp)  # 运算过程:将列表序列化后写入文件,文件存储bytes内容# 步骤2:load → 读取文件并反序列化
with open("ceshi002", mode="rb") as fp:res = pickle.load(fp)
print("文件反序列化结果:", res)
# 运算过程:读取文件中的bytes,反序列化为列表,输出:['刘晨宇', '呼和金', '精心开']

二、time模块(时间处理)

1. 时间的三种形态
形态 说明 示例
时间戳 从1970-01-01 00:00:00到现在的秒数(浮点数) 1001905710.0
时间元组 struct_time,9个字段(年/月/日/时/分/秒等) time.struct_time(tm_year=2001, ...)
时间字符串 易读的字符串格式 "Wed Jul 3 11:17:36 2019"
2. 核心方法(带运算过程)
import time# 1. 获取时间戳(time())
ts = time.time()
print("当前时间戳:", ts)  # 运算过程:返回当前时间的时间戳,如1719600000.123456# 2. 时间戳 ↔ 时间元组
# (1)时间戳→时间元组(localtime())
ttp = time.localtime(ts)
print("时间戳转时间元组:", ttp)
# 运算过程:解析时间戳,返回struct_time,如time.struct_time(tm_year=2024, tm_mon=6, ...)# (2)时间元组→时间戳(mktime())
ttp_manual = (2001,10,1,11,8,30,0,0,0)
ts2 = time.mktime(ttp_manual)
print("时间元组转时间戳:", ts2)  # 运算过程:计算该时间元组对应的时间戳,输出:1001905710.0# 3. 时间戳 ↔ 时间字符串
# (1)时间戳→时间字符串(ctime())
ts3 = 1001905710.0
time_str = time.ctime(ts3)
print("时间戳转字符串:", time_str)  # 运算过程:解析时间戳,输出:Mon Oct  1 11:08:30 2001# (2)时间元组→时间字符串(asctime(),需先转时间戳再用ctime避免周几错误)
ttp4 = (2019,7,3,11,18,30,0,0,0)
ts4 = time.mktime(ttp4)
time_str2 = time.ctime(ts4)
print("时间元组转字符串(修正周几):", time_str2)  # 输出:Wed Jul  3 11:18:30 2019# 4. 格式化时间(strftime/strptime)
# (1)时间元组→自定义格式字符串(strftime)
fmt_str = time.strftime("%Y-%m-%d %H:%M:%S", ttp4)
print("格式化时间字符串:", fmt_str)  # 运算过程:按指定格式拼接,输出:2019-07-03 11:18:30# (2)自定义字符串→时间元组(strptime)
str_var = "2018-7-3 2:2:2 是生日"
fmt_var = "%Y-%m-%d %H:%M:%S 是生日"
ttp5 = time.strptime(str_var, fmt_var)
print("字符串转时间元组:", ttp5)  # 运算过程:按格式解析字符串,返回对应时间元组# 5. 辅助功能
# (1)程序休眠(sleep)
# time.sleep(2)  # 运算过程:程序暂停2秒后继续# (2)程序计时(perf_counter)
start = time.perf_counter()
for i in range(10000000):pass  # 空循环,模拟耗时操作
end = time.perf_counter()
cost = end - start
print("程序耗时:", cost)  # 运算过程:计算结束时间-开始时间,输出耗时(如0.123秒)

三、os模块(系统与文件操作)

1. 核心功能:执行系统命令、目录操作、系统属性
import os# 1. 执行系统命令(system/popen)
# (1)system:直接执行,无返回值(除退出码)
os.system("ifconfig")  # 运算过程:在终端执行ifconfig命令,输出网卡信息(Linux)# (2)popen:执行并返回对象,read()获取结果
res_popen = os.popen("ifconfig").read()
print("popen执行结果:", res_popen)  # 运算过程:读取命令输出,返回字符串# 2. 目录操作
# (1)listdir:获取目录下所有内容名称
lst_dir = os.listdir(".")  # "."表示当前目录
print("当前目录内容:", lst_dir)  # 运算过程:遍历当前目录,返回文件名/目录名列表# (2)getcwd:获取当前工作目录
curr_path = os.getcwd()
print("当前工作目录:", curr_path)  # 运算过程:返回当前Python脚本的工作路径,如/mnt/hgfs/gongxiang_16/day17# (3)chdir:切换工作目录
os.chdir("/home/wangwen")
os.system("touch wangwen.txt")  # 运算过程:切换到/home/wangwen,创建wangwen.txt文件# 3. 环境变量(environ)
env = os.environ
print("环境变量PATH:", env["PATH"])  # 运算过程:返回系统PATH环境变量字符串
os.environ["PATH"] += ":/home/wangwen"  # 运算过程:追加自定义路径到PATH
os.system("wangwen")  # 运算过程:执行/home/wangwen下的wangwen脚本(需提前创建并赋权)# 4. 系统属性(name/sep/linesep)
print("系统标识:", os.name)  # Linux/Mac输出posix,Windows输出nt
print("路径分隔符:", os.sep)  # Linux/Mac输出/,Windows输出\
print("换行符:", repr(os.linesep))  # Linux/Mac输出'\n',Windows输出'\r\n'

四、os.path模块(路径与文件属性)

import os
import time# 1. 路径处理
# (1)abspath:相对路径转绝对路径
abs_path = os.path.abspath(".")
print("绝对路径:", abs_path)  # 运算过程:将"."转为完整路径,如/mnt/hgfs/gongxiang_16/day17# (2)basename/dirname:拆分文件名/路径
full_path = "/mnt/hgfs/gongxiang_16/day17/3.txt"
file_name = os.path.basename(full_path)
file_dir = os.path.dirname(full_path)
print("文件名:", file_name, "路径:", file_dir)  # 输出:3.txt /mnt/hgfs/gongxiang_16/day17# (3)split:拆分路径为(路径, 文件名)元组
split_res = os.path.split(full_path)
print("路径拆分:", split_res)  # 输出:('/mnt/hgfs/gongxiang_16/day17', '3.txt')# (4)join:拼接路径(自动适配系统分隔符)
path1 = "home"
path2 = "wangwen"
path3 = "biemo.txt"
join_path = os.path.join(path1, path2, path3)
print("路径拼接:", join_path)  # Linux输出home/wangwen/biemo.txt,Windows输出home\wangwen\biemo.txt# (5)splitext:拆分后缀
ext_path = "/mnt/hgfs/gongxiang_16/day17/2.txt"
ext_res = os.path.splitext(ext_path)
print("后缀拆分:", ext_res)  # 输出:('/mnt/hgfs/gongxiang_16/day17/2', '.txt')# 2. 文件属性检测
# (1)getsize:获取文件大小(字节)
size = os.path.getsize("/home/wangwen/2.txt")
print("文件大小:", size, "字节")  # 运算过程:读取文件的字节数,如1024字节# (2)isfile/isdir:检测文件/目录
is_file = os.path.isfile("/mnt/hgfs/gongxiang_16/day17/2.time模块.py")
is_dir = os.path.isdir("/mnt/hgfs/gongxiang_16/day17/ceshi100")
print("是否是文件:", is_file, "是否是目录:", is_dir)  # 输出:True/False(依实际路径)# (3)exists:检测路径是否存在
is_exist = os.path.exists("/home/wangwen/2454545.txt")
print("路径是否存在:", is_exist)  # 输出:False# (4)文件时间(ctime/mtime/atime,返回时间戳)
file_path = "/home/wangwen/2.txt"
ctime = os.path.getctime(file_path)  # Windows创建时间,Linux权限改动时间
mtime = os.path.getmtime(file_path)  # 最后修改时间
atime = os.path.getatime(file_path)  # 最后访问时间
print("创建/权限改动时间:", time.ctime(ctime))
print("最后修改时间:", time.ctime(mtime))
print("最后访问时间:", time.ctime(atime))
# 运算过程:返回时间戳,经ctime转为易读字符串

五、shutil/zipfile/tarfile模块(文件复制/压缩)

1. shutil模块(复制/移动/删除)
import shutil# 1. 复制文件
# (1)copyfile:仅复制内容
shutil.copyfile("src.txt", "dst.txt")  # 运算过程:读取src.txt内容,写入dst.txt# (2)copy2:复制内容+权限+时间等属性
shutil.copy2("src.txt", "dst2.txt")  # 运算过程:复制内容,同时复制文件的权限、修改时间等# 2. 复制目录(递归)
shutil.copytree("src_dir", "dst_dir")  # 运算过程:递归复制src_dir下所有文件/子目录到dst_dir# 3. 移动文件/目录
shutil.move("src.txt", "new_dir/src.txt")  # 运算过程:将src.txt移动到new_dir目录下# 4. 递归删除目录
shutil.rmtree("dst_dir")  # 运算过程:删除dst_dir及其中所有文件/子目录
2. zipfile模块(zip压缩/解压)
import zipfile# 1. 压缩文件
zf = zipfile.ZipFile("test.zip", "w", zipfile.ZIP_DEFLATED)  # w=新建,ZIP_DEFLATED=压缩
zf.write("1.txt", "alias_1.txt")  # 运算过程:将1.txt添加到压缩包,别名为alias_1.txt
zf.close()# 2. 解压文件
zf2 = zipfile.ZipFile("test.zip", "r")
zf2.extractall("unzip_dir")  # 运算过程:解压所有文件到unzip_dir目录
# zf2.extract("alias_1.txt", "unzip_single")  # 仅解压指定文件
zf2.close()# 3. 追加文件
zf3 = zipfile.ZipFile("test.zip", "a")  # a=追加模式
zf3.write("2.txt")
zf3.close()# 4. 查看压缩包内容
zf4 = zipfile.ZipFile("test.zip", "r")
print("压缩包内容:", zf4.namelist())  # 运算过程:返回压缩包内所有文件名称列表
zf4.close()
3. tarfile模块(tar/tar.gz/tar.bz2压缩)
import tarfile# 1. 压缩为tar.gz
tf = tarfile.open("test.tar.gz", "w:gz")  # w:gz=gz压缩
tf.add("1.txt", arcname="alias_1.txt")  # 运算过程:添加1.txt到压缩包,别名alias_1.txt
tf.close()# 2. 解压
tf2 = tarfile.open("test.tar.gz", "r")
tf2.extractall("untar_dir")  # 运算过程:解压所有文件到untar_dir
tf2.close()# 3. 查看内容
tf3 = tarfile.open("test.tar.gz", "r")
print("tar包内容:", tf3.getnames())  # 运算过程:返回压缩包内所有文件名称列表
tf3.close()

六、计算文件夹所有文件的大小(递归实现)

import osdef get_all_size(pathvar):size = 0  # 初始化总大小lst = os.listdir(pathvar)  # 步骤1:遍历目录下所有内容for i in lst:# 步骤2:拼接绝对路径(避免路径错误)path_sub = os.path.join(pathvar, i)# 步骤3:判断是否是文件 → 累加大小if os.path.isfile(path_sub):size += os.path.getsize(path_sub)# 运算过程:如path_sub是1.txt,大小100字节,size变为100# 步骤4:判断是否是目录 → 递归计算子目录大小elif os.path.isdir(path_sub):size += get_all_size(path_sub)# 运算过程:子目录ceshi200内有3.py(200字节),size += 200 → 总size=300return size# 调用函数
target_path = "/mnt/hgfs/gongxiang_16/day17/ceshi100"
total_size = get_all_size(target_path)
print("文件夹总大小:", total_size, "字节")
# 运算过程示例:
# ceshi100/1.txt(100字节) + ceshi100/2.txt(150字节) + ceshi100/ceshi200/3.py(200字节) = 450字节

应用场景及案例(带详细运算过程)

一、pickle模块应用场景

1. 场景:保存/恢复复杂Python对象(如模型参数、复杂数据结构)
2. 案例:保存训练好的机器学习模型(简化版)
import pickle# 模拟训练好的模型(字典存储参数)
model = {"weights": [0.1, 0.2, 0.3],"bias": 0.5,"epoch": 100
}# 步骤1:序列化并保存到文件
with open("model.pkl", "wb") as fp:pickle.dump(model, fp)
# 运算过程:将字典对象序列化为bytes,写入model.pkl文件# 步骤2:读取并反序列化恢复模型
with open("model.pkl", "rb") as fp:loaded_model = pickle.load(fp)
print("恢复的模型参数:", loaded_model)
# 运算过程:读取model.pkl中的bytes,反序列化为原字典,输出:
# {'weights': [0.1, 0.2, 0.3], 'bias': 0.5, 'epoch': 100}

二、time模块应用场景

1. 场景:日志记录(带时间戳)、程序性能分析
2. 案例:记录函数执行时间并输出带格式的日志
import timedef test_func():# 模拟耗时操作sum_val = 0for i in range(1000000):sum_val += ireturn sum_val# 步骤1:记录开始时间
start_time = time.perf_counter()# 步骤2:执行函数
result = test_func()# 步骤3:记录结束时间,计算耗时
end_time = time.perf_counter()
cost_time = end_time - start_time# 步骤4:生成带格式的日志时间
log_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())# 步骤5:输出日志
print(f"[{log_time}] 函数执行完成,结果:{result},耗时:{cost_time:.4f}秒")
# 运算过程:
# 1. perf_counter()获取开始/结束时间,差值为耗时(如0.0234秒);
# 2. localtime()获取当前时间元组,strftime格式化为"2024-06-29 15:30:00";
# 3. 输出日志:[2024-06-29 15:30:00] 函数执行完成,结果:499999500000,耗时:0.0234秒

三、os & os.path模块应用场景

1. 场景:批量处理文件(遍历目录、筛选文件)
2. 案例:遍历指定目录,筛选所有txt文件并输出大小
import os
import timedef filter_txt_files(dir_path):txt_files = []# 步骤1:遍历目录for file_name in os.listdir(dir_path):# 步骤2:拼接绝对路径file_path = os.path.join(dir_path, file_name)# 步骤3:筛选txt文件且是文件(非目录)if os.path.isfile(file_path) and file_path.endswith(".txt"):# 步骤4:获取文件大小和最后修改时间file_size = os.path.getsize(file_path)modify_time = time.ctime(os.path.getmtime(file_path))txt_files.append({"name": file_name,"path": file_path,"size": file_size,"modify_time": modify_time})return txt_files# 调用函数
target_dir = "/home/wangwen"
txt_list = filter_txt_files(target_dir)
# 步骤5:输出结果
for txt in txt_list:print(f"文件名:{txt['name']},路径:{txt['path']},大小:{txt['size']}字节,最后修改:{txt['modify_time']}")# 运算过程示例:
# 遍历/home/wangwen,找到1.txt:
# - isfile(1.txt) → True,endswith(.txt) → True;
# - getsize(1.txt) → 512字节;
# - getmtime(1.txt) → 1719599999.0 → ctime转为"Sat Jun 29 15:29:59 2024";
# 输出:文件名:1.txt,路径:/home/wangwen/1.txt,大小:512字节,最后修改:Sat Jun 29 15:29:59 2024

四、shutil/zipfile模块应用场景

1. 场景:批量备份文件(复制+压缩)
2. 案例:备份指定目录的所有txt文件到zip压缩包
import os
import shutil
import zipfile# 步骤1:创建临时目录,复制txt文件
temp_dir = "/home/wangwen/temp_backup"
if not os.path.exists(temp_dir):os.mkdir(temp_dir)  # 创建临时目录target_dir = "/home/wangwen"
for file_name in os.listdir(target_dir):file_path = os.path.join(target_dir, file_name)if os.path.isfile(file_path) and file_path.endswith(".txt"):shutil.copy2(file_path, temp_dir)  # 复制txt文件到临时目录# 运算过程:复制1.txt、2.txt到temp_backup# 步骤2:压缩临时目录为zip包
backup_zip = "/home/wangwen/txt_backup.zip"
zf = zipfile.ZipFile(backup_zip, "w", zipfile.ZIP_DEFLATED)# 遍历临时目录,添加到压缩包
for root, dirs, files in os.walk(temp_dir):for file in files:file_path = os.path.join(root, file)# 计算压缩包内的相对路径arcname = os.path.relpath(file_path, temp_dir)zf.write(file_path, arcname)# 运算过程:将temp_backup/1.txt添加到压缩包,别名1.txtzf.close()# 步骤3:删除临时目录
shutil.rmtree(temp_dir)
# 运算过程:删除temp_backup及其中所有文件print(f"备份完成!压缩包路径:{backup_zip}")
# 最终结果:生成txt_backup.zip,包含所有txt文件,临时目录被清理

五、文件夹大小计算应用场景

1. 场景:磁盘空间分析(统计目录占用大小)
2. 案例:统计用户目录下各子目录的大小,输出TOP3
import osdef get_dir_size(dir_path):# 复用之前的递归计算函数size = 0for item in os.listdir(dir_path):item_path = os.path.join(dir_path, item)if os.path.isfile(item_path):size += os.path.getsize(item_path)elif os.path.isdir(item_path):size += get_dir_size(item_path)return size# 步骤1:指定根目录
root_dir = "/home/wangwen"# 步骤2:遍历根目录下的子目录,计算每个子目录大小
dir_sizes = []
for item in os.listdir(root_dir):item_path = os.path.join(root_dir, item)if os.path.isdir(item_path):dir_size = get_dir_size(item_path)dir_sizes.append((item, dir_size))# 运算过程:# 子目录dir1 → 计算大小为1024000字节;# 子目录dir2 → 计算大小为2048000字节;# 子目录dir3 → 计算大小为1536000字节;# 步骤3:按大小降序排序,取TOP3
dir_sizes.sort(key=lambda x: x[1], reverse=True)
top3 = dir_sizes[:3]# 步骤4:输出结果(转换为MB,1MB=1024*1024字节)
print("目录大小TOP3(单位:MB):")
for dir_name, size in top3:size_mb = size / (1024 * 1024)print(f"{dir_name}: {size_mb:.2f} MB")# 运算过程输出:
# 目录大小TOP3(单位:MB):
# dir2: 1.95 MB
# dir3: 1.47 MB
# dir1: 0.98 MB


18、os_shutil_json_pickle_zipfile_tarfile

全文总结

表格版总结

模块 核心功能 关键特性/限制
os 文件/目录的创建、删除、重命名、路径操作 支持单层/递归创建/删除目录,可修改工作路径、获取系统标识/路径分隔符等
shutil 文件/目录的复制、移动 支持文件内容/权限/状态复制,递归拷贝/删除目录,移动文件/目录
json 跨语言数据序列化/反序列化 序列化后为str,支持基础数据类型,不能连续load,需分行存储后逐行loads
pickle Python专属数据序列化 序列化后为bytes,支持所有Python类型,可连续load,仅限Python间传输存储
zipfile ZIP格式压缩/解压 支持创建、解压、追加文件,可指定压缩算法,查看压缩包内容
tarfile TAR/TAR.GZ/TAR.BZ2压缩 支持不同压缩算法(gz/bz2),纯tar可追加文件,压缩后的包(gz/bz2)不可直接追加

分段版总结

  1. 文件/目录操作(os + shutil)

    • os负责「基础增删改」:创建/删除文件/目录、重命名、修改工作路径、获取系统/路径相关属性;
    • shutil负责「复制/移动」:弥补os的不足,支持文件内容/权限/状态的复制,递归拷贝/删除目录、移动文件/目录。
  2. 数据序列化(json + pickle)

    • json是「跨语言通用方案」:仅支持基础数据类型,序列化后为字符串,无法连续读取多组数据,需手动分行处理;
    • pickle是「Python专属方案」:支持所有Python数据类型,序列化后为字节流,可连续读取多组数据,仅限Python使用。
  3. 压缩解压(zipfile + tarfile)

    • zipfile:处理ZIP格式,支持创建、解压、追加文件,指定压缩算法(存储/DEFLATED);
    • tarfile:处理TAR/TAR.GZ/TAR.BZ2格式,bz2压缩率更高,纯TAR包可追加文件,压缩后的包需解压后重新压缩才能追加。

完整详细输出(分步讲解+运算过程)

一、os模块:文件/目录基础操作

os模块是Python操作操作系统文件/目录的核心,重点掌握「创建、删除、重命名、路径/系统属性」。

1. 核心方法(带运算过程)
import os# 1. 修改当前工作路径(运算:切换到指定目录,后续操作基于此路径)
os.chdir("/home/wangwen/")  # 执行后,当前工作路径变为/home/wangwen/# 2. 创建/删除文件
os.mknod("ceshi01.txt")    # 运算:在当前路径创建空文件ceshi01.txt
os.remove("ceshi01.txt")   # 运算:删除当前路径下的ceshi01.txt# 3. 创建/删除单层目录
os.mkdir("ceshi003")       # 运算:创建空目录ceshi003
os.rmdir("ceshi003")       # 运算:删除空目录ceshi003(非空则报错)# 4. 重命名文件/目录
os.rename("ceshi003", "ceshi004")  # 运算:将目录ceshi003改名为ceshi004# 5. 递归创建/删除目录
os.makedirs("./a/b/c/d")   # 运算:递归创建多层目录a/b/c/d(相对路径)
os.removedirs("./a/b/c/d") # 运算:递归删除空目录a/b/c/d(需所有子目录为空)# 6. 获取系统/路径属性(运算结果示例)
print(os.name)       # 运算结果:linux/mac输出posix,windows输出nt
print(os.sep)        # 运算结果:linux/mac输出/,windows输出\
print(os.getcwd())   # 运算结果:返回当前工作路径,如/home/wangwen/
print(os.listdir("."))# 运算结果:返回当前路径下所有文件/目录名称列表

二、shutil模块:文件/目录复制&移动

shutil基于os扩展,重点解决「复制、移动」需求,弥补os的不足。

1. 核心方法(带运算过程)
import shutil# 1. 复制文件内容(底层调用copyfileobj)
shutil.copyfile("1.txt", "3.txt")  # 运算:仅复制1.txt的内容到3.txt,权限不变# 2. 复制文件内容+权限
shutil.copy("1.txt", "5.txt")     # 运算:复制1.txt的内容+权限到5.txt# 3. 复制文件内容+权限+状态(用户/组/修改时间等)
shutil.copy2("1.txt", "6.txt")    # 运算:比copy多复制文件的状态信息# 4. 递归拷贝目录(含所有子文件/目录)
shutil.copytree("ceshi500", "myceshi")  # 运算:把ceshi500的所有内容拷贝到myceshi# 5. 递归删除目录(含所有内容)
shutil.rmtree("myceshi")          # 运算:删除myceshi目录及其中所有文件/子目录# 6. 移动文件/目录
shutil.move("ceshi001", "mysoft") # 运算:把ceshi001(文件/目录)移动到mysoft目录下

三、json模块:跨语言数据序列化

序列化:把Python对象转成通用字符串;反序列化:把字符串转回Python对象。

1. 核心方法(带运算过程)
import json# 原始数据
dictvar = {"name":"胡哲","sex":"中性","age":89,"family":["哥哥","爸爸","妈妈"]}# 1. dumps:序列化(Python对象→JSON字符串)
res1 = json.dumps(dictvar, ensure_ascii=False)  # ensure_ascii=False:显示中文
# 运算结果:res1是字符串,内容为{"name":"胡哲","sex":"中性","age":89,"family":["哥哥","爸爸","妈妈"]}
res2 = json.dumps(dictvar, sort_keys=True, ensure_ascii=False) # sort_keys=True:按键排序
# 运算结果:字符串按键排序,如{"age":89,"family":["哥哥","爸爸","妈妈"],"name":"胡哲","sex":"中性"}# 2. loads:反序列化(JSON字符串→Python对象)
dic = json.loads(res1)
# 运算结果:dic是字典,和原始dictvar一致,类型为dict# 3. dump:序列化并写入文件
with open("ceshi001.txt", "w", encoding="utf-8") as fp:json.dump(dictvar, fp, ensure_ascii=False)
# 运算:把dictvar序列化后写入ceshi001.txt,文件内容为JSON字符串# 4. load:从文件读取并反序列化
with open("ceshi001.txt", "r", encoding="utf-8") as fp:dic = json.load(fp)
# 运算:读取文件内容,反序列化为字典,和原始dictvar一致# 5. 多组数据存储/读取(json无法直接连续load,需分行处理)
dic1 = {"a":1,"b":2}
dic2 = {"c":3,"d":4}
# 存储:逐行dump
with open("ceshi002.json", "w", encoding="utf-8") as fp:json.dump(dic1, fp)fp.write("\n")  # 手动换行json.dump(dic2, fp)fp.write("\n")
# 读取:逐行loads
with open("ceshi002.json", "r", encoding="utf-8") as fp:for line in fp:dic = json.loads(line.strip())  # strip()去除换行符# 运算结果:第一次循环dic={"a":1,"b":2},第二次={"c":3,"d":4}print(dic)

四、pickle模块:Python专属序列化

序列化后为bytes,支持所有Python类型,可连续load,仅限Python使用。

1. 核心方法(带运算过程)
import pickle# 原始数据
dic3 = {"e":5,"f":6}
dic4 = {"g":7,"h":8}# 1. dump:序列化并写入文件(需二进制模式wb)
with open("ceshi003.pkl", "wb") as fp:pickle.dump(dic3, fp)pickle.dump(dic4, fp)  # 可连续dump# 2. load:从文件读取并反序列化(需二进制模式rb)
# 方法1:逐次load
with open("ceshi003.pkl", "rb") as fp:res1 = pickle.load(fp)  # 运算结果:res1={"e":5,"f":6}res2 = pickle.load(fp)  # 运算结果:res2={"g":7,"h":8}# 方法2:循环load(兼容多组数据)
with open("ceshi003.pkl", "rb") as fp:try:while True:res = pickle.load(fp)print(res)  # 运算结果:先输出{"e":5,"f":6},再输出{"g":7,"h":8}except EOFError:  # 读取到文件末尾触发异常,捕获后退出pass

五、zipfile模块:ZIP格式压缩/解压

处理.zip后缀的压缩包,支持创建、解压、追加、查看内容。

1. 核心方法(带运算过程)
import zipfile# 1. 创建压缩包(ZIP_DEFLATED:压缩;ZIP_STORED:仅打包)
zf = zipfile.ZipFile("ceshi0704.zip", "w", zipfile.ZIP_DEFLATED)
zf.write("/bin/bzgrep", "bzgrep")  # 运算:把/bin/bzgrep添加到压缩包,别名为bzgrep
zf.write("/bin/bzip2", "bzip2")    # 运算:添加/bin/bzip2,别名为bzip2
zf.write("/bin/bzmore", "/tmp/bzmore")  # 运算:添加/bin/bzmore,放到压缩包的tmp目录下
zf.close()  # 运算:关闭压缩包,完成创建# 2. 解压压缩包
zf = zipfile.ZipFile("ceshi0704.zip", "r")
zf.extractall("ceshi0704")  # 运算:解压所有内容到ceshi0704目录
zf.extract("bzip2", "ceshi070444444")  # 运算:仅解压bzip2到ceshi070444444目录
zf.close()# 3. 追加文件(a模式)
with zipfile.ZipFile("ceshi0704.zip", "a", zipfile.ZIP_DEFLATED) as zf:zf.write("/bin/chmod", "chmod")  # 运算:把/bin/chmod追加到压缩包# 4. 查看压缩包内容
with zipfile.ZipFile("ceshi0704.zip", "r") as zf:res = zf.namelist()  # 运算结果:返回压缩包内所有文件/目录名称列表,如['bzgrep','bzip2','tmp/bzmore','chmod']
print(res)

六、tarfile模块:TAR/TAR.GZ/TAR.BZ2压缩/解压

支持.tar(仅打包)、.tar.gz(gz压缩)、.tar.bz2(bz2压缩,压缩率更高)。

1. 核心方法(带运算过程)
import tarfile
import os# 1. 创建压缩包
# ① 仅打包(.tar)
tf = tarfile.open("ceshi0704_2.tar", "w", encoding="utf-8")
tf.add("/bin/echo", "echo")  # 运算:添加/bin/echo,别名为echo
tf.add("/bin/ed", "ed2")     # 运算:添加/bin/ed,别名为ed2
tf.close()# ② gz压缩(.tar.gz)
tf = tarfile.open("ceshi0704_3.tar.gz", "w:gz", encoding="utf-8")
tf.add("/bin/echo", "echo")
tf.close()  # 运算:生成gz压缩包,体积比纯tar小# ③ bz2压缩(.tar.bz2,压缩率更高)
tf = tarfile.open("ceshi0704_4.tar.bz2", "w:bz2", encoding="utf-8")
tf.add("/bin/echo", "echo")
tf.close()# 2. 解压压缩包
tf = tarfile.open("ceshi0704_3.tar.gz", "r")
tf.extractall("ceshi0704_3")  # 运算:解压所有内容到ceshi0704_3目录
tf.extract("echo", "ceshiecho")  # 运算:仅解压echo到ceshiecho目录
tf.close()# 3. 追加文件(仅纯.tar包支持,gz/bz2不支持)
with tarfile.open("ceshi0704_2.tar", "a", encoding="utf-8") as tf:tf.add("/bin/fuser", "fuser")  # 运算:追加/bin/fuser到纯tar包# 4. 查看压缩包内容
with tarfile.open("ceshi0704_4.tar.bz2", "r", encoding="utf-8") as tf:res = tf.getnames()  # 运算结果:返回压缩包内文件列表,如['echo','ed2']
print(res)# 5. 解决gz/bz2包无法追加的问题(解压→追加→重新压缩)
# ① 解压原压缩包
path2 = os.path.join(os.getcwd(), "ceshi0704_4")
with tarfile.open("ceshi0704_4.tar.bz2", "r", encoding="utf-8") as tf:tf.extractall(path2)  # 运算:解压到ceshi0704_4目录# ② 追加文件(复制/bin/more到解压目录)
os.system(f"cp -a /bin/more {path2}")  # 运算:把/bin/more复制到ceshi0704_4目录# ③ 重新压缩(过滤ed2文件)
path1 = os.path.join(os.getcwd(), "ceshi0704_4.tar.bz2")
lst = os.listdir(path2)  # 运算:获取解压目录下的文件列表,如['echo','ed2','more']
with tarfile.open(path1, "w:bz2") as tf:for i in lst:pathvar = os.path.join(path2, i)if i != "ed2":  # 过滤ed2文件tf.add(pathvar, i)  # 运算:重新压缩,仅包含echo和more

应用场景及案例(带详细运算过程)

一、os + shutil:项目文件整理

场景描述

批量整理项目目录:创建「data/raw」「data/processed」目录,把原始数据文件复制到raw,处理后的文件移动到processed,删除临时文件。

案例代码+运算过程
import os
import shutil# 步骤1:递归创建目录(运算:创建data/raw和data/processed两层目录)
os.makedirs("./data/raw", exist_ok=True)  # exist_ok=True:目录已存在不报错
os.makedirs("./data/processed", exist_ok=True)# 步骤2:复制原始数据到raw目录(运算:把local_raw_data.csv复制到data/raw)
shutil.copy2("local_raw_data.csv", "./data/raw/raw_data.csv")# 步骤3:模拟处理数据后,移动文件到processed(运算:把processed_data.csv移动到data/processed)
shutil.move("processed_data.csv", "./data/processed/")# 步骤4:删除临时文件(运算:删除临时生成的tmp_data.csv)
os.remove("tmp_data.csv")# 步骤5:查看目录结构(运算:输出data目录下的子目录/文件)
print(os.listdir("./data"))  # 运算结果:['raw', 'processed']
print(os.listdir("./data/raw"))  # 运算结果:['raw_data.csv']

二、json:跨语言数据交互(Python→前端/Java)

场景描述

Python后端生成用户数据,序列化为JSON字符串,供前端/Java程序读取(JSON是跨语言通用格式)。

案例代码+运算过程
import json# 步骤1:Python生成用户数据(原始对象)
user_data = [{"id": 1, "name": "张三", "age": 25, "is_vip": True},{"id": 2, "name": "李四", "age": 30, "is_vip": False}
]# 步骤2:序列化为JSON字符串(确保中文显示,按id排序)
json_str = json.dumps(user_data, ensure_ascii=False, sort_keys=True)
# 运算结果:
# [{"age":25,"id":1,"is_vip":true,"name":"张三"},{"age":30,"id":2,"is_vip":false,"name":"李四"}]
print(json_str, type(json_str))  # 类型为str# 步骤3:写入文件(供前端/Java读取)
with open("user_data.json", "w", encoding="utf-8") as fp:json.dump(user_data, fp, ensure_ascii=False)# 步骤4:前端/Java读取后,Python模拟反序列化(验证数据)
with open("user_data.json", "r", encoding="utf-8") as fp:data = json.load(fp)
# 运算结果:data是列表,和原始user_data一致,可遍历使用
for user in data:print(f"用户{user['name']},年龄{user['age']}")  # 输出:用户张三,年龄25;用户李四,年龄30

三、pickle:Python内数据持久化

场景描述

Python程序中训练好的机器学习模型(复杂对象,如sklearn的模型),需要保存到文件,下次直接加载使用(json不支持复杂对象,pickle专属)。

案例代码+运算过程
import pickle
from sklearn.linear_model import LinearRegression
import numpy as np# 步骤1:模拟训练模型(复杂Python对象)
X = np.array([[1, 1], [1, 2], [2, 2], [2, 3]])
y = np.dot(X, np.array([1, 2])) + 3
model = LinearRegression()
model.fit(X, y)  # 运算:训练线性回归模型# 步骤2:序列化模型到文件(二进制模式)
with open("model.pkl", "wb") as fp:pickle.dump(model, fp)  # 运算:把模型对象序列化为bytes,写入文件# 步骤3:反序列化加载模型(直接使用)
with open("model.pkl", "rb") as fp:loaded_model = pickle.load(fp)  # 运算:读取bytes,反序列化为模型对象# 步骤4:验证模型(运算:用加载的模型预测,结果和原模型一致)
test_X = np.array([[3, 4]])
pred = loaded_model.predict(test_X)
print(pred)  # 运算结果:[14.](原模型计算:3*1 +4*2 +3=14)

四、zipfile:多文件打包分发

场景描述

把项目的「代码文件、配置文件、数据文件」打包为ZIP压缩包,分发给同事(跨平台通用,Windows/Linux都支持)。

案例代码+运算过程
import zipfile
import os# 步骤1:定义要打包的文件列表
files = [("app.py", "app.py"),          # 本地文件→压缩包内别名("config.ini", "config.ini"),  # 配置文件("data.csv", "data/data.csv")  # 数据文件→压缩包内data目录
]# 步骤2:创建ZIP压缩包(压缩模式)
with zipfile.ZipFile("project.zip", "w", zipfile.ZIP_DEFLATED) as zf:for src, dst in files:zf.write(src, dst)  # 运算:逐个添加文件到压缩包,按别名组织目录print(f"已添加{src}到压缩包,路径为{dst}")# 步骤3:查看压缩包内容(验证)
with zipfile.ZipFile("project.zip", "r") as zf:content = zf.namelist()
# 运算结果:content = ['app.py','config.ini','data/data.csv']
print("压缩包内容:", content)# 步骤4:解压测试(同事接收后解压)
with zipfile.ZipFile("project.zip", "r") as zf:zf.extractall("project")  # 运算:解压到project目录,生成app.py、config.ini、data/data.csv
print("解压完成,project目录结构:", os.listdir("project"))

五、tarfile:大文件高效压缩(Linux服务器)

场景描述

Linux服务器上的日志文件(体积大),需要压缩归档(bz2压缩率高,节省磁盘空间),且需要过滤掉无用日志。

案例代码+运算过程
import tarfile
import os# 步骤1:定义日志目录和要压缩的文件(过滤.log.bak备份文件)
log_dir = "./logs"
files_to_compress = []
for file in os.listdir(log_dir):if file.endswith(".log") and not file.endswith(".log.bak"):  # 过滤备份文件files_to_compress.append(os.path.join(log_dir, file))# 步骤2:创建bz2压缩包(高压缩率)
with tarfile.open("logs_2024.tar.bz2", "w:bz2", encoding="utf-8") as tf:for file in files_to_compress:# 运算:添加日志文件,压缩包内保留原文件名tf.add(file, os.path.basename(file))print(f"已压缩{file}")# 步骤3:查看压缩包内容
with tarfile.open("logs_2024.tar.bz2", "r", encoding="utf-8") as tf:content = tf.getnames()
# 运算结果:content = ['access.log','error.log'](假设logs目录有这两个log文件)
print("压缩包内容:", content)# 步骤4:解压到指定目录(需要查看日志时)
with tarfile.open("logs_2024.tar.bz2", "r") as tf:tf.extractall("./extracted_logs")  # 运算:解压到extracted_logs目录
print("解压完成,日志文件:", os.listdir("./extracted_logs"))


19、面向对象OOP_类_对象_封装_成员权限_方法

全文总结-面向对象

1. 核心概念总结(表格)

核心概念 核心说明
抽象模板,定义一类事物的属性和方法;仅包含属性/方法(禁止裸写判断/循环);命名用「大驼峰」(如MyCar、Plane)
对象 类的具体实例(类只有1个,对象可实例化多个);对象可使用类的公有成员,但无归属权
封装 保护类的成员,控制外界访问;分「公有(public)」和「私有(private)」两个等级
成员权限 公有:类内/外均可访问;私有(加__):仅类内访问,类外可通过「_类名__成员名」绕过(非推荐)
方法类型 普通方法(无参数,仅类调用);绑定方法(带self,对象调用时自动传自身);静态方法(无参数,类/对象均可调用)
类/对象操作 均可动态添加/删除公有成员;私有成员仅类内可操作,类外无法直接修改/删除

2. 核心规则总结(分段)

  • 类的私有成员(属性/方法)在类外无法直接访问,但可通过「_类名__成员名」强制访问(仅了解,开发中禁止);
  • 对象可「覆盖」类的公有成员(对象同名成员优先),删除对象成员后会恢复使用类的成员;
  • 类无法访问对象的专属成员,对象可访问类的公有成员;
  • 类/对象的操作仅针对「公有成员」生效,私有成员仅类内可控。

完整详细讲解(带步骤+运算过程)

步骤1:类与对象的基础定义

1.1 类的定义(3种写法,推荐第二种)
# 写法1:最简
class Car:pass# 写法2:推荐(显式空括号)
class Car():# 公有属性color = "天蓝色"# 私有属性(加__)__oil = "1.5L"# 公有绑定方法(带self,对象调用)def run(self):print("小车会跑")# 私有绑定方法(加__)def __oil_info(self):print(f"油耗:{self.__oil}")# 普通方法(无参数,仅类调用)def horn():print("小车滴滴叫")# 写法3:继承object(等同于写法2)
class Car(object):pass
1.2 类的实例化(创建对象)
# 实例化对象:类名()
obj = Car()# 运算过程&结果:
# obj是Car类的具体实例,此时obj本身无任何成员(__dict__为空)
print(obj.__dict__)  # 输出:{}

步骤2:公有/私有成员的访问规则

2.1 访问公有成员(类内+类外均可)
# ① 对象访问公有属性/方法
print(obj.color)  # 运算结果:天蓝色
obj.run()         # 运算结果:小车会跑# ② 类访问公有属性/方法
print(Car.color)  # 运算结果:天蓝色
Car.horn()        # 运算结果:小车滴滴叫
2.2 访问私有成员(仅类内可直接访问)
# 错误:类外直接访问私有属性/方法
# print(obj.__oil)       # 报错:AttributeError
# obj.__oil_info()       # 报错:AttributeError# 正确1:类内访问(通过公有方法间接暴露)
class Car():__oil = "1.5L"def get_oil(self):self.__oil_info()  # 类内调用私有方法return self.__oil  # 类内访问私有属性obj = Car()
print(obj.get_oil())  # 运算过程:先执行__oil_info()输出「油耗:1.5L」,再返回1.5L# 正确2:类外强制访问(改名策略:_类名__成员名)
print(obj._Car__oil)    # 运算结果:1.5L
obj._Car__oil_info()    # 运算结果:油耗:1.5L

步骤3:类/对象的增删改操作

3.1 对象的动态操作(添加/修改/删除公有成员)
obj = Car()
# ① 动态添加属性
obj.color = "屎黄色"  # 覆盖类的color
obj.money = "10万"    # 新增对象专属属性
print(obj.__dict__)   # 运算结果:{'color': '屎黄色', 'money': '10万'}
print(obj.color)      # 运算结果:屎黄色(优先对象自身)# ② 动态添加方法
# 无参方法
def beitai():print("我是备胎")
obj.beitai = beitai
obj.beitai()  # 运算结果:我是备胎# lambda方法
obj.dipan = lambda : print("制造底盘")
obj.dipan()   # 运算结果:制造底盘# ③ 删除对象成员
del obj.color
print(obj.color)  # 运算结果:天蓝色(恢复使用类的属性)
del obj.beitai
# obj.beitai()  # 报错:AttributeError(对象无此方法)
3.2 类的动态操作(添加/修改/删除公有成员)
# ① 动态添加属性
Car.color = "鸭屎绿"
Car.price = "500亿"
print(Car.__dict__)  # 运算结果:包含color、price等公有属性# ② 动态添加方法
def dahuangfeng():print("大黄蜂")
Car.dahuangfeng = dahuangfeng
Car.dahuangfeng()  # 运算结果:大黄蜂# ③ 删除类的成员
del Car.horn
# Car.horn()  # 报错:AttributeError(类无此方法)# 注意:无法删除类的私有成员
# del Car.__oil  # 报错:AttributeError

步骤4:核心规则验证(类与对象的成员归属)

# ① 对象可使用类的成员,但类无法使用对象的成员
obj = Car()
obj.money = "10万"
# print(Car.money)  # 报错:AttributeError(类无此属性)# ② 类添加成员,对象可直接使用
Car.mashaji = "按摩员"
print(obj.mashaji)  # 运算结果:按摩员# ③ 私有成员仅类内可操作
class Plane():__captain = "陈雪斌"def public_func1(self):print(self.__captain)  # 类内访问私有属性
Plane.public_func1(obj)  # 运算结果:陈雪斌

应用场景及案例(带详细运算过程)

场景1:用户信息封装(保护敏感数据)

需求:

定义用户类,保护「手机号」「密码」等私有信息,仅通过公有方法暴露/修改,防止外部直接篡改。

代码实现+运算过程:
### 定义类
class User():# 公有属性username = "zhangsan"# 私有属性(敏感数据)__phone = "13888888888"__password = "123456"# 公有方法:获取手机号(可控暴露)def get_phone(self):# 可添加权限校验(如验证身份)return f"脱敏手机号:{self.__phone[:3]}****{self.__phone[-4:]}"# 公有方法:修改密码(可控修改)def change_pwd(self, old_pwd, new_pwd):if old_pwd == self.__password:self.__password = new_pwdreturn "密码修改成功"else:return "原密码错误"### 实例化对象
user = User()### 运算过程1:访问公有属性
print(user.username)  # 结果:zhangsan### 运算过程2:获取脱敏手机号(通过公有方法)
print(user.get_phone())  # 结果:脱敏手机号:138****8888### 运算过程3:修改密码(正确原密码)
res1 = user.change_pwd("123456", "654321")
print(res1)  # 结果:密码修改成功
# 验证密码是否修改(强制访问私有属性)
print(user._User__password)  # 结果:654321### 运算过程4:修改密码(错误原密码)
res2 = user.change_pwd("111111", "654321")
print(res2)  # 结果:原密码错误

场景2:汽车管理系统(类/对象的动态操作)

需求:

动态管理汽车的属性(如颜色、油耗),支持新增配置、删除无用配置,保护核心参数(如价格)不被外部修改。

代码实现+运算过程:
### 定义类
class CarSystem():# 公有属性brand = "特斯拉"oil = "1.5L"# 私有属性(核心价格)__price = "50万"# 普通方法(仅类调用)def oil_info():print(f"基础油耗:{CarSystem.oil}")### 实例化对象
car1 = CarSystem()### 运算过程1:动态添加车辆配置(对象级别)
car1.color = "红色"
car1.max_speed = "250km/h"
print(car1.__dict__)  # 结果:{'color': '红色', 'max_speed': '250km/h'}
print(car1.color)     # 结果:红色### 运算过程2:动态添加类的通用配置(所有对象生效)
CarSystem.wheel = "4个"
print(car1.wheel)     # 结果:4个
car2 = CarSystem()
print(car2.wheel)     # 结果:4个(新对象也有该属性)### 运算过程3:删除无用配置
del car1.max_speed
# print(car1.max_speed)  # 报错:AttributeError
del CarSystem.wheel
# print(car2.wheel)      # 报错:AttributeError### 运算过程4:保护核心价格(私有属性)
# print(CarSystem.__price)  # 报错:AttributeError
# 仅类内可访问
class CarSystem():__price = "50万"def get_price(self):return self.__price
car1 = CarSystem()
print(car1.get_price())  # 结果:50万

核心总结

  1. 封装的核心是「可控访问」:私有成员保护敏感数据,公有方法对外提供统一接口;
  2. 类是模板,对象是实例,对象可自定义专属成员,但类无法访问;
  3. 动态增删改仅针对「公有成员」,私有成员仅类内可操作;
  4. 开发中禁止使用「_类名__成员名」强制访问私有成员,需通过类提供的公有方法操作。


20、类的定义与实例化_继承_super_多态_魔术方法

全文总结

1. 核心知识点表格总结

核心模块 关键知识点 核心规则/特点
面向对象基础 类、对象、实例化 1. 类是模板,对象是类的具体实例;
2. 类包含属性(特征)和方法(行为);
3. 对象可调用类的公有成员,类不能调用对象成员
封装 公有/私有成员 1. 公有:类内、子类、外部均可访问;
2. 私有(加__):仅类内可访问;
3. 私有成员改名策略:_类名__成员名
继承 单继承、多继承、菱形继承 1. 单继承:子类继承一个父类,可调用父类公有成员、重写父类方法;
2. 多继承:子类继承多个父类,用逗号分隔;
3. 菱形继承:super按C3算法(广度优先)调用,可通过mro()查看顺序
super用法 super()对象 1. super是类,super()是对象,用于调用父类绑定方法;
2. self优先调用自身成员,super优先调用父类成员;
3. 仅用于绑定方法,自动传self
多态 继承+方法重写 1. 不同子类对象调用同一父类方法,执行不同逻辑;
2. 优势:不修改原有代码,扩展不同效果
魔术方法 init/__str__等 1. 特定时机自动触发;
2. init:实例化时初始化,给对象加成员;
3. 不同魔术方法有固定触发场景和返回值要求

2. 分段核心总结

2.1 面向对象核心逻辑
  • 类与对象:类是抽象“模板”(如“人类”),对象是模板生成的具体实例(如“张三”);实例化是通过类创建对象的过程。
  • 成员访问:对象可调用类的公有属性/方法,多个对象之间相互独立,属性互不干扰。
2.2 封装:控制成员访问权限
  • 公有成员:无特殊前缀,任意位置可访问;
  • 私有成员:前缀加__,仅类内部可访问,子类和外部直接调用会报错;
  • 间接访问私有成员:可通过类内公有方法调用。
2.3 继承:代码复用的核心
  • 单继承:子类继承一个父类,可复用父类公有成员,也可重写父类方法;若子类无构造方法,自动调用父类构造方法。
  • 多继承:子类继承多个父类,需注意方法名冲突问题,尽量避免同名方法。
  • 菱形继承:多继承的特殊场景,super()按mro列表(广度优先)解决调用顺序问题。
2.4 多态:灵活扩展代码
  • 核心是“继承+方法重写”,让同一行为有不同实现;
  • 常用场景:批量处理不同子类对象,根据对象类型执行不同逻辑。
2.5 魔术方法:简化对象操作
  • __init__是最常用的魔术方法,用于初始化对象属性;
  • 每个魔术方法有固定触发条件(如print对象触发__str__),需遵守参数和返回值规则。

完整详细内容(新人一步步理解)

步骤1:理解类与对象(基础)

1.1 类的定义与实例化

类是“模板”,定义格式:

class 类名():# 公有属性(所有对象共享)公有属性 = 值# 构造方法(初始化对象,实例化时自动触发)def __init__(self, 参数1, 参数2):# 对象的私有属性(仅当前对象可用)self.属性1 = 参数1self.属性2 = 参数2# 公有方法(对象的行为)def 方法名(self):方法逻辑

示例:定义“小孩”类,实例化多个对象

class Children():# 类的公有属性type = "人类幼崽"# 构造方法:初始化对象属性def __init__(self, name, skin):self.name = name  # 姓名self.skin = skin  # 肤色# 打印对象信息的方法def children_info(self):strvar = f"姓名:{self.name},肤色:{self.skin},类型:{self.type}"print(strvar)# 实例化对象(触发__init__,传入参数)
obj1 = Children("刘钢蛋", "黑色")
obj2 = Children("赵铁锤", "屎黄色")# 调用对象方法
obj1.children_info()
obj2.children_info()

详细运算过程

  1. 执行class Children()::定义类,创建公有属性type = "人类幼崽"
  2. 执行obj1 = Children("刘钢蛋", "黑色")
    • 触发__init__方法,self绑定obj1
    • 初始化obj1.name = "刘钢蛋"obj1.skin = "黑色"
  3. 执行obj1.children_info()
    • 拼接字符串:"姓名:刘钢蛋,肤色:黑色,类型:人类幼崽"并打印;
  4. 执行obj2 = Children("赵铁锤", "屎黄色")
    • 触发__init__self绑定obj2
    • 初始化obj2.name = "赵铁锤"obj2.skin = "屎黄色"
  5. 执行obj2.children_info():打印"姓名:赵铁锤,肤色:屎黄色,类型:人类幼崽"

执行结果

姓名:刘钢蛋,肤色:黑色,类型:人类幼崽
姓名:赵铁锤,肤色:屎黄色,类型:人类幼崽
1.2 封装:公有/私有成员

核心:控制成员的访问范围,私有成员加__前缀。

示例:公有vs私有成员

class Human():# 公有属性hair = "绿色头发"# 私有属性(加__)__sex = "中性"# 公有方法def hunting(self):print("打猎")# 私有方法(加__)def __sleep(self):print("睡觉")# 类内调用私有成员(合法)def call_private(self):print(self.__sex)  # 调用私有属性self.__sleep()     # 调用私有方法# 实例化
obj = Human()# 1. 访问公有成员(合法)
print(obj.hair)  # 输出:绿色头发
obj.hunting()    # 输出:打猎# 2. 间接访问私有成员(合法)
obj.call_private()# 3. 直接访问私有成员(注释掉,执行会报错)
# print(obj.__sex)  # AttributeError
# obj.__sleep()     # AttributeError

详细运算过程

  1. 定义Human类:包含公有属性hair、私有属性__sex,公有方法hunting、私有方法__sleep,公有方法call_private
  2. 实例化obj = Human()
  3. 执行print(obj.hair):访问公有属性,输出“绿色头发”;
  4. 执行obj.hunting():调用公有方法,输出“打猎”;
  5. 执行obj.call_private()
    • 方法内访问self.__sex(私有属性),输出“中性”;
    • 调用self.__sleep()(私有方法),输出“睡觉”;
  6. 若执行print(obj.__sex):直接访问私有属性,触发AttributeError

执行结果

绿色头发
打猎
中性
睡觉

步骤2:继承(单继承→多继承→菱形继承)

2.1 单继承:子类继承一个父类

核心:子类可复用父类公有成员,可重写父类方法。

示例1:基础单继承

# 父类
class Human():hair = "绿色头发"def hunting(self):print("土著人打猎")# 子类继承父类(括号写父类名)
class Children(Human):pass  # 暂不定义内容# 实例化子类对象
obj = Children()
# 调用父类公有属性
print(obj.hair)
# 调用父类公有方法
obj.hunting()

详细运算过程

  1. 定义父类Human,含公有属性hair、公有方法hunting
  2. 定义子类Children,继承Human,无自定义内容;
  3. 实例化obj = Children()
  4. 执行print(obj.hair):子类无hair属性,调用父类的hair,输出“绿色头发”;
  5. 执行obj.hunting():子类无hunting方法,调用父类的hunting,输出“土著人打猎”。

执行结果

绿色头发
土著人打猎

示例2:重写父类方法

class Human():def hunting(self):print("土著人打猎")class Children(Human):# 重写父类hunting方法def hunting(self):print("小孩用弹弓打猎")obj = Children()
obj.hunting()

详细运算过程

  1. 定义父类Humanhunting方法;
  2. 定义子类Children,重写hunting方法;
  3. 实例化obj = Children()
  4. 执行obj.hunting():子类有hunting方法,优先调用自身的,输出“小孩用弹弓打猎”。

执行结果

小孩用弹弓打猎
2.2 多继承:子类继承多个父类

核心:多个父类用逗号分隔,子类可调用所有父类的公有成员。

示例

# 父类1
class Father():f_attr = "父亲的特征"def f_hobby(self):print("父亲的爱好:按摩")# 父类2
class Mother():m_attr = "母亲的特征"def m_hobby(self):print("母亲的爱好:打麻将")# 子类继承两个父类
class Son(Father, Mother):passobj = Son()
# 调用父类1的属性
print(obj.f_attr)
# 调用父类2的方法
obj.m_hobby()

详细运算过程

  1. 定义FatherMother两个父类,各有公有属性和方法;
  2. 定义Son类,继承FatherMother
  3. 实例化obj = Son()
  4. 执行print(obj.f_attr):调用Fatherf_attr,输出“父亲的特征”;
  5. 执行obj.m_hobby():调用Motherm_hobby,输出“母亲的爱好:打麻将”。

执行结果

父亲的特征
母亲的爱好:打麻将
2.3 super用法:区分self和super

核心:self优先调用自身成员,super()优先调用父类成员。

示例

class Mother():m_attr = "母亲的特征"def m_hobby(self):print("母亲的爱好:打麻将")class Son(Mother):m_attr = "儿子的特征"  # 子类重写属性def use_self(self):# self优先调用自身的m_attr和m_hobbyprint(self.m_attr)self.m_hobby()def use_super(self):# super优先调用父类的m_attr和m_hobbyprint(super().m_attr)super().m_hobby()obj = Son()
print("===self调用===")
obj.use_self()
print("===super调用===")
obj.use_super()

详细运算过程

  1. 定义Mother类,含m_attrm_hobby
  2. 定义Son类,继承Mother,重写m_attr,定义use_selfuse_super方法;
  3. 实例化obj = Son()
  4. 执行obj.use_self()
    • self.m_attrSonm_attr,输出“儿子的特征”;
    • self.m_hobby()Sonm_hobby,调用Motherm_hobby,输出“母亲的爱好:打麻将”;
  5. 执行obj.use_super()
    • super().m_attr:跳过Sonm_attr,调用Motherm_attr,输出“母亲的特征”;
    • super().m_hobby():调用Motherm_hobby,输出“母亲的爱好:打麻将”。

执行结果

===self调用===
儿子的特征
母亲的爱好:打麻将
===super调用===
母亲的特征
母亲的爱好:打麻将
2.4 菱形继承:super的调用顺序

核心:通过类名.mro()查看调用顺序,super()按该顺序执行。

示例

# 菱形继承结构:Human → Man/Woman → Children
class Human():def feel(self):print("人类的感受")class Man(Human):def feel(self):print("男人的感受")super().feel()  # 调用下一个类的feelclass Woman(Human):def feel(self):print("女人的感受")super().feel()  # 调用下一个类的feelclass Children(Man, Woman):def feel(self):print("小孩的感受")super().feel()  # 调用下一个类的feel# 查看mro列表(调用顺序)
print("mro列表:", Children.mro())
# 实例化调用
obj = Children()
obj.feel()

详细运算过程

  1. 定义菱形继承的4个类,每个类的feel方法都调用super().feel()
  2. 执行Children.mro():输出顺序为[Children, Man, Woman, Human, object]
  3. 实例化obj = Children(),执行obj.feel()
    • 先执行Childrenfeel:输出“小孩的感受”;
    • super().feel() → 调用Manfeel:输出“男人的感受”;
    • Mansuper().feel() → 调用Womanfeel:输出“女人的感受”;
    • Womansuper().feel() → 调用Humanfeel:输出“人类的感受”;
    • Humansuper().feel()objectfeel,停止。

执行结果

mro列表: [<class '__main__.Children'>, <class '__main__.Man'>, <class '__main__.Woman'>, <class '__main__.Human'>, <class 'object'>]
小孩的感受
男人的感受
女人的感受
人类的感受

步骤3:多态:不同子类的差异化执行

核心:继承父类+重写方法,同一调用逻辑执行不同结果。

示例

# 父类:士兵
class Soldier():def attack(self):pass  # 空方法,由子类重写# 子类1:陆军
class Army(Soldier):def attack(self):print("陆军:占领堡垒")# 子类2:海军
class Navy(Soldier):def attack(self):print("海军:发射鱼雷")# 子类3:空军
class AirForce(Soldier):def attack(self):print("空军:空投炸弹")# 批量处理不同子类对象
soldiers = [Army(), Navy(), AirForce()]
# 统一调用attack方法,执行不同逻辑
for soldier in soldiers:soldier.attack()

详细运算过程

  1. 定义父类Soldier,含空方法attack
  2. 定义3个子类,分别重写attack方法;
  3. 创建列表soldiers,包含3个子类的实例;
  4. 遍历列表,对每个实例调用attack方法:
    • 第一个元素(Army实例):调用Armyattack,输出“陆军:占领堡垒”;
    • 第二个元素(Navy实例):调用Navyattack,输出“海军:发射鱼雷”;
    • 第三个元素(AirForce实例):调用AirForceattack,输出“空军:空投炸弹”。

执行结果

陆军:占领堡垒
海军:发射鱼雷
空军:空投炸弹

步骤4:常用魔术方法(init/str

示例

class Student():# 带参数的__init__:初始化对象属性def __init__(self, name, score):self.name = nameself.score = score# __str__:print对象时触发,必须返回字符串def __str__(self):return f"学生:{self.name},分数:{self.score}"# 实例化(必须传入name和score)
stu = Student("张三", 90)
# 打印对象,触发__str__
print(stu)
# 访问对象属性
print(stu.name)
print(stu.score)

详细运算过程

  1. 定义Student类,__init__接收namescore,初始化对象属性;__str__返回字符串;
  2. 实例化stu = Student("张三", 90)
    • 触发__init__self绑定stu,初始化stu.name = "张三"stu.score = 90
  3. 执行print(stu):触发__str__,返回“学生:张三,分数:90”并打印;
  4. 打印stu.name输出“张三”,打印stu.score输出90。

执行结果

学生:张三,分数:90
张三
90

应用场景及案例(附详细运算过程)

场景1:封装用户信息(封装+init

用途:保护用户敏感信息(如密码),仅通过类内方法访问/修改。

案例代码

class User():def __init__(self, username, password):self.username = username  # 公有属性self.__password = password  # 私有属性(密码脱敏)# 公有方法:验证密码def check_pwd(self, input_pwd):if input_pwd == self.__password:print("密码正确,登录成功")else:print("密码错误,登录失败")# 公有方法:修改密码def change_pwd(self, old_pwd, new_pwd):if old_pwd == self.__password:self.__password = new_pwdprint("密码修改成功")else:print("原密码错误,修改失败")# 实例化用户
user = User("zhangsan", "123456")# 1. 验证密码
print("===验证密码===")
user.check_pwd("123456")  # 正确密码
user.check_pwd("654321")  # 错误密码# 2. 修改密码
print("===修改密码===")
user.change_pwd("123456", "888888")  # 原密码正确
user.change_pwd("654321", "888888")  # 原密码错误# 3. 直接访问私有密码(注释掉,执行会报错)
# print(user.__password)

详细运算过程

  1. 定义User类:
    • __init__:接收username(公有)、password(私有__password);
    • check_pwd:验证输入密码与私有密码是否一致;
    • change_pwd:验证原密码后修改私有密码;
  2. 实例化user = User("zhangsan", "123456")
    • 触发__init__,初始化user.username = "zhangsan"user.__password = "123456"
  3. 执行user.check_pwd("123456")
    • input_pwd = "123456",与self.__password(123456)一致,输出“密码正确,登录成功”;
  4. 执行user.check_pwd("654321")
    • input_pwd与私有密码不一致,输出“密码错误,登录失败”;
  5. 执行user.change_pwd("123456", "888888")
    • old_pwd = "123456",与私有密码一致,修改self.__password = "888888",输出“密码修改成功”;
  6. 执行user.change_pwd("654321", "888888")
    • old_pwd与私有密码不一致,输出“原密码错误,修改失败”;
  7. 若执行print(user.__password):直接访问私有属性,触发AttributeError

执行结果

===验证密码===
密码正确,登录成功
密码错误,登录失败
===修改密码===
密码修改成功
原密码错误,修改失败

场景2:多态实现不同支付方式(多态+继承)

用途:统一支付接口,扩展不同支付方式(微信、支付宝),无需修改核心逻辑。

案例代码

# 父类:支付基类
class Payment():def pay(self, money):pass  # 统一支付接口,子类重写# 子类1:微信支付
class WeChatPay(Payment):def pay(self, money):print(f"微信支付:扣款{money}元,支付成功")# 子类2:支付宝支付
class AliPay(Payment):def pay(self, money):print(f"支付宝支付:扣款{money}元,支付成功")# 核心支付逻辑(无需修改,可扩展新支付方式)
def pay_process(pay_obj, money):pay_obj.pay(money)# 调用不同支付方式
print("===微信支付===")
wechat = WeChatPay()
pay_process(wechat, 100)print("===支付宝支付===")
ali = AliPay()
pay_process(ali, 200)

详细运算过程

  1. 定义Payment父类,含空方法pay(统一接口);
  2. 定义WeChatPayAliPay子类,继承Payment,重写pay方法;
  3. 定义pay_process函数:接收支付对象和金额,调用pay方法;
  4. 执行微信支付逻辑:
    • 实例化wechat = WeChatPay()
    • 调用pay_process(wechat, 100)
      • pay_obj = wechatWeChatPay实例),money = 100
      • 执行pay_obj.pay(100) → 调用WeChatPaypay,输出“微信支付:扣款100元,支付成功”;
  5. 执行支付宝支付逻辑:
    • 实例化ali = AliPay()
    • 调用pay_process(ali, 200)
      • pay_obj = aliAliPay实例),money = 200
      • 执行pay_obj.pay(200) → 调用AliPaypay,输出“支付宝支付:扣款200元,支付成功”。

执行结果

===微信支付===
微信支付:扣款100元,支付成功
===支付宝支付===
支付宝支付:扣款200元,支付成功

场景3:多继承实现功能复用(多继承+super)

用途:子类继承多个工具类,复用不同工具的功能,简化代码。

案例代码

# 工具类1:文件操作
class FileTool():def read_file(self):print("读取文件内容")def write_file(self):print("写入文件内容")# 工具类2:数据处理
class DataTool():def parse_data(self):print("解析数据格式")def clean_data(self):print("清洗脏数据")# 业务类:继承两个工具类,复用功能
class Business(FileTool, DataTool):def process(self):# 复用文件操作和数据处理功能self.read_file()self.parse_data()self.clean_data()self.write_file()# 实例化业务类,执行流程
obj = Business()
obj.process()

详细运算过程

  1. 定义FileTool(文件操作)、DataTool(数据处理)两个工具类;
  2. 定义Business类,继承FileToolDataTool,定义process方法,调用两个父类的方法;
  3. 实例化obj = Business()
  4. 执行obj.process()
    • self.read_file() → 调用FileToolread_file,输出“读取文件内容”;
    • self.parse_data() → 调用DataToolparse_data,输出“解析数据格式”;
    • self.clean_data() → 调用DataToolclean_data,输出“清洗脏数据”;
    • self.write_file() → 调用FileToolwrite_file,输出“写入文件内容”。

执行结果

读取文件内容
解析数据格式
清洗脏数据
写入文件内容


21、魔术方法

全文总结

核心知识点总结表

知识点类别 核心方法/概念 触发时机 核心功能 关键注意点
对象创建与初始化 __new__ 实例化类生成对象时(__init__之前) 控制对象创建过程 至少接收cls参数,返回本类对象才会触发__init__;返回None/其他类对象则不触发
__init__ 实例化对象初始化时 为对象添加成员属性 至少接收self参数,无返回值
对象销毁 __del__ 对象被内存回收时(页面执行完毕/所有指向对象的变量被del) 回收对象占用的资源(如文件句柄、网络连接) 仅接收self参数,无返回值;需删除所有对象引用才会触发
对象函数化 __call__ 把对象当作函数调用时(obj() 模拟函数化操作,可封装统一执行流程 参数不固定(至少self),返回值按需定义
对象字符串展示 __str__ print(对象)/str(对象) 自定义对象的友好字符串展示(面向用户) 必须返回字符串类型;无__str__时会调用__repr__
__repr__ repr(对象) 自定义对象的字符串展示(面向开发者) 必须返回字符串类型;系统底层默认__str__ = __repr__
类型转换 __bool__ bool(对象) 自定义对象转布尔类型的规则 必须返回布尔类型;类似的还有__int__/__float__
运算符重载 __add__ 对象作为加号左侧操作数时(obj + x 自定义对象的加法运算 接收selfother参数,返回运算结果;__radd__为右侧触发
长度检测 __len__ len(对象) 自定义“长度”统计规则(如统计类成员、自定义容器元素数) 必须返回整型;仅接收self参数
设计模式 单例模式(基于__new__ 多次实例化类时 确保类只有一个实例,节省内存 用类私有属性存储唯一实例,__new__中判断并返回
多继承 super 调用父类方法时 解决多继承(菱形继承)的方法调用顺序问题 按MRO列表调用;仅用于绑定方法,自动传递self

补充总结(分段)

  1. 魔术方法共性:所有魔术方法均以__开头和结尾,在特定场景下自动触发,无需手动调用;核心作用是自定义类/对象的行为,让Python面向对象更灵活。
  2. 对象生命周期__new__(创建)→ __init__(初始化)→ 业务使用 → __del__(销毁),完整覆盖对象从创建到回收的全流程。
  3. 单例模式核心逻辑:通过__new__控制对象创建,用类私有属性存储已创建的实例,后续实例化时直接返回已有实例,避免重复创建。
  4. 多继承调用规则:Python3新式类按“广度优先”的MRO列表执行,super()可按MRO顺序调用父类方法,解决菱形继承的调用混乱问题。

完整详细讲解(带执行过程)

一、魔术方法基础认知

魔术方法是Python内置的特殊方法,无需手动调用,在特定操作触发时自动执行。核心价值是让自定义类拥有更贴合业务的行为(比如让对象支持加法、打印时展示友好信息等)。

二、对象创建与初始化:new + init

1. 核心逻辑

  • __new__:负责“创建”对象,是类级别的方法(接收cls),触发时机最早;
  • __init__:负责“初始化”对象,是对象级别的方法(接收self),仅在__new__返回本类对象时触发。

2. 代码示例+执行过程

class Boat:def __new__(cls, *args, **kwargs):print("步骤1:__new__触发,创建对象")# 调用object的__new__创建本类对象obj = object.__new__(cls)return obj  # 返回本类对象,才会触发__init__def __init__(self, boat_name):print("步骤2:__init__触发,初始化对象")self.boat_name = boat_name  # 给对象添加属性# 实例化执行过程
obj = Boat("泰坦尼克号")
"""
执行输出:
步骤1:__new__触发,创建对象
步骤2:__init__触发,初始化对象执行逻辑:
1. 执行Boat("泰坦尼克号"),先调用__new__(Boat, "泰坦尼克号");
2. __new__中通过object.__new__(cls)创建Boat类的空对象;
3. 返回空对象给解释器,解释器自动调用__init__(空对象, "泰坦尼克号");
4. __init__给对象添加boat_name属性,最终得到完整对象obj。
"""
print(obj.boat_name)  # 输出:泰坦尼克号

3. 关键易错点

如果__new__返回其他类对象/None,__init__不会触发:

class MyClass:__obj = None  # 其他类的对象def __new__(cls):print("__new__触发,但返回其他对象")return MyClass.__obj  # 返回None/其他类对象def __init__(self):print("__init__不会触发")obj = MyClass()  # 输出:__new__触发,但返回其他对象;无__init__输出

三、对象销毁:del(析构方法)

1. 核心逻辑

对象被内存回收时自动触发,用于释放资源(如关闭文件、断开数据库连接)。

2. 代码示例+执行过程

class ReadFile:def __init__(self, filename):print("步骤1:初始化,打开文件")self.fp = open(filename, "r", encoding="utf-8")  # 占用文件资源def get_content(self):return self.fp.read(10)def __del__(self):print("步骤2:析构触发,关闭文件")self.fp.close()  # 释放文件资源# 执行过程
obj = ReadFile("test.txt")  # 输出:步骤1:初始化,打开文件
res = obj.get_content()
print(res)  # 输出:test.txt的前10个字符# 手动删除所有对象引用(触发__del__)
del obj  # 输出:步骤2:析构触发,关闭文件"""
执行逻辑:
1. 实例化ReadFile时,__init__打开文件,占用系统资源;
2. 调用get_content读取文件内容;
3. del obj删除最后一个指向对象的引用,Python回收对象,触发__del__;
4. __del__关闭文件句柄,释放资源。
"""

3. 触发条件说明

  • 场景1:页面执行完毕,Python自动回收所有变量,触发__del__
  • 场景2:删除所有指向对象的变量(如obj1=obj2=ReadFile(...),需del obj1 + del obj2才会触发)。

四、对象函数化:call

1. 核心逻辑

把对象当作函数调用(obj())时触发,可封装统一的执行流程。

2. 代码示例+执行过程

# 模拟做蛋糕的统一流程
class MakeCake:def __call__(self, flavor):print(f"开始做{flavor}蛋糕")self.step1()self.step2()self.step3()return f"{flavor}蛋糕制作完成"def step1(self):print("步骤1:准备面粉、鸡蛋、糖")def step2(self):print("步骤2:搅拌原料,倒入模具")def step3(self):print("步骤3:烤箱烘烤30分钟")# 执行过程
cake_obj = MakeCake()
res = cake_obj("巧克力")  # 把对象当函数调用,触发__call__
"""
执行输出:
开始做巧克力蛋糕
步骤1:准备面粉、鸡蛋、糖
步骤2:搅拌原料,倒入模具
步骤3:烤箱烘烤30分钟执行逻辑:
1. 实例化MakeCake得到cake_obj;
2. 执行cake_obj("巧克力"),触发__call__(self, "巧克力");
3. __call__内部依次调用step1/step2/step3,封装统一流程;
4. 返回制作完成的字符串,赋值给res。
"""
print(res)  # 输出:巧克力蛋糕制作完成

五、对象字符串展示:str + repr

1. 核心逻辑

  • __str__:面向用户的友好展示(print/str触发);
  • __repr__:面向开发者的精准展示(repr触发),无__str__时会替代其执行。

2. 代码示例+执行过程

class Cat:def __init__(self, name, age):self.name = nameself.age = agedef __str__(self):# 面向用户的友好展示return f"猫咪{self.name},年龄{self.age}岁"def __repr__(self):# 面向开发者的精准展示(含对象属性)return f"Cat(name='{self.name}', age={self.age})"# 执行过程
tom = Cat("汤姆", 3)
# 触发__str__
print(tom)  # 输出:猫咪汤姆,年龄3岁
res_str = str(tom)
print(res_str)  # 输出:猫咪汤姆,年龄3岁# 触发__repr__
res_repr = repr(tom)
print(res_repr)  # 输出:Cat(name='汤姆', age=3)"""
执行逻辑:
1. 实例化Cat,添加name/age属性;
2. print(tom)触发__str__,返回用户友好的字符串;
3. str(tom)直接调用__str__;
4. repr(tom)直接调用__repr__;
5. 若删除__str__,print(tom)会调用__repr__(系统默认__str__ = __repr__)。
"""

六、类型转换:bool(及衍生)

1. 核心逻辑

bool(对象)时触发,自定义对象转布尔的规则;类似的还有__int__/__float__(转整型/浮点型)。

2. 代码示例+执行过程

class MyBool:def __init__(self, value):self.value = value  # 自定义判断依据def __bool__(self):# 自定义布尔转换规则:value>0返回True,否则Falsereturn self.value > 0# 执行过程
obj1 = MyBool(5)
res1 = bool(obj1)
print(res1)  # 输出:Trueobj2 = MyBool(-2)
res2 = bool(obj2)
print(res2)  # 输出:False"""
执行逻辑:
1. 实例化MyBool,传入value参数;
2. 执行bool(obj1),触发__bool__;
3. __bool__判断self.value>0,返回布尔值;
4. 结果赋值给res1/res2并打印。
"""

七、运算符重载:add + radd

1. 核心逻辑

  • __add__:对象在加号左侧时触发(obj + x);
  • __radd__:对象在加号右侧时触发(x + obj);
  • 用于自定义对象的运算规则。

2. 代码示例+执行过程

class MyNum:def __init__(self, num):self.num = numdef __add__(self, other):# obj在左侧:self=当前对象,other=右侧值print("触发__add__")return self.num + otherdef __radd__(self, other):# obj在右侧:self=当前对象,other=左侧值print("触发__radd__")return self.num + other * 2# 执行过程
a = MyNum(3)
# 场景1:obj在左侧(触发__add__)
res1 = a + 5
"""
执行逻辑:
1. a+5 → 触发a.__add__(5);
2. self.num=3,other=5 → 3+5=8;
3. 返回8赋值给res1。
"""
print(res1)  # 输出:触发__add__ → 8# 场景2:obj在右侧(触发__radd__)
res2 = 5 + a
"""
执行逻辑:
1. 5+a → 触发a.__radd__(5);
2. self.num=3,other=5 → 3 + 5*2=13;
3. 返回13赋值给res2。
"""
print(res2)  # 输出:触发__radd__ → 13

八、长度检测:len

1. 核心逻辑

len(对象)时触发,自定义“长度”的统计规则(如统计类的成员数量)。

2. 代码示例+执行过程

class MyClass:# 类成员pty1 = 1pty2 = 2__pty3 = 3  # 私有属性def func1(self):passdef __len__(self):# 统计类中非系统内置的成员数量(排除__xxx__)class_dict = MyClass.__dict__# 筛选条件:不以__开头且不以__结尾valid_members = [k for k in class_dict if not (k.startswith("__") and k.endswith("__"))]return len(valid_members)# 执行过程
obj = MyClass()
res = len(obj)
"""
执行逻辑:
1. len(obj)触发__len__;
2. MyClass.__dict__获取类的所有成员字典;
3. 筛选出非系统内置成员(pty1、pty2、_MyClass__pty3、func1、__len__);
4. 统计数量为5,返回给res。
"""
print(res)  # 输出:5

九、单例模式(基于__new__)

1. 核心逻辑

通过__new__控制对象创建,确保类只有一个实例,节省内存。

2. 代码示例+执行过程

class Singleton:__instance = None  # 私有属性,存储唯一实例def __new__(cls):# 步骤1:判断是否已有实例if cls.__instance is None:# 步骤2:无实例则创建cls.__instance = object.__new__(cls)# 步骤3:有实例则直接返回return cls.__instance# 执行过程
obj1 = Singleton()
obj2 = Singleton()
obj3 = Singleton()
"""
执行逻辑:
1. 第一次实例化(obj1):- __instance=None → 创建对象,赋值给__instance → 返回对象给obj1;
2. 第二次实例化(obj2):- __instance已有值 → 直接返回该对象给obj2;
3. 第三次实例化(obj3):- 同上,返回同一个对象给obj3;
4. 最终obj1/obj2/obj3指向同一个对象。
"""
print(obj1 is obj2)  # 输出:True
print(obj2 is obj3)  # 输出:True

十、多继承与super(补充)

1. 核心逻辑

  • 多继承弊端:菱形继承导致方法调用顺序混乱;
  • super():按MRO列表(Python3广度优先)调用父类方法,解决顺序问题;
  • super()是对象,仅用于绑定方法,自动传递self

应用场景及案例(带详细运算过程)

场景1:单例模式(new)→ 配置管理类

场景说明

项目中配置类只需一个实例(避免重复加载配置、节省内存),用单例模式实现。

案例代码+执行过程

class ConfigManager:__instance = None  # 存储唯一实例config = {}  # 存储配置def __new__(cls):if cls.__instance is None:cls.__instance = object.__new__(cls)# 仅第一次创建实例时加载配置cls.__instance.load_config()return cls.__instancedef load_config(self):# 模拟加载配置文件self.config = {"db_host": "127.0.0.1","db_port": 3306,"redis_port": 6379}def get_config(self, key):return self.config.get(key)# 执行过程
# 第一次实例化:加载配置
cfg1 = ConfigManager()
res1 = cfg1.get_config("db_port")
"""
执行逻辑:
1. cfg1 = ConfigManager() → 调用__new__;
2. __instance=None → 创建对象,调用load_config加载配置;
3. 返回对象给cfg1;
4. cfg1.get_config("db_port") → 从config字典取3306。
"""
print(res1)  # 输出:3306# 第二次实例化:直接返回已有实例(不重复加载配置)
cfg2 = ConfigManager()
res2 = cfg2.get_config("redis_port")
"""
执行逻辑:
1. cfg2 = ConfigManager() → 调用__new__;
2. __instance已有值 → 直接返回该对象;
3. cfg2.get_config("redis_port") → 从同一个config字典取6379。
"""
print(res2)  # 输出:6379# 验证是同一个实例
print(cfg1 is cfg2)  # 输出:True

场景2:统一业务流程(call)→ 订单处理

场景说明

订单处理包含“校验参数→创建订单→扣库存→发送通知”固定流程,用__call__封装,调用更简洁。

案例代码+执行过程

class OrderHandler:def __call__(self, order_id, goods_id, num):print(f"开始处理订单{order_id}")# 封装统一流程check_res = self.check_param(goods_id, num)if not check_res:return "订单处理失败:参数错误"create_res = self.create_order(order_id, goods_id, num)reduce_res = self.reduce_stock(goods_id, num)notify_res = self.send_notify(order_id)return f"订单{order_id}处理完成:{create_res}/{reduce_res}/{notify_res}"def check_param(self, goods_id, num):# 校验商品ID和数量print("步骤1:校验参数")return isinstance(goods_id, int) and isinstance(num, int) and num > 0def create_order(self, order_id, goods_id, num):print("步骤2:创建订单")return f"订单{order_id}创建成功"def reduce_stock(self, goods_id, num):print("步骤3:扣减库存")return f"商品{goods_id}库存扣减{num}件"def send_notify(self, order_id):print("步骤4:发送通知")return f"订单{order_id}通知已发送"# 执行过程
handler = OrderHandler()
res = handler(1001, 5001, 2)
"""
执行逻辑:
1. handler(1001,5001,2) → 触发__call__;
2. 调用check_param校验参数(5001是int,2>0 → 返回True);
3. 依次调用create_order/reduce_stock/send_notify;
4. 拼接结果返回给res。
"""
print(res)
"""
输出:
开始处理订单1001
步骤1:校验参数
步骤2:创建订单
步骤3:扣减库存
步骤4:发送通知
订单1001处理完成:订单1001创建成功/商品5001库存扣减2件/订单1001通知已发送
"""

场景3:资源自动回收(del)→ 数据库连接

场景说明

数据库连接是稀缺资源,使用完毕后需及时关闭,用__del__自动回收,避免资源泄露。

案例代码+执行过程

import pymysql  # 需安装:pip install pymysqlclass DBConnector:def __init__(self, host, user, password, db):print("步骤1:创建数据库连接")self.conn = pymysql.connect(host=host,user=user,password=password,db=db)self.cursor = self.conn.cursor()def query(self, sql):print("步骤2:执行查询")self.cursor.execute(sql)return self.cursor.fetchall()def __del__(self):print("步骤3:关闭数据库连接")self.cursor.close()self.conn.close()# 执行过程(模拟)
db = DBConnector("127.0.0.1", "root", "123456", "test_db")
res = db.query("SELECT * FROM user LIMIT 10")
print(f"查询结果条数:{len(res)}")
del db  # 手动删除,触发__del__
"""
执行逻辑:
1. 实例化DBConnector,__init__创建数据库连接和游标;
2. 调用query执行SQL,返回查询结果;
3. del db删除最后一个引用,触发__del__;
4. __del__关闭游标和连接,释放数据库资源。
"""

场景4:友好的对象展示(str)→ 日志打印

场景说明

自定义类的对象打印时,默认显示<__main__.XXX object at 0x...>,不友好;用__str__自定义展示内容,便于日志/调试。

案例代码+执行过程

class User:def __init__(self, uid, name, phone):self.uid = uidself.name = nameself.phone = phone  # 敏感信息,脱敏展示def __str__(self):# 友好展示+脱敏手机号(仅显示后4位)return f"用户[ID:{self.uid}]:姓名{self.name},手机号****{self.phone[-4:]}"# 执行过程
user = User(10086, "张三", "13812345678")
# 日志打印对象(触发__str__)
print(f"用户信息:{user}")
"""
执行逻辑:
1. 实例化User,添加uid/name/phone属性;
2. print(f"用户信息:{user}") → 触发__str__;
3. __str__脱敏手机号,返回友好字符串;
4. 打印最终结果。
"""
# 输出:用户[ID:10086]:姓名张三,手机号****5678

场景5:自定义对象运算(add)→ 购物车金额计算

场景说明

自定义购物车商品类,支持“商品+商品”计算总金额,简化金额统计逻辑。

案例代码+执行过程

class CartItem:def __init__(self, goods_name, price, num):self.goods_name = goods_nameself.price = price  # 单价self.num = num      # 数量@propertydef total(self):# 单个商品总金额return self.price * self.numdef __add__(self, other):# 自定义加法:两个商品的总金额相加return self.total + other.total# 执行过程
item1 = CartItem("手机", 2999, 1)
item2 = CartItem("耳机", 199, 2)
# 计算两个商品的总金额(触发__add__)
total = item1 + item2
"""
执行逻辑:
1. item1+item2 → 触发item1.__add__(item2);
2. self.total=2999*1=2999,other.total=199*2=398;
3. 2999+398=3397,返回给total。
"""
print(f"两个商品总金额:{total}元")  # 输出:两个商品总金额:3397元


22、装饰器

Python装饰器核心知识点(简化版课件)

全文总结

1. 装饰器核心本质

装饰器是Python中不修改原函数/类代码的前提下,为其拓展新功能的语法方案;核心逻辑是“将原函数/类作为参数传入装饰器,返回新函数/类替换原对象”,通过@语法简化调用流程,是Python“开闭原则”(对拓展开放、对修改封闭)的典型实现。

2. 装饰器分类与核心特征(表格版)

装饰器类型 核心语法/特征 关键执行要点
基础函数装饰器 @装饰器函数 放在原函数上方 新函数包裹原函数,拓展功能;原函数执行前/后新增逻辑
嵌套函数装饰器 多层@装饰器堆叠(如@装饰器2+@装饰器1 从下往上传递原函数(先执行装饰器1,再执行装饰器2),逐层拓展功能
带参数的函数装饰器 装饰器外层套“接收参数”的函数(如@outer(1) 先执行outer(1)返回真正的装饰器,再触发@语法绑定原函数
类装饰器 类实现__call__方法,通过@类名()/@类名.类方法装饰 @类名()触发__call__,将类实例当成“装饰器函数”使用
带参数的类装饰器 __init__接收参数,__call__处理原类/函数 可动态为类添加属性/方法,或修改类成员(如把方法转为属性)
@property装饰器 @property(获取)+@xxx.setter(设置)+@xxx.deleter(删除) 把方法伪装成属性,简化属性的读写删(无需()调用)

3. 装饰器通用执行逻辑

所有@语法的本质是“语法糖”,等价于手动赋值:

  • 基础装饰器:@kuozhanfunc = kuozhan(func)
  • 带参数装饰器:@outer(1)func = outer(1)(func)
  • 类装饰器:@Kuozhan()func = Kuozhan()(func)(触发__call__

完整详细讲解(带逐步运算过程)

3.1 基础函数装饰器(入门级)

案例代码
# 定义装饰器函数:拓展功能
def kuozhan(func):def newfunc():print("厕所前,蒙头垢面")  # 拓展功能1func()                   # 执行原函数print("厕所后,精神抖擞")  # 拓展功能2return newfunc# 定义原函数
def func():print("我是个高富帅")# 手动绑定装饰器(等价于@kuozhan)
func = kuozhan(func)
func()
逐步运算过程
  1. 执行func = kuozhan(func)
    • 把原函数func作为参数传入kuozhan
    • kuozhan内部定义newfunc(包裹原函数+拓展逻辑);
    • kuozhan返回newfunc,赋值给func(原func被替换)。
  2. 执行func()
    • 实际执行的是newfunc()
    • 先打印“厕所前,蒙头垢面”;
    • 调用func()(原函数),打印“我是个高富帅”;
    • 最后打印“厕所后,精神抖擞”。
简化语法(@符)
@kuozhan  # 等价于 func = kuozhan(func)
def func():print("我是白富美")
func()

执行过程和手动绑定完全一致,仅简化了赋值步骤。

3.2 带参数的原函数装饰器

案例代码
def kuozhan(func):# 新函数参数匹配原函数def newfunc(who,where):print("厕所前,得得色色")func(who,where)print("厕所后,老实巴交")return newfunc@kuozhan
def func(who,where):print(f"{who}在{where}解手")func("陈学斌","女厕所")
逐步运算过程
  1. @kuozhan触发func = kuozhan(func)newfunc被返回并替换原func
  2. 执行func("陈学斌","女厕所") → 实际执行newfunc("陈学斌","女厕所")
  3. 打印“厕所前,得得色色”;
  4. 调用原func("陈学斌","女厕所"),打印“陈学斌在女厕所解手”;
  5. 打印“厕所后,老实巴交”。
通用参数适配(*args/**kwargs)

若原函数参数不固定,用*args(位置参数)+**kwargs(关键字参数)适配:

def kuozhan(func):def newfunc(*args,**kwargs):print("厕所前,饥肠辘辘")res = func(*args,**kwargs)  # 解包参数传给原函数print("厕所后,酒足饭饱")return resreturn newfunc@kuozhan
def func(*args,**kwargs):return [f"参数{k}的值是{v}" for k,v in kwargs.items()]res = func(a=1,b=2)
print(res)

执行过程:

  1. func = kuozhan(func)替换原函数;
  2. func(a=1,b=2)newfunc(a=1,b=2)
  3. 打印“厕所前,饥肠辘辘”;
  4. func接收args=()kwargs={"a":1,"b":2},返回列表["参数a的值是1","参数b的值是2"]
  5. 打印“厕所后,酒足饭饱”,返回结果并打印。

3.3 嵌套函数装饰器

案例代码
def kuozhan1(func):def newfunc():print("厕所前,牛头马面1")func()print("厕所后,人模狗样2")return newfuncdef kuozhan2(func):def newfunc():print("吃饭前,洗洗手3")func()print("吃饭后,走一走4")return newfunc@kuozhan2
@kuozhan1
def func():print("我是个屌丝5")func()
逐步运算过程
  1. 嵌套装饰器从下往上执行:先执行@kuozhan1func = kuozhan1(func)
  2. 再执行@kuozhan2func = kuozhan2(新的func)(即kuozhan1返回的newfunc);
  3. 执行func() → 实际执行kuozhan2的newfunc:
    • 打印“吃饭前,洗洗手3”;
    • 调用kuozhan1的newfunc:
      • 打印“厕所前,牛头马面1”;
      • 调用原func,打印“我是个屌丝5”;
      • 打印“厕所后,人模狗样2”;
    • 打印“吃饭后,走一走4”。

3.4 类装饰器

案例1:类方法作为装饰器
class Kuozhan():@staticmethod  # 类方法无需selfdef kuozhan1(func):def newfunc():print("厕所前,干净整齐")func()print("厕所后,黄金满地")return newfunc@Kuozhan.kuozhan1
def func():print("厕所进行时 ... ")func()

执行过程:

  1. @Kuozhan.kuozhan1func = Kuozhan.kuozhan1(func)
  2. func() → 执行kuozhan1返回的newfunc,按顺序打印拓展逻辑+原函数逻辑。
案例2:带__call__的类装饰器
class Kuozhan():def __call__(self,func):  # 实例被当成函数调用时触发def newfunc():print("厕所前,茶饭不思")func()print("厕所后,满口雌黄")return newfunc@Kuozhan()  # 先实例化(Kuozhan()返回对象),再触发@
def func():print("厕所进行时 ... ")func()

逐步运算过程:

  1. Kuozhan() → 创建Kuozhan实例(记为obj);
  2. @objfunc = obj(func)(触发__call__);
  3. __call__返回newfunc,替换原func;
  4. func() → 执行newfunc,打印拓展逻辑+原函数逻辑。

3.5 带参数的装饰器(函数/类)

3.5.1 带参数的函数装饰器
def outer(n):  # 外层函数接收装饰器参数def kuozhan(func):def newfunc1():print("拓展功能1")func()def newfunc2():print("拓展功能2")func()# 根据参数返回不同拓展逻辑return newfunc1 if n==1 else newfunc2return kuozhan@outer(1)  # 先执行outer(1)返回kuozhan,再触发@
def func():print("原函数")func()

执行过程:

  1. outer(1) → 返回kuozhan(此时n=1);
  2. @kuozhanfunc = kuozhan(func),返回newfunc1;
  3. func() → 执行newfunc1,打印“拓展功能1”+“原函数”。
3.5.2 带参数的类装饰器(动态修改类)
class Kuozhan():def __init__(self,num):  # 接收装饰器参数self.num = numdef __call__(self,cls):  # 接收被装饰的类if self.num ==1:# 为类添加属性/方法cls.ad = "贵族厕所欢迎您"cls.money = lambda self: print("每分钟10元")return cls  # 返回修改后的类elif self.num ==2:# 把类的run方法转为属性cls.run = cls.run()return cls@Kuozhan(1)
class MyClass():passobj = MyClass()
print(obj.ad)
obj.money()

逐步运算过程:

  1. Kuozhan(1) → 实例化(self.num=1),返回obj;
  2. @objMyClass = obj(MyClass)(触发__call__);
  3. __call__为MyClass添加属性ad和方法money,返回修改后的MyClass;
  4. obj = MyClass() → 创建实例;
  5. print(obj.ad) → 打印“贵族厕所欢迎您”;
  6. obj.money() → 执行lambda,打印“每分钟10元”。

3.6 @property装饰器(方法转属性)

案例代码
class MyClass():def __init__(self,name):self.name = name@propertydef username(self):  # 获取属性return self.name@username.setterdef username(self,val):  # 设置属性self.name = val@username.deleterdef username(self):  # 删除属性del self.nameobj = MyClass("小红")
print(obj.username)    # 获取:等价于obj.username()
obj.username = "小王"  # 设置:等价于obj.username("小王")
del obj.username       # 删除:等价于obj.username()

执行过程:

  1. @propertyusername方法转为“只读属性”,调用obj.username时触发username()
  2. @username.setter绑定“设置逻辑”,赋值obj.username=xxx时触发username(xxx)
  3. @username.deleter绑定“删除逻辑”,del obj.username时触发username()

装饰器应用场景及案例(带运算过程)

4.1 应用场景1:函数执行耗时统计

场景说明

需要统计函数执行时间,不修改原函数代码。

案例代码
import time# 装饰器:统计耗时
def time_count(func):def newfunc(*args,**kwargs):start = time.time()  # 开始时间res = func(*args,**kwargs)end = time.time()    # 结束时间print(f"函数{func.__name__}执行耗时:{end-start:.2f}秒")return resreturn newfunc@time_count
def test_func():time.sleep(1)  # 模拟耗时操作print("函数执行完成")test_func()
逐步运算过程
  1. @time_counttest_func = time_count(test_func),newfunc替换原函数;
  2. 执行test_func() → 执行newfunc:
    • start = time.time() → 记录开始时间(如1718000000.00);
    • 调用原test_func():sleep 1秒,打印“函数执行完成”;
    • end = time.time() → 记录结束时间(如1718000001.00);
    • 打印“函数test_func执行耗时:1.00秒”;
    • 返回原函数结果(None)。

4.2 应用场景2:接口请求鉴权

场景说明

接口函数执行前,验证用户是否登录,未登录则拒绝执行。

案例代码
# 模拟用户状态
user_status = {"is_login": False}# 装饰器:鉴权
def auth(func):def newfunc(*args,**kwargs):if not user_status["is_login"]:print("未登录,拒绝执行接口")return Noneres = func(*args,**kwargs)return resreturn newfunc@auth
def order_api():print("执行下单接口,创建订单成功")# 未登录调用
order_api()
# 模拟登录
user_status["is_login"] = True
# 登录后调用
order_api()
逐步运算过程
  1. @authorder_api = auth(order_api),newfunc替换原函数;
  2. 第一次调用order_api()
    • 执行newfunc,检查user_status["is_login"]为False;
    • 打印“未登录,拒绝执行接口”,返回None;
  3. 修改user_status["is_login"] = True
  4. 第二次调用order_api()
    • 检查状态为True;
    • 调用原order_api(),打印“执行下单接口,创建订单成功”;
    • 返回None。

4.3 应用场景3:类属性的安全读写(@property)

场景说明

控制类属性的赋值范围(如年龄只能是0-120),不直接暴露属性。

案例代码
class Person():def __init__(self):self.__age = 0  # 私有属性@propertydef age(self):return self.__age@age.setterdef age(self,val):if not isinstance(val,int) or val <0 or val>120:raise ValueError("年龄必须是0-120的整数")self.__age = valp = Person()
p.age = 20
print(p.age)
# p.age = 150  # 触发ValueError
逐步运算过程
  1. 实例化p = Person(),私有属性__age=0
  2. p.age = 20 → 触发age.setter方法:
    • 检查20是0-120的整数,符合规则;
    • 赋值self.__age = 20
  3. print(p.age) → 触发age.property方法,返回self.__age=20
  4. 若赋值p.age=150 → 检查失败,抛出ValueError

4.4 应用场景4:缓存函数返回结果(避免重复计算)

场景说明

耗时的计算函数(如斐波那契),缓存已计算的结果,重复调用直接返回缓存值。

案例代码
# 装饰器:缓存结果
def cache(func):cache_dict = {}  # 缓存字典def newfunc(n):if n not in cache_dict:cache_dict[n] = func(n)  # 计算并缓存return cache_dict[n]return newfunc@cache
def fib(n):if n <=2:return 1return fib(n-1)+fib(n-2)# 第一次调用(计算+缓存)
print(fib(10))
# 第二次调用(直接返回缓存)
print(fib(10))
逐步运算过程
  1. @cachefib = cache(fib),newfunc替换原函数,cache_dict初始化空字典;
  2. 第一次调用fib(10)
    • n=10不在cache_dict,调用原fib(10)计算得55;
    • 缓存cache_dict[10] = 55,返回55;
  3. 第二次调用fib(10)
    • n=10cache_dict,直接返回cache_dict[10]=55,无需重复计算。


23、异常处理

Python异常处理核心课件(简化版)

全文总结

表格版核心总结

核心模块 关键知识点 核心作用
异常基础概念 1. 语法错误:违反Python语法规则(必改);2. 异常错误:语法正确但运行时出错(可捕获) 区分两类错误,明确异常处理的目标是解决运行时异常
常见异常类型 索引错误(IndexError)、键错误(KeyError)、除零错误(ZeroDivisionError)等30+类型 识别不同异常场景,精准捕获和处理错误
异常处理语法 1. try-except:捕获异常;2. try-except-else:无异常执行else;3. try-finally:必执行finally 避免程序崩溃,控制异常后的执行逻辑(如释放资源)
主动抛出异常 1. raise抛出内置异常;2. 自定义异常类(继承BaseException);3. 获取错误行号/文件名 主动校验业务规则,抛出精准的自定义错误信息
模块导入(辅助) 1. import/from import导入模块/包;2. 别名/相对路径导入;3. __name__区分执行方式 复用代码,组织项目结构,实现单入口模式

分段版核心总结

1. 异常的本质

程序错误分两类:

  • 语法错误:比如缩进混乱、关键字拼写错,属于“写法错误”,必须修正语法才能运行;
  • 异常错误:比如索引越界、除数为0,属于“运行时错误”,可通过异常语法捕获并继续执行程序。
2. 异常处理的核心逻辑

try包裹“可能出错的代码”,异常触发时跳转到except处理;else仅在无异常时执行,finally无论是否异常都执行(如关闭文件)。

3. 主动抛异常的价值

通过raise主动触发异常,可实现自定义业务规则校验(如性别只能是男/女),并携带错误号、行号等精准信息。

4. 模块导入的辅助作用

模块(.py文件)/包(含__init__.py的文件夹)是代码复用核心,支持多种导入方式,__name__可实现“单入口模式”(仅主文件执行)。

完整详细输出(带详细运算过程)

一、异常基础概念(从0理解)

1.1 两类程序错误

语法错误(必改,无法运行)
  • 定义:代码违反Python语法规则,解释器直接拒绝运行。
  • 示例代码:
# 错误示例:缩进混用Tab和空格
if 5 == 5:print(22)  # 空格缩进print(11)  # Tab缩进
  • 运算过程:
    运行代码后,解释器立即报错IndentationError: unindent does not match any outer indentation level,程序无法启动,必须统一缩进(全用空格/Tab)才能运行。
异常错误(可捕获,运行时触发)
  • 定义:语法完全正确,但运行时因逻辑/数据问题触发错误。
  • 示例代码:
# 错误示例:索引越界
listvar = [1,2,3]
print(listvar[99])
  • 运算过程:
    1. 执行listvar = [1,2,3]:创建列表,无问题;
    2. 执行print(listvar[99]):列表最大索引为2,触发IndexError
    3. 程序崩溃,输出IndexError: list index out of range

1.2 高频异常类型(必记)

异常类型 触发场景 示例代码 报错信息
IndexError 索引超出序列范围 [1,2][3] list index out of range
KeyError 字典查不存在的键 {"a":1}["b"] KeyError: 'b'
ZeroDivisionError 除数为0 10/0 ZeroDivisionError: division by zero
TypeError 不同类型无效操作 1 + "2" TypeError: unsupported operand type(s) for +: 'int' and 'str'
ValueError 传入无效参数 int("abc") ValueError: invalid literal for int() with base 10: 'abc'

二、异常处理核心语法(一步步学)

2.1 基础语法:try-except(捕获异常)

语法结构:
try:# 监控可能出错的代码待执行代码
except [异常类型]:# 异常触发时执行的代码异常处理代码
示例:捕获索引越界异常
try:listvar = [1,2,3,4,5]listvar[999]  # 可能出错的代码
except:print("有异常错误...")
运算过程:
  1. 执行try块:先创建列表listvar = [1,2,3,4,5]
  2. 执行listvar[999]:触发IndexError
  3. 跳转到except块,输出有异常错误...
  4. 程序不崩溃,继续运行后续代码。

2.2 多分支异常捕获(精准处理)

示例代码:
try:dic = {"a":1,"b":2}dic["pppooii"]  # 触发KeyErrorprint(wangwen)  # 若上面无异常,触发NameError
except IndexError:print("索引下标错误")
except KeyError:print("找不到对应的键")
except:print("其他异常")
运算过程:
  1. 执行try块:创建字典dic = {"a":1,"b":2}
  2. 执行dic["pppooii"]:触发KeyError
  3. 匹配except KeyError分支,输出找不到对应的键
  4. 后续print(wangwen)不再执行,程序正常结束。

2.3 扩展语法:try-except-else

语法:无异常时执行else分支
try:print(123)  # 无异常代码
except:print(112233)
else:print(456)
运算过程:
  1. 执行try块:输出123,无异常;
  2. 跳过except,执行else块,输出456
  3. 最终输出:123456

2.4 扩展语法:try-finally(必执行)

示例代码:
try:print(333)listvar[999]  # 触发异常
finally:print(111)print(222)
运算过程:
  1. 执行try块:输出333,然后触发IndexError
  2. 先执行finally块,输出111222
  3. 程序最终崩溃(未捕获异常),但finally内容已执行。

2.5 完整语法:try-except-else-finally

执行优先级:
  • 有异常:try → except → finally;
  • 无异常:try → else → finally。

三、主动抛出异常(raise)

3.1 基础用法:抛出内置异常

try:raise KeyError  # 主动抛出KeyError
except KeyError:print("捕获到主动抛出的KeyError")
运算过程:
  1. 执行try块:raise KeyError主动触发异常;
  2. 匹配except KeyError分支,输出捕获到主动抛出的KeyError
  3. 程序正常结束。

3.2 进阶:自定义异常类

步骤1:定义自定义异常类(继承BaseException)
class MyException(BaseException):def __init__(self, err_num, err_msg, err_line, err_filename):self.err_num = err_num      # 错误号self.err_msg = err_msg      # 错误信息self.err_line = err_line    # 错误行号self.err_filename = err_filename  # 错误文件名
步骤2:获取错误行号/文件名的函数
def return_errorinfo(n):import sysf = sys.exc_info()[2].tb_frame.f_backif n==1:return str(f.f_lineno)      # 行号elif n == 2:return f.f_code.co_filename # 文件名def get_info(n):try:raise  # 触发异常才能获取信息except:return return_errorinfo(n)
步骤3:主动抛出并捕获自定义异常
sex = "中性"
try:if sex == "中性":raise MyException(10089,"人类没有中性!!",get_info(1),get_info(2))
except MyException as e:print("错误号:", e.err_num)print("错误信息:", e.err_msg)print("错误行号:", e.err_line)print("错误文件:", e.err_filename)
运算过程:
  1. 定义sex = "中性",进入try块;
  2. 判定sex == "中性"为True,执行raise MyException(...)
  3. 调用get_info(1):触发raise → 获取行号;
  4. 调用get_info(2):获取文件名;
  5. 抛出MyException,被except捕获,输出:
    错误号: 10089
    错误信息: 人类没有中性!!
    错误行号: 45(实际行号随代码位置变化)
    错误文件: 3.主动抛出异常.py
    

四、模块导入(辅助知识点)

4.1 核心概念

  • 模块:单个.py文件(代码复用单位);
  • 包:包含__init__.py的文件夹(管理多个模块)。

4.2 基础导入方式

导入方式 语法示例 调用方式
import 模块 import keyword keyword.kwlist
import 模块 as 别名 import keyword as kw kw.kwlist
from 模块 import 成员 from keyword import kwlist kwlist

五、应用场景及案例(带详细运算过程)

5.1 场景1:数据校验(业务规则校验)

场景描述:校验用户输入的年龄(1-120的整数)
案例代码:
# 自定义异常类
class AgeError(BaseException):def __init__(self, err_msg, err_line):self.err_msg = err_msgself.err_line = err_line# 获取错误行号
def get_line():try:raiseexcept:import sysreturn str(sys.exc_info()[2].tb_frame.f_back.f_lineno)# 校验逻辑
try:age_input = input("请输入年龄(1-120):")age = int(age_input)if not (1 <= age <= 120):raise AgeError(f"年龄{age}超出范围", get_line())
except ValueError:print(f"错误:{age_input}不是整数(行号:{get_line()})")
except AgeError as e:print(f"错误:{e.err_msg}(行号:{e.err_line})")
else:print(f"年龄{age}校验通过")
finally:print("校验流程结束")
运算过程(测试场景:输入200)
  1. 执行input:用户输入200age_input = "200"
  2. 执行age = int(age_input):转换为200
  3. 判定1<=200<=120为False,执行raise AgeError(...)
  4. 调用get_line()获取行号,抛出AgeError
  5. 匹配except AgeError分支,输出错误:年龄200超出范围(行号:19)
  6. 执行finally块,输出校验流程结束
  7. 最终输出:
    请输入年龄(1-120):200
    错误:年龄200超出范围(行号:19)
    校验流程结束
    

5.2 场景2:文件操作(避免文件不存在崩溃)

场景描述:读取文件,捕获不存在/编码异常,确保关闭文件句柄
案例代码:
file_path = "test.txt"
f = None
try:f = open(file_path, "r", encoding="utf-8")content = f.read()print(f"文件内容:{content}")
except FileNotFoundError:print(f"错误:文件{file_path}不存在")
except UnicodeDecodeError:print(f"错误:文件编码不是utf-8")
finally:if f:f.close()print("文件句柄已关闭")else:print("文件未打开,无需关闭")
运算过程(测试场景:文件不存在)
  1. 执行f = open(file_path, "r", ...):触发FileNotFoundError
  2. 匹配except FileNotFoundError分支,输出错误:文件test.txt不存在
  3. 执行finally块:fNone,输出文件未打开,无需关闭
  4. 最终输出:
    错误:文件test.txt不存在
    文件未打开,无需关闭
    

5.3 场景3:生成器迭代(捕获StopIteration)

场景描述:遍历生成器,捕获迭代结束异常,获取return值
案例代码:
def num_gen():yield 1yield 2return "生成器迭代完毕"try:gen = num_gen()for i in range(10):num = next(gen)print(f"迭代第{i+1}次:{num}")
except StopIteration as e:print(f"迭代结束:{str(e)}")
运算过程:
  1. 初始化生成器gen = num_gen()
  2. 循环i=0next(gen)返回1,输出迭代第1次:1
  3. 循环i=1next(gen)返回2,输出迭代第2次:2
  4. 循环i=2next(gen)触发StopIteration,携带生成器迭代完毕
  5. 匹配except StopIteration分支,输出迭代结束:生成器迭代完毕
  6. 最终输出:
    迭代第1次:1
    迭代第2次:2
    迭代结束:生成器迭代完毕
    


24、ATM 系统完整开发流程

全文总结

一、开发流程总表(清晰版)

开发阶段 核心工作 输出产物
需求分析 梳理10大业务+5条强制校验规则 业务清单、校验规则
类设计 拆分4个核心类(卡/用户/视图/操作) 类结构、属性方法
数据修复 解决user.txt/userid.txt乱码 UTF-8编码数据文件
功能开发 逐行实现10大ATM业务 功能代码、校验逻辑
启动运行 单入口main.py统一调度 可运行完整项目

二、核心逻辑总结

  1. 业务核心:开户/查询/存钱/取钱/转账/改密/锁卡/解卡/补卡/退出 10大功能;
  2. 架构核心:面向对象4类分工,高内聚低耦合,互不干扰;
  3. 校验核心:姓名/密码/身份证非空,身份证唯一,禁止给自己转账;
  4. 问题解决:文件乱码→重新保存为UTF-8编码即可正常读取。

一、需求分析(开发第一步)

1. 10大核心业务(必做)

  1. 开户(register):新用户办卡,录入个人信息
  2. 查询(query):查看余额、卡锁定状态
  3. 存钱(save_money):增加卡片余额
  4. 取钱(get_money):扣减余额(校验余额/卡状态)
  5. 转账(trans_money):转给他人(禁止转自己)
  6. 改密(change_pwd):原密码/身份证两种方式改密
  7. 锁卡(lock):冻结卡片,停止交易
  8. 解卡(unlock):解冻卡片,恢复使用
  9. 补卡(new_card):旧卡丢失,新卡继承所有信息
  10. 保存退出(save):保存数据,关闭系统

2. 强制校验规则(死守)

  1. 姓名:不能为空
  2. 密码:必须6位,不能为空
  3. 身份证:必须18位,不能为空,一个身份证只能开1张卡
  4. 转账:不能给自己转账
  5. 所有交易:卡必须存在、未被冻结

二、类结构设计(面向对象拆分)

1. 四大核心类(分工明确)

(1)Card 卡类

  • 作用:存储卡片本身数据
  • 属性:卡号(cardid)、密码(password)、余额(money)、是否锁定(islock)

(2)Person 用户类

  • 作用:绑定用户信息 + 卡片
  • 属性:姓名(name)、身份证(userid)、电话(phone)、卡对象(card)

(3)View 视图类

  • 作用:界面展示 + 用户交互
  • 方法:登录(login)、打印菜单(show_menu)

(4)Operation 操作类

  • 作用:实现所有业务逻辑
  • 方法:10大ATM功能全部写在这里

2. 类之间关系

  • 1个用户(Person) 绑定 1张卡(Card)
  • 视图(View)负责输入输出,调用操作(Operation)
  • 操作(Operation)修改用户/卡的数据
  • main.py 单入口启动整个系统

三、数据处理(解决文件乱码)

1. 问题

user.txt/userid.txt 报错:文件乱码,无法解析文本

2. 解决步骤(1分钟搞定)

  1. 用记事本打开两个文件
  2. 点击「另存为」→ 编码选择 UTF-8 → 覆盖原文件
  3. 存储格式:每行1条数据,逗号分隔
    卡号,姓名,身份证,电话,密码,余额,是否锁定

四、完整开发流程(一步步实现)

第1步:搭建项目目录

atm_project/
├── main.py           # 单入口(唯一启动文件)
├── package/          # 包(存放4个类)
│   ├── card.py       # 卡类
│   ├── person.py     # 用户类
│   ├── view.py       # 视图交互
│   └── operation.py  # 业务实现
├── user.txt          # 修复编码后的用户数据
└── userid.txt        # 修复编码后的卡号数据

第2步:编写4个基础类

(1)card.py

class Card:def __init__(self, cardid, password, money=0, islock=False):self.cardid = cardid    # 卡号self.password = password # 密码self.money = money      # 余额self.islock = islock    # 锁定状态 True=冻结

(2)person.py

class Person:def __init__(self, name, userid, phone, card):self.name = name      # 姓名self.userid = userid  # 身份证self.phone = phone    # 电话self.card = card      # 绑定卡对象

(3)view.py

class View:@staticmethoddef login():print("===== 欢迎使用ATM系统 =====")# 登录校验逻辑return True@staticmethoddef show_menu():print("1开户 2查询 3存钱 4取钱 5转账")print("6改密 7锁卡 8解卡 9补卡 0退出")

(4)operation.py

# 存放10大业务功能,后续逐步实现
class Operation:def __init__(self):# 加载user.txt/userid.txt数据到内存self.user_list = []

第3步:单入口main.py(启动)

from package.view import View
from package.operation import Operationclass Main():@staticmethoddef run():# 1. 登录if View.login():obj = Operation()# 2. 循环菜单while True:View.show_menu()choice = input("请选择业务:")# 3. 业务分发if choice == "1": obj.register()elif choice == "2": obj.query()elif choice == "3": obj.save_money()elif choice == "4": obj.get_money()elif choice == "5": obj.trans_money()elif choice == "6": obj.change_pwd()elif choice == "7": obj.lock()elif choice == "8": obj.unlock()elif choice == "9": obj.new_card()elif choice == "0": obj.save(); breakelse: print("输入错误")if __name__ == "__main__":	Main.run()

第4步:10大功能分步实现(核心)

1. 开户(register)

  1. 输入姓名→校验非空
  2. 输入身份证→校验18位、唯一
  3. 输入电话、密码→密码必须6位
  4. 生成卡号
  5. 创建Card→创建Person→保存到文件

2. 查询(query)

  1. 获取当前登录用户的卡
  2. 打印:卡号、姓名、余额、锁定状态

3. 存钱(save_money)

  1. 输入金额→校验>0
  2. 卡余额 += 金额
  3. 提示成功,保存数据

4. 取钱(get_money)

  1. 校验卡未冻结
  2. 输入金额→校验≤余额
  3. 卡余额 -= 金额
  4. 提示成功,保存数据

5. 转账(trans_money)

  1. 输入对方卡号→禁止转自己
  2. 校验对方卡存在、未冻结
  3. 输入金额→校验≤自己余额
  4. 自己扣钱、对方加钱
  5. 保存数据

6. 改密(change_pwd)

  • 原密码改密:输入旧密码→验证→设置新6位密码
  • 身份证改密:输入身份证→验证→设置新密码

7. 锁卡(lock)

  1. 找到当前卡
  2. 设置islock = True
  3. 保存,卡冻结

8. 解卡(unlock)

  1. 输入卡号+身份证→校验匹配
  2. 设置islock = False
  3. 保存,卡解冻

9. 补卡(new_card)

  1. 输入姓名+身份证→找到旧用户
  2. 生成新卡号
  3. 旧卡余额、密码全部赋值给新卡
  4. 旧卡作废,新卡生效

10. 保存退出(save)

  1. 内存所有数据写入user.txt
  2. 打印退出提示
  3. 结束程序

五、项目运行流程(新人实操)

1. 启动

运行main.py → 进入登录界面

2. 完整业务流程(演示)

  1. 1开户 → 录入信息 → 办卡成功
  2. 3存钱 → 输入1000 → 余额=1000
  3. 2查询 → 查看余额
  4. 5转账 → 转他人200 → 余额=800
  5. 6改密 → 修改密码
  6. 0退出 → 保存数据 → 关闭系统

3. 异常保护

  • 输入非数字→提示重新输入
  • 卡冻结→无法交易
  • 余额不足→取钱/转账失败
  • 身份证重复→开户失败

应用场景(ATM真实业务场景)

场景:用户丢卡补办+转账

详细运算过程

  1. 启动系统→登录旧账号
  2. 9补卡→输入姓名、身份证→验证通过
  3. 系统生成新卡号→继承旧卡800元余额
  4. 5转账→输入他人卡号、金额300→转账成功
  5. 新卡余额=500→旧卡作废
  6. 0退出→数据保存


25、正则表达式

全文总结

1. 正则表达式核心定义与用途

  • 定义:约束字符串匹配某种形式的规则,由普通字符(字母/数字)和元字符(特殊含义符号)组成。
  • 核心用途:
    • 校验:检测字符串是否符合规则(如手机号、身份证合法性);
    • 提取:从文本(如网页、日志)中提取目标数据(如爬虫取天气、股票代码)。

2. 正则核心元素速查表

正则核心元素速查表

2 匹配单个字符(正则的基础单元,精准匹配单个字符)
2.1 预定义字符集

  • 核心符号/规则:.、\d(数字)、\D(非数字)、\w(字母/数字/下划线)、\W(非\w)、\s(空白符)
  • 作用说明:快速匹配特定类型的单个字符

2.2 字符组

  • 核心符号/规则:[](列举字符)、[^](排除字符)、[0-9]/[a-z](范围)
  • 作用说明:自定义单个字符的匹配范围(如 [0-9a-f] 匹配十六进制)

2 匹配多个字符(控制字符/分组的重复次数,解决重复匹配需求)
2.1 量词

  • 核心符号/规则:?(0/1次)、+(≥1次)、*(0+次)、{n}(n次)、{n,m}(n-m次)
  • 作用说明:控制字符/分组的匹配次数

2.2 匹配模式

  • 核心符号/规则:.(贪婪)、.?(非贪婪)
  • 作用说明:贪婪:匹配最多字符;非贪婪:匹配最少字符(量词后加?)

2 边界控制(限定匹配位置,避免部分匹配错误)
2.1 边界符

  • 核心符号/规则:^(开头)、$(结尾)、\b (字符边界)
  • 作用说明:限定匹配的位置(如 ^1[3-9]\d{9}$ 匹配完整手机号)

2 分组与逻辑(处理复杂规则,实现多条件匹配和结果提取)
2.1 分组/或

  • 核心符号/规则:()(分组)、|(或)、(?P)(命名分组)
  • 作用说明:分组复用匹配内容,| 实现多规则匹配(长规则放前)

2 辅助功能(扩展匹配规则,适配复杂文本场景)
2.1 修饰符

  • 核心符号/规则:re.I(忽略大小写)、re.M(多行)、re.S(.匹配换行)
  • 作用说明:扩展匹配灵活性当前文件内容过长

3. 常用正则函数速查表

函数名 核心作用
findall 匹配所有符合规则的内容,返回列表
search 匹配第一个符合规则的内容,返回匹配对象(需group()取值)
match 从字符串开头匹配规则,返回匹配对象(常用于输入校验)
split 按正则规则切割字符串,返回列表
sub 按正则规则替换字符串,返回替换后结果
compile 预编译正则规则,重复使用提升效率

完整详细讲解

步骤1:理解正则的核心本质

正则是字符串匹配的规则,比如判断“13812345678”是否是手机号,需定义规则:以1开头,第二位3-9,后接9位数字,用正则写为^1[3-9]\d{9}$

步骤2:匹配单个字符(基础)

2.1 预定义字符集(现成规则直接用)
符号 含义 示例代码 运算过程 & 结果
. 任意字符(除\n) re.findall('a.b','a1b a@b a\nb') 匹配“a+任意字符+b”,\n不匹配 → ['a1b','a@b']
\d 数字 re.findall('\d','价格:99元') 匹配所有数字 → ['99']
\w 字母/数字/下划线 re.findall('\w','a_1@#b') 匹配字母/数字/下划线 → ['a','_','1','b']
2.2 字符组(自定义匹配范围)

核心语法:[](必须选1个)、[^](排除选1个)、-(范围)。

  • 示例1:re.findall('a[0-9]b','a1b a5b acb')
    运算过程:匹配“a+0-9数字+b” → 结果:['a1b','a5b']
  • 示例2:re.findall('a[^0-9]b','a1b a@b a_b')
    运算过程:匹配“a+非数字+b” → 结果:['a@b','a_b']

步骤3:匹配多个字符(量词控制次数)

量词控制“前面的字符/分组”匹配多少次,核心示例如下:

量词 含义 示例代码 运算过程 & 结果
? 0次或1次 re.findall('a?b','abb ab b') 匹配“0/1个a + b” → ['ab','ab','b']
+ ≥1次 re.findall('a+b','b ab aaab') 匹配“≥1个a + b” → ['ab','aaab']
* 0+次 re.findall('a*b','b ab aaaab') 匹配“0+个a + b” → ['b','ab','aaaab']
{n,m} n-m次 re.findall('a{1,3}b','ab aaab') 匹配“1-3个a + b” → ['ab','aaab']
3.1 贪婪 vs 非贪婪匹配
  • 贪婪(默认):.* 匹配尽可能多的字符
    示例:re.findall('a.*b','a123b456b') → 结果:['a123b456b'](匹配到最后一个b)
  • 非贪婪:.*?(量词后加?)匹配尽可能少的字符
    示例:re.findall('a.*?b','a123b456b') → 结果:['a123b'](匹配到第一个b即停止)

步骤4:控制匹配边界(精准定位)

边界符限定匹配的“位置”,核心示例:

  • ^(开头):re.findall('^大.','大哥大嫂') → 匹配开头的“大+任意字符” → ['大哥']
  • $(结尾):re.findall('大.$','大哥大嫂') → 匹配“任意字符+结尾的大” → ['大嫂']
  • ^+$(完整匹配):re.findall('^1[3-9]\d{9}$','13812345678') → 匹配完整11位手机号 → ['13812345678']

步骤5:分组与逻辑匹配(复杂规则)

5.1 分组(()):把多个字符当整体
  • 基础分组:re.findall('(ab)+','abab abc') → 匹配“ab”重复≥1次 → ['ab'](findall优先返回分组)
  • 取消分组优先:re.findall('(?:ab)+','abab abc') → 结果:['abab']
5.2 或逻辑(|):匹配多规则中的一个

规则:长规则放前面(避免被短规则覆盖)。
示例:匹配“www.baidu.com”或“www.oldboy.com”

import re
res = re.findall('www\.(baidu|oldboy)\.com','www.baidu.com www.oldboy.com')
print(res)  # 结果:['baidu','oldboy']

步骤6:正则修饰符(扩展规则)

  • re.I(忽略大小写):re.findall('a','A a',re.I)['A','a']
  • re.S(.匹配换行):re.findall('a.b','a\nb',re.S)['a\nb']

应用场景及案例(带详细运算过程)

场景1:输入合法性校验(最常用)

案例1:校验11位手机号
  • 需求:匹配以1开头,第二位3-9,后9位数字的完整手机号;
  • 正则:^1[3-9]\d{9}$
  • 测试代码:
    import re
    # 合法手机号
    res1 = re.findall('^1[3-9]\d{9}$','13812345678')
    # 非法手机号(第二位是2)
    res2 = re.findall('^1[3-9]\d{9}$','12812345678')
    print(res1)  # ['13812345678']
    print(res2)  # []
    
  • 运算过程:
    1. ^1:字符串开头必须是1;
    2. [3-9]:第二位必须是3-9;
    3. \d{9}:后接9位数字;
    4. $:字符串结尾(无多余字符)。
案例2:校验邮箱(如123463922@qq.com.cn)
  • 正则:^[\w\-\.]+@[a-zA-Z\d\-]+(\.[a-zA-Z\d\-]+)*\.[a-zA-Z0-9]{2,6}$
  • 测试代码:
    import re
    res = re.findall('^[\w\-\.]+@[a-zA-Z\d\-]+(\.[a-zA-Z\d\-]+)*\.[a-zA-Z0-9]{2,6}$','123463922@qq.com.cn')
    print(res)  # ['.cn'](分组优先,整体匹配成功)
    
  • 运算过程:
    1. ^[\w\-\.]+:匹配用户名(字母/数字/下划线/-/.,≥1个);
    2. @:匹配@符号;
    3. [a-zA-Z\d\-]+:匹配一级域名(如qq);
    4. (\.[a-zA-Z\d\-]+)*:匹配多级域名(如.com/.cn,0+次);
    5. \.[a-zA-Z0-9]{2,6}:匹配最终后缀(2-6位,如cn);
    6. $:字符串结尾。

场景2:文本内容提取(爬虫/日志分析)

案例:提取HTML标签内的内容(如wahaha
  • 需求:从<a>wahaha</a> <h1>qqxing</h1>提取标签内的文本;
  • 正则:<(.*?)>(.*?)<.*?>
  • 测试代码:
    import re
    text = '<a>wahaha</a> <h1>qqxing</h1>'
    res = re.findall('<(.*?)>(.*?)<.*?>',text)
    # 提取标签内内容(取第二个分组)
    content = [i[1] for i in res]
    print(content)  # ['wahaha','qqxing']
    
  • 运算过程:
    1. <(.*?)>:非贪婪匹配标签名(a/h1),存入第一个分组;
    2. (.*?):非贪婪匹配标签内文本(wahaha/qqxing),存入第二个分组;
    3. <.*?>:匹配闭合标签(/);
    4. findall返回所有分组结果,最终提取第二个分组即可。

场景3:字符串替换/切割(数据清洗)

案例:清洗手机号中的非数字字符
  • 需求:把138-1234-5678转为纯数字13812345678
  • 正则:\D(匹配非数字);
  • 测试代码:
    import re
    phone = '138-1234-5678'
    clean_phone = re.sub('\D','',phone)
    print(clean_phone)  # 13812345678
    
  • 运算过程:
    1. \D匹配所有非数字字符(-);
    2. re.sub将匹配到的内容替换为空字符串;
    3. 最终得到纯数字手机号。

场景4:数学表达式提取(复杂文本分析)

案例:提取数学表达式中最内层括号的内容
  • 需求:从1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))提取最内层括号内容;
  • 正则:\(([^()]+)\)(匹配括号内无括号的内容);
  • 测试代码:
    import re
    expr = '1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'
    res = re.findall(r'\(([^()]+)\)',expr)
    print(res)
    # 结果:['-40/5', '9-2*5/3+7/3*99/4*2998+10*568/14', '-4*3', '16-3*2']
    
  • 运算过程:
    1. \(:匹配左括号;
    2. ([^()]+):分组匹配“非括号的内容”(最内层括号无嵌套);
    3. \):匹配右括号;
    4. 最终提取所有最内层括号的内容。


26、正则表达式

全文总结

1. 正则表达式核心定义

正则表达式是约束字符串匹配规则的语法,核心作用分两类:

  • 校验类:验证字符串合法性(如手机号、身份证号格式);
  • 处理类:提取/替换/切割字符串中的目标数据(如爬虫提取关键字、清洗特殊字符)。

2. 正则核心元素(表格)

元素类别 核心符号/规则 核心作用
预定义字符集 .、\d、\w、[]、[^...] 匹配单个字符(数字/字母/自定义字符范围,或排除指定字符)
量词 ?、+、*、{n}、{n,}、 控制字符重复次数(支持贪婪/非贪婪匹配,非贪婪需加?)
边界符 ^、$、\b 限定匹配位置(开头/结尾/字符边界,避免部分匹配)
分组 ()、|、(?P)、(?P=name) 批量匹配(或逻辑)、分组引用(普通/命名分组)
修饰符 re.I、re.M、re.S 扩展匹配规则(忽略大小写、多行匹配、.匹配换行)

3. 正则核心函数(表格)

函数名 核心作用 适用场景
findall 匹配所有结果,返回列表 批量提取目标数据(如爬虫提取链接)
search 匹配第一个结果,返回对象(需group取值) 提取单个目标+分组内容(如日志提取时间)
match 从字符串开头匹配,返回对象 校验输入合法性(如手机号/密码格式)
split 按规则切割字符串,返回列表 拆分多分隔符字符串(如`alex
sub/subn 按规则替换字符串 清洗特殊字符(sub返回字符串,subn返回“字符串+替换次数”)
finditer 匹配所有结果,返回迭代器 处理大字符串(节省内存,逐次取值)
compile 预编译正则表达式 重复使用同一正则(避免反复编译,提升效率)

4. 贪婪/非贪婪匹配

  • 贪婪匹配(默认):量词(*、+、{})向“更多次数”匹配(如a.*b匹配到最后一个b);
  • 非贪婪匹配:量词后加?(如a.*?b),向“更少次数”匹配(遇到第一个b即停止)。

完整详细内容(带运算过程)

第一步:基础 - 匹配单个字符(预定义字符集)

核心逻辑:针对“单个字符”的精准匹配,是正则的最小单元。

符号/语法 示例代码 运行结果 运算逻辑解释
. re.findall('.', 'a1\n') ['a', '1'] .匹配任意字符(除换行符\n),所以\n不匹配
\d re.findall('\d', 'a1b2') ['1', '2'] \d仅匹配数字,a/b是非数字不匹配
\D re.findall('\D', 'a1b2') ['a', 'b'] \D匹配非数字,1/2是数字不匹配
\w re.findall('\w', 'a_1#') ['a', '_', '1'] \w匹配字母/数字/下划线,#是非\w字符不匹配
[] re.findall('[0-9a-z]', 'A1b') ['1', 'b'] [0-9a-z]匹配数字/小写字母,A(大写)不匹配
[^...] re.findall('[^0-9]', 'A1b') ['A', 'b'] [^0-9]排除数字,1是数字不匹配

第二步:进阶 - 匹配多个字符(量词)

核心逻辑:控制“单个字符/分组”的重复次数,区分贪婪/非贪婪。

量词 示例代码 运行结果 运算逻辑解释
? re.findall('a?b', 'abb') ['ab', 'b'] a出现0/1次后接b:第一个b前有1个a(ab),第二个b前有0个a(b)
+ re.findall('a+b', 'abb') ['ab'] a出现≥1次后接b:仅第一个b前的a满足,第二个b前无a不匹配
* re.findall('a*b', 'abb') ['ab', 'b'] a出现≥0次后接b:两个b都满足(第一个有a,第二个无a)
re.findall('a{2}b', 'aab') ['aab'] a必须出现2次后接b:aab中a刚好2次,匹配成功
re.findall('a{2,}b', 'aaab') ['aaab'] a出现≥2次后接b:aaab中a有3次,满足条件
re.findall('a{1,2}b', 'aaab') ['aab'] a出现1-2次后接b:取前2个a+ b,剩余1个a无匹配
贪婪 re.findall('a.*b', 'a1b2b') ['a1b2b'] .*贪婪匹配到最后一个b,覆盖1b2全部内容
非贪婪 re.findall('a.*?b', 'a1b2b') ['a1b'] .*?非贪婪匹配到第一个b即停止,仅覆盖1

第三步:精准匹配 - 边界符

核心逻辑:限定匹配的“位置”,避免“部分匹配”导致的错误结果。

边界符 示例代码 运行结果 运算逻辑解释
^ re.findall('^大.', '大哥大嫂') ['大哥'] ^限定“开头”,仅匹配第一个“大+任意字符”
$ | re.findall('大.$', '大哥大嫂') ['大嫂'] $限定“结尾”,仅匹配最后一个“大+任意字符”
^+$ | re.findall('^giveme$', 'giveme') ['giveme'] ^+$限定“完全匹配”,字符串必须和正则完全一致

第四步:批量匹配 - 分组

核心逻辑:将多个字符视为整体,支持“或逻辑”“分组引用”。

分组语法 示例代码 运行结果 运算逻辑解释
a|b re.findall('135|171', '1356789') ['135'] 匹配135或171,字符串中只有135满足
() re.findall('(.*?)_good', 'wusir_good') ['wusir'] ()是分组,findall优先返回分组内内容,而非完整的wusir_good
(?😃 re.findall('(?:.*?)_good', 'wusir_good') ['wusir_good'] ?:取消分组优先显示,返回完整匹配结果
命名分组 re.search('(?P<name>.*?)_good', 'wusir_good').group('name') wusir 给分组命名为name,通过group('name')直接取值,更易读

第五步:扩展规则 - 修饰符

核心逻辑:调整匹配的附加规则,解决“大小写/多行/换行”问题。

修饰符 示例代码 运行结果 运算逻辑解释
re.I re.search('<h1>(.*?)</h1>', '<h1>abc</H1>', flags=re.I).group(1) abc 忽略大小写,和视为一致
re.M re.findall('^<.*?>(.*?)<.*?>, '<h1>a</h1>\n<h2>b</h2>', flags=re.M) | ['a', 'b'] | 多行匹配,^/$作用于每行开头/结尾,而非整个字符串
re.S re.search('(.*?)mefive', 'give\n123mefive', flags=re.S).group(1) give\n123 .匹配换行符\n,否则仅匹配give(\n会中断匹配)

第六步:实战工具 - 正则函数

1. search(提取第一个结果+分组)
import re
strvar = "a123b c8f"
obj = re.search("(.*?)(\d+)", strvar)
print(obj.group())    # 结果:a123(匹配整个正则)
print(obj.group(1))   # 结果:a(第一个分组:任意字符非贪婪)
print(obj.groups())   # 结果:('a', '123')(所有分组)

运算逻辑(.*?)匹配到a(非贪婪),(\d+)匹配到123(连续数字),整体匹配a123。

2. match(开头匹配,校验输入)
import re
strvar = "dj23sdf"
obj1 = re.match("\d+", strvar)  # 开头是d(非数字),返回None
obj2 = re.match("^d.*", strvar) # 开头是d,后续任意字符,返回对象
print(obj2.group())  # 结果:dj23sdf

运算逻辑:match等价于search加,仅从开头匹配,所以\d+匹配失败,d.*匹配成功。

3. split(按规则切割)
import re
strvar = "alex134wusir909xboyww"
res1 = re.split("\d+", strvar)  # 结果:['alex', 'wusir', 'xboyww'](按数字切割)
res2 = re.split("\d+", strvar, 1) # 结果:['alex', 'wusir909xboyww'](仅切割1次)

运算逻辑\d+匹配连续数字,split按这些数字拆分字符串,第二个参数控制切割次数。

4. sub/subn(替换)
import re
strvar = "alex^wusir%xboyww$"
res1 = re.sub("[\^%$]", "-", strvar)    # 结果:alex-wusir-xboyww-(替换所有)
res2 = re.sub("[\^%$]", "-", strvar, 2) # 结果:alex-wusir-xboyww$(仅替换2次)
res3 = re.subn("[\^%$]", "-", strvar, 2)# 结果:('alex-wusir-xboyww$', 2)(返回字符串+次数)

运算逻辑[\^%$]匹配^/%/$,sub将其替换为-,第三个参数限定替换次数。

5. finditer(迭代器匹配,省内存)
import re
strvar = "sdf3423sdf43234sdf23423"
it = re.finditer("\d+", strvar)
print(next(it).group())  # 结果:3423(第一个数字)
for i in it:print(i.group())     # 结果:43234、23423(剩余数字)

运算逻辑:finditer返回迭代器,逐次生成匹配对象,避免一次性加载所有结果到内存。

6. compile(预编译正则,提效率)
import re
strvar = "234sdf234"
pattern = re.compile("\d+(.*?)\d+")  # 预编译正则
res1 = pattern.findall(strvar)       # 结果:['sdf']
res2 = pattern.search(strvar).group(1) # 结果:sdf

运算逻辑:compile仅编译正则一次,后续重复调用findall/search无需重新编译,提升效率。

应用场景及案例(带详细运算过程)

场景1:手机号合法性校验

需求:校验11位手机号,且以135/171开头。
正则规则^1(35|171)\d{8}$

  • ^:字符串开头;1:手机号首位固定为1;(35|171):第二位+第三位为35/171;\d{8}:后续8位数字;$:字符串结尾。

案例代码+运算过程

import re
def check_phone(phone):pattern = re.compile("^1(35|171)\d{8}$")return bool(pattern.match(phone))# 测试用例
print(check_phone("13512345678"))  # True:135开头+8位数字,11位
print(check_phone("17112345678"))  # True:171开头+8位数字,11位
print(check_phone("13612345678"))  # False:开头非135/171
print(check_phone("1351234567"))   # False:仅10位,\d{8}匹配失败

运算逻辑:match从开头匹配,需完全满足“1+35/171+8位数字+结尾”才返回True。

场景2:爬虫提取网页链接

需求:从HTML字符串中提取所有<a href="链接">中的链接。
正则规则<a href="(.*?)">

  • <a href=":固定前缀;(.*?):非贪婪匹配链接(避免匹配到最后一个">);">:固定后缀。

案例代码+运算过程

import re
html = '<a href="https://www.baidu.com">百度</a><a href="https://www.oldboy.com">老男孩</a>'
pattern = re.compile('<a href="(.*?)">')
links = pattern.findall(html)
print(links)  # 结果:['https://www.baidu.com', 'https://www.oldboy.com']

运算逻辑:findall优先返回分组内内容,(.*?)非贪婪匹配,遇到第一个">即停止,所以提取到两个链接。

场景3:字符串清洗(替换特殊字符)

需求:将字符串中的^、%、\(、#替换为-,仅替换前2次。 **正则规则**:`[\^%\)#]`(匹配^/%/$/#中的任意一个)。

案例代码+运算过程

import re
strvar = "name^age%gender$address#"
res = re.sub("[\^%$#]", "-", strvar, 2)
print(res)  # 结果:name-age-gender$address#

运算逻辑:第一个^替换为-,第二个%替换为-,第三个$、第四个#未替换(仅替换2次)。

场景4:日志提取关键信息

需求:从日志2024-05-01 10:00 ERROR: 登录失败中提取“时间”和“错误类型”。
正则规则(\d{4}-\d{2}-\d{2} \d{2}:\d{2}) (.*?):

  • 第一个分组:匹配时间(年-月-日 时:分);第二个分组:匹配错误类型(非贪婪到:停止)。

案例代码+运算过程

import re
log = "2024-05-01 10:00 ERROR: 登录失败"
pattern = re.compile("(\d{4}-\d{2}-\d{2} \d{2}:\d{2}) (.*?):")
obj = pattern.search(log)
time = obj.group(1)       # 结果:2024-05-01 10:00
error_type = obj.group(2) # 结果:ERROR
print(f"时间:{time},错误类型:{error_type}")

运算逻辑:search匹配第一个结果,group(1)提取时间分组,group(2)提取错误类型分组。

场景5:多行日志提取告警级别

需求:从多行日志中提取每行的告警级别(INFO/WARN/ERROR)。
正则规则^(\w+):(加re.M修饰符,多行匹配)。

案例代码+运算过程

import re
log = """INFO: 系统启动成功
WARN: 内存使用率80%
ERROR: 数据库连接失败
"""
pattern = re.compile("^(\w+):", flags=re.M)
levels = pattern.findall(log)
print(levels)  # 结果:['INFO', 'WARN', 'ERROR']

运算逻辑:re.M让^作用于每行开头,(\w+)匹配每行的告警级别,findall返回所有分组内容。

http://www.jsqmd.com/news/897687/

相关文章:

  • Turnitin降AI还在瞎折腾?实测避坑:3款高效工具助你从80%稳降至10%
  • 发膜真实用户报告:大数据揭秘哪款卖最好 - 资讯速览
  • SPSS实战:卡方检验在医学研究中的分布验证
  • 新沃李晓伟律师团队,让沈阳保险拒赔法律纠纷一键化解 - 行路心安
  • UniversalUnityDemosaics终极指南:免费去除Unity游戏马赛克
  • 2026年AI搜索引流哪家强?选服务商需要避开这三个误区 - FaiscoJeff
  • 绵阳黄金回收门店怎么选靠谱商家看这篇长悦领跑 优选长悦 - 专业黄金回收
  • 使用AI教材写作工具,轻松搞定教材编写,还能保证低查重率!
  • 2026三亚目的地婚礼全新最终版攻略|滨海婚礼品牌排名+选店避坑完整版 - 江湖评测
  • 2026年OpenClaw翻车后的最佳替代选择,支持私有化部署替代方案推荐:速+X综合智能体系统1.0 - 品牌2025
  • ChatGPT谜题解答成功率暴跌预警(2024Q2实测数据:未结构化提问导致47.6%失败率)
  • 2026 国内广东佛山地区五大包装印刷推荐:2026 最新排名出炉,佛山市千寻包装印刷有限公司以综合实力领先 - 十大品牌榜
  • 给新手的华为云Region、VPC、AZ选择指南:从概念到实战,看完就懂
  • 深圳外贸网站建设公司排名2026年:多语言与海外访问速度对比 - 资讯速览
  • Windows风扇控制终极指南:FanControl让电脑静音又高效
  • 华彩台球选购指南:专业竞技级球台挑选全攻略 - 资讯速览
  • 软文媒体发布怎么做才有效?怎么发新闻媒体软文才能达到想要的效果? - 代码非世界
  • 2026年佛山搬厂/搬家公司哪家好?深度测评实力品牌解析! - 深度智识库
  • MATLAB图像质量评估实战:从SSIM与PSNR原理到自定义实现
  • 告别虚拟机!在Ubuntu 20.04上用Wine 5.0跑微信,保姆级配置与美化全记录
  • 卖粉末涂料怎么找客户?下游工厂都在哪里
  • 深圳厂房仓库搬家选哪家好?2026避坑全攻略 - 幸福生活序曲
  • 终极指南:chfsgui图形化文件共享工具快速上手教程
  • 2026全国光伏电缆TOP5品牌实力榜:谁是首选? - 深度智识库
  • 基于上下文感知与迁移学习的VLC/RF异构网络智能选择算法
  • 2026丽江雪山目的地婚礼备婚选购全指南|避坑干货+预算分级+头部品牌精准匹配 - 江湖评测
  • 2026 湖北百度推广公司哪家靠谱?本地优质服务商详细推荐 - 深度智识库
  • VPKEdit终极指南:免费高效的Valve游戏资源管理器
  • 动态子阵列混合预编码:毫米波大规模MIMO中性能与效率的平衡之道
  • AI财务审核系统哪家好?智能发票识别与合规审查平台精选 | 汇联易 - 财务流程医生