[{"columns":"python-course","content":"Python 基础第一课：你好世界 课程概述 欢迎来到 Python 编程系列课程的第一天！本节课我们将一起踏入 Python 编程的精彩世界。今天的学习内容包括：Python 语言简介、安装与运行环境、print() 函数的标准输出、代码注释的写法，以及现代 Python 中最常用的 f-string（格式化字符串字面量）。本课程内容基于 Python 3.11 编写，涵盖了 Python 3.11 中引入的最新语法特性与最佳实践。无论你是完全没有编程经验的初学者，还是从其他语言转来的开发者，本课程都将帮助你建立扎实的基础。\nPython 由荷兰程序员 Guido van Rossum 于 1991 年首次发布，至今已有超过 30 年的发展历史。Python 的设计哲学强调代码的可读性和简洁性，其核心原则之一就是\u0026quot;Readability counts\u0026quot;（可读性很重要）。Python 使用缩进（indentation）来划分代码块，而不是像许多其他语言那样使用大括号 {} 或 begin/end 关键字。这种独特的设计使得 Python 代码在视觉上非常清晰，也强制开发者写出格式良好的代码。Python 的另一条著名的设计原则是\u0026quot;Simple is better than complex\u0026quot;（简单优于复杂），这使得 Python 成为最适合初学者入门的编程语言之一。\nPython 3.11 的新特性 在学习基础知识之前，我们有必要了解一下 Python 3.11 相比之前版本带来了哪些重要改进。Python 3.11 于 2022 年 10 月正式发布，被誉为\u0026quot;Python 史上最快的版本\u0026quot;，其解释器启动速度比 Python 3.10 快了 10-15%，而平均执行速度更是提升了 25%。这些性能的提升主要来自于对 Python 虚拟机（Virtual Machine）的深度优化和重构。Python 3.11 还引入了更为精确的错误提示信息（Better Error Messages），当程序出现异常时，Python 3.11 会显示更多上下文信息，帮助开发者更快地定位和修复问题。\n在语法层面，Python 3.11 引入了\u0026quot;异常组\u0026quot;（Exception Groups）和except*语法，用于并发编程中的错误处理。同时，Python 3.11 还改进了类型提示（Type Hints）系统，支持使用变量名直接注解类型，并在标准库中添加了新的tomllib模块来解析 TOML 格式文件。Python 3.11 的另一个重要特性是对 f-string 的进一步增强——虽然 f-string 在 Python 3.6 就已引入，但 Python 3.11 对其进行了多项改进，包括支持更复杂的表达式求值和调试功能。了解这些新特性对于编写现代化的 Python 代码至关重要。\n第一个 Python 程序：print() 函数 让我们从最简单的程序开始。传统上，程序员学习一门新语言的第一个程序就是\u0026quot;Hello, World!\u0026quot;（你好，世界！）。在 Python 中，这个程序简单到只需要一行代码：\nprint(\u0026#34;Hello, World!\u0026#34;) 运行这行代码，你将看到终端上输出：\nHello, World!这就是你的第一个 Python 程序！虽然它非常简单，但其中包含了几个重要的概念。print() 是 Python 的一个内置函数（built-in function），函数名后面紧跟着一对圆括号 ()，括号内的 \u0026quot;Hello, World!\u0026quot; 被称为函数的参数（argument）。print() 函数的作用是将括号内的内容输出到标准输出设备（通常是终端屏幕）。字符串内容必须用引号包裹起来，Python 支持单引号 '...' 和双引号 \u0026quot;...\u0026quot; 两种方式定义字符串，两者在功能上是等价的。\n让我们多尝试几个 print() 的例子：\nprint(\u0026#34;你好，世界！\u0026#34;) print(\u0026#39;Python 3.11 是目前最新的稳定版本\u0026#39;) print(\u0026#34;让我们开始学习 Python 编程吧！\u0026#34;) 在 Python 3.11 中运行这些代码，你将看到：\n你好，世界！ Python 3.11 是目前最新的稳定版本 让我们开始学习 Python 编程吧！print() 函数不仅可以输出字符串，还可以输出各种 Python 数据类型的值：\nprint(42) # 输出整数 print(3.14159) # 输出浮点数 print(True) # 输出布尔值 print(None) # 输出空值 输出结果：\n42 3.14159 True Noneprint() 函数的 sep 和 end 参数 print() 函数实际上是一个功能非常丰富的函数，它接受多个参数。了解这些参数可以让你更好地控制输出格式。\nsep 参数用于指定多个参数之间的分隔符，默认为一个空格 ' '。end 参数用于指定输出结束后追加的字符，默认为换行符 '\\n'。\nprint(\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;, sep=\u0026#34;,\u0026#34;) # 输出：苹果,香蕉,橙子 print(\u0026#34;第一行\u0026#34;, end=\u0026#34; | \u0026#34;) print(\u0026#34;第二行\u0026#34;) # 输出：第一行 | 第二行 print(\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;, sep=\u0026#34; -\u0026gt; \u0026#34;) # 输出：a -\u0026gt; b -\u0026gt; c 在 Python 3.11 中运行上述代码，输出结果为：\n苹果,香蕉,橙子 第一行 | 第二行 a -\u0026gt; b -\u0026gt; cprint() 函数的美化输出 在 Python 3.11 中，我们可以结合多种参数来创建格式化的输出：\nprint(\u0026#34;=\u0026#34; * 50) # 使用乘法运算符重复字符串 print(\u0026#34; Python 课程表\u0026#34;) print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;周一\u0026#34;, \u0026#34;Python 基础\u0026#34;, sep=\u0026#34;：\u0026#34;) print(\u0026#34;周二\u0026#34;, \u0026#34;变量与数据类型\u0026#34;, sep=\u0026#34;：\u0026#34;) print(\u0026#34;周三\u0026#34;, \u0026#34;运算符与表达式\u0026#34;, sep=\u0026#34;：\u0026#34;) print(\u0026#34;=\u0026#34; * 50) 输出：\n================================================== Python 课程表 ================================================== 周一：Python 基础 周二：变量与数据类型 周三：运算符与表达式 ==================================================Python 代码的运行方式 方式一：交互式解释器 Python 自带一个交互式解释器（Interactive Interpreter），你可以在终端中输入 python3 或 python 来启动它。在交互式模式下，你可以逐行输入代码并立即看到结果：\n$ python3 Python 3.11.0 (main, Oct 24 2022, 18:15:42) [GCC 11.2.0] on linux Type \u0026#34;help\u0026#34;, \u0026#34;copyright\u0026#34;, \u0026#34;credits\u0026#34; or \u0026#34;license\u0026#34; for more information. \u0026gt;\u0026gt;\u0026gt; print(\u0026#34;Hello, World!\u0026#34;) Hello, World! \u0026gt;\u0026gt;\u0026gt;交互式解释器非常适合快速测试一些短小的代码片段，以及学习 Python 的各种功能。当你输入一个表达式时，Python 会立即计算并显示结果：\n\u0026gt;\u0026gt;\u0026gt; 2 + 3 5 \u0026gt;\u0026gt;\u0026gt; 10 / 3 3.3333333333333335 \u0026gt;\u0026gt;\u0026gt; \u0026#34;Hello\u0026#34; + \u0026#34; \u0026#34; + \u0026#34;Python\u0026#34; \u0026#39;Hello Python\u0026#39; 方式二：脚本文件 将代码保存为 .py 文件，然后用 Python 解释器执行，这是实际开发中的主要方式：\n$ python3 hello.py 假设 hello.py 文件内容为：\n# hello.py - 第一个 Python 脚本 print(\u0026#34;你好，Python 世界！\u0026#34;) print(\u0026#34;欢迎来到 Python 3.11 课程\u0026#34;) Python 3.11 的 -m 运行模式 Python 3.11 还支持通过模块方式运行脚本：\n$ python3 -m hello 这种方式会自动设置模块搜索路径，在大型项目中非常有用。\n代码注释的艺术 注释（Comments）是代码中不会被 Python 解释器执行的文本，用于向人类读者解释代码的含义和意图。编写良好的注释是写出高质量代码的重要部分。Python 中的注释以井号 # 开头，直到该行末尾为止。\n单行注释 单行注释是最常见的注释形式，用于解释一行或一小段代码的功能：\n# 这是一个注释，解释下面的代码 x = 10 # 这是一个行内注释 # 计算圆的面积 radius = 5 area = 3.14159 * radius ** 2 # 圆面积 = π × r² print(f\u0026#34;半径为 {radius} 的圆面积为：{area}\u0026#34;) 注释应该解释\u0026quot;为什么\u0026quot;而不是\u0026quot;是什么\u0026quot;。例如，下面是一个不好的注释和一个好的注释：\n# 不好的注释：只是重复了代码 x = x + 1 # 将 x 加 1 # 好的注释：解释了代码的目的 x = x + 1 # 跳过已处理的用户 多行注释（块注释） 虽然 Python 没有专门的多行注释语法，但我们可以使用多个连续的单行注释来实现多行注释的效果：\n# ============================================================ # 这是一个复杂算法的说明 # 1. 首先对输入数据进行预处理 # 2. 然后应用核心算法 # 3. 最后进行结果后处理 # ============================================================ 文档字符串（Docstring） 在 Python 中，还有一类特殊的注释被称为文档字符串（Documentation String），简称 Docstring。文档字符串使用三引号 \u0026quot;\u0026quot;\u0026quot;...\u0026quot;\u0026quot;\u0026quot; 或 '''...''' 包围，可以出现在模块、函数、类或方法的开头。文档字符串不仅是一段说明文字，还可以通过 __doc__ 属性和 help() 函数访问：\ndef greet(name): \u0026#34;\u0026#34;\u0026#34; 向指定名字的人打招呼。 参数: name (str): 人的名字 返回: str: 问候语 \u0026#34;\u0026#34;\u0026#34; return f\u0026#34;你好，{name}！欢迎学习 Python。\u0026#34; 在 Python 交互式解释器中：\n\u0026gt;\u0026gt;\u0026gt; help(greet) Help on function greet in module __main__: greet(name) 向指定名字的人打招呼。 参数: name (str): 人的名字 返回: str: 问候语 \u0026gt;\u0026gt;\u0026gt; print(greet.__doc__) 向指定名字的人打招呼。 参数: name (str): 人的名字 返回: str: 问候语 注释的实用技巧 以下是一些编写注释的最佳实践：\n# 1. 使用 TODO 注释标记待办事项 # TODO: 添加输入验证 def process_data(data): pass # 2. 使用 FIXME 注释标记已知问题 # FIXME: 这个函数在某些边界情况下会崩溃 def calculate(x): return 10 / x # 3. 使用 NOTE 注释提供额外说明 # NOTE: 这个算法的时间复杂度为 O(n) def find_max(numbers): max_val = numbers[0] for num in numbers: if num \u0026gt; max_val: max_val = num return max_val f-string：现代 Python 格式化字符串 f-string 是 Python 3.6 引入的一种全新的字符串格式化方式，全称为\u0026quot;formatted string literal\u0026quot;（格式化字符串字面量）。相比传统的 % 格式化方式和 str.format() 方法，f-string 更加简洁、直观和易读。在 Python 3.11 中，f-string 的功能得到了进一步增强。\nf-string 的基本语法 f-string 的基本形式是在字符串字面量前加上字母 f 或 F，然后在字符串内部使用大括号 {} 包裹需要插入的表达式或变量：\nname = \u0026#34;张三\u0026#34; age = 25 height = 1.75 # 使用 f-string 格式化字符串 print(f\u0026#34;姓名：{name}\u0026#34;) print(f\u0026#34;年龄：{age}\u0026#34;) print(f\u0026#34;身高：{height} 米\u0026#34;) 输出：\n姓名：张三 年龄：25 身高：1.75 米在大括号中使用表达式 f-string 的大括号 {} 中不仅可以放置变量名，还可以放置任意的 Python 表达式：\na = 10 b = 20 # 在 f-string 中直接进行计算 print(f\u0026#34;{a} + {b} = {a + b}\u0026#34;) print(f\u0026#34;{a} × {b} = {a * b}\u0026#34;) print(f\u0026#34;{a} 的 {b}% 是 {a * b / 100}\u0026#34;) # 使用函数调用 words = [\u0026#34;Python\u0026#34;, \u0026#34;是\u0026#34;, \u0026#34;一门\u0026#34;, \u0026#34;很棒\u0026#34;, \u0026#34;的\u0026#34;, \u0026#34;语言\u0026#34;] sentence = f\u0026#34;结论：{\u0026#39; \u0026#39;.join(words)}\u0026#34; print(sentence) 输出：\n10 \u0026#43; 20 = 30 10 × 20 = 200 10 的 20% 是 2.0 结论：Python 是一门很棒的语言f-string 中的类型转换与格式化 f-string 支持类似于 str.format() 的格式化规格（Format Specifier），使用冒号 : 分隔变量名和格式化规格：\nimport math # 保留小数位数 pi = math.pi print(f\u0026#34;π 保留两位小数：{pi:.2f}\u0026#34;) print(f\u0026#34;π 保留四位小数：{pi:.4f}\u0026#34;) # 千位分隔符与精度控制 big_number = 1234567.89 print(f\u0026#34;大数字带千位分隔符：{big_number:,.2f}\u0026#34;) # 百分数格式化 ratio = 0.256 print(f\u0026#34;转换为百分比：{ratio:.1%}\u0026#34;) # 指数记数法 large_num = 123456789 print(f\u0026#34;使用科学计数法：{large_num:.2e}\u0026#34;) # 进制转换（这是 Python 3.11 的增强特性） print(f\u0026#34;十进制 255 转换为十六进制：{255:08X}\u0026#34;) # 08X 表示宽度8，不足补0，大写十六进制 print(f\u0026#34;十进制 255 转换为二进制：{255:016b}\u0026#34;) # 016b 表示宽度16，不足补0，二进制 f-string 的对齐与填充 f-string 还支持强大的文本对齐和填充功能：\n# 左对齐、右对齐、居中对齐 text = \u0026#34;Python\u0026#34; print(f\u0026#34;|{text:\u0026lt;10}|\u0026#34;) # 左对齐，宽度10 print(f\u0026#34;|{text:\u0026gt;10}|\u0026#34;) # 右对齐，宽度10 print(f\u0026#34;|{text:^10}|\u0026#34;) # 居中对齐，宽度10 # 使用特定字符填充 print(f\u0026#34;|{text:*\u0026lt;10}|\u0026#34;) # 左对齐，用 * 填充 print(f\u0026#34;|{text:#\u0026gt;10}|\u0026#34;) # 右对齐，用 # 填充 print(f\u0026#34;|{text:-^10}|\u0026#34;) # 居中对齐，用 - 填充 # 制作表格 print(\u0026#34;-\u0026#34; * 37) print(f\u0026#34;|{\u0026#39;姓名\u0026#39;:^10}|{\u0026#39;年龄\u0026#39;:^8}|{\u0026#39;城市\u0026#39;:^12}|\u0026#34;) print(\u0026#34;-\u0026#34; * 37) print(f\u0026#34;|{\u0026#39;张三\u0026#39;:^10}|{28:^8}|{\u0026#39;北京\u0026#39;:^12}|\u0026#34;) print(f\u0026#34;|{\u0026#39;李四\u0026#39;:^10}|{35:^8}|{\u0026#39;上海\u0026#39;:^12}|\u0026#34;) print(f\u0026#34;|{\u0026#39;王五\u0026#39;:^10}|{42:^8}|{\u0026#39;深圳\u0026#39;:^12}|\u0026#34;) print(\u0026#34;-\u0026#34; * 37) Python 3.11 中 f-string 的增强特性 Python 3.11 对 f-string 进行了一些重要的增强：\n1. 支持自文档表达式（调试友好）：\nx = 42 # Python 3.11 中，可以在 f-string 中使用 = 来同时显示变量名和值 print(f\u0026#34;{x=}\u0026#34;) # 输出：x=42 name = \u0026#34;Alice\u0026#34; print(f\u0026#34;{name=}, {len(name)=}\u0026#34;) # 输出：name=\u0026#39;Alice\u0026#39;, len(name)=5 2. 支持反斜杠转义：\n虽然 Python 3.11 之前的版本不允许在 f-string 的表达式中使用直接的反斜杠，但在 Python 3.11 中我们可以通过在表达式外使用来处理：\n# 使用字典来组织转义序列 escape_sequences = { \u0026#34;newline\u0026#34;: \u0026#34;\\n\u0026#34;, \u0026#34;tab\u0026#34;: \u0026#34;\\t\u0026#34;, \u0026#34;quote\u0026#34;: \u0026#34;\\\u0026#34;\u0026#34; } print(f\u0026#34;换行符的 ASCII 码：{ord(escape_sequences[\u0026#39;newline\u0026#39;])}\u0026#34;) 3. 嵌套 f-string：\nfor width in [5, 10, 15]: print(f\u0026#34;{\u0026#39;#\u0026#39;:*{width}}\u0026#34;) # 输出：#####, ##########, ############### f-string 与其他格式化方式的对比 为了让你更好地理解 f-string 的优势，这里做一个全面的对比：\nname = \u0026#34;小明\u0026#34; score = 95.678 # 方式一：% 格式化（旧式） print(\u0026#34;姓名：%s，成绩：%.1f\u0026#34; % (name, score)) # 方式二：str.format() 方法 print(\u0026#34;姓名：{}，成绩：{:.1f}\u0026#34;.format(name, score)) print(\u0026#34;姓名：{0}，成绩：{1:.1f}\u0026#34;.format(name, score)) print(\u0026#34;姓名：{n}，成绩：{s:.1f}\u0026#34;.format(n=name, s=score)) # 方式三：f-string（现代推荐方式） print(f\u0026#34;姓名：{name}，成绩：{score:.1f}\u0026#34;) 三种方式的输出完全相同，但 f-string 显然是最简洁、最易读的。\n综合练习题 练习一：个人介绍卡 使用 print() 函数和 f-string 编写一个程序，输出你的个人介绍卡：\n# 个人介绍卡 name = \u0026#34;你的名字\u0026#34; age = 18 city = \u0026#34;你的城市\u0026#34; hobby = \u0026#34;你的爱好\u0026#34; print(\u0026#34;=\u0026#34; * 40) print(f\u0026#34; 个 人 介 绍 卡\u0026#34;) print(\u0026#34;=\u0026#34; * 40) print(f\u0026#34;姓名：{name}\u0026#34;) print(f\u0026#34;年龄：{age} 岁\u0026#34;) print(f\u0026#34;城市：{city}\u0026#34;) print(f\u0026#34;爱好：{hobby}\u0026#34;) print(\u0026#34;=\u0026#34; * 40) 练习二：数学计算展示 编写程序展示数学计算过程和结果：\na = 8 b = 3 print(\u0026#34;=\u0026#34; * 35) print(f\u0026#34; 数学计算演示 (Python 3.11)\u0026#34;) print(\u0026#34;=\u0026#34; * 35) print(f\u0026#34;a = {a}, b = {b}\u0026#34;) print(\u0026#34;-\u0026#34; * 35) print(f\u0026#34;加法： a + b = {a} + {b} = {a + b}\u0026#34;) print(f\u0026#34;减法： a - b = {a} - {b} = {a - b}\u0026#34;) print(f\u0026#34;乘法： a × b = {a} × {b} = {a * b}\u0026#34;) print(f\u0026#34;除法： a ÷ b = {a} ÷ {b} = {a / b:.4f}\u0026#34;) print(f\u0026#34;整除： a // b = {a} // {b} = {a // b}\u0026#34;) print(f\u0026#34;取余： a % b = {a} % {b} = {a % b}\u0026#34;) print(f\u0026#34;幂运算： a ** b = {a} ** {b} = {a ** b}\u0026#34;) print(\u0026#34;=\u0026#34; * 35) 练习三：使用注释编写程序文档 \u0026#34;\u0026#34;\u0026#34; 课程：Python 基础第一课 功能：演示 print()、注释和 f-string 的用法 版本：Python 3.11 \u0026#34;\u0026#34;\u0026#34; # 定义常量 COURSE_NAME = \u0026#34;Python 编程入门\u0026#34; LESSON_NUMBER = 1 # 定义变量 topics = [\u0026#34;print() 函数\u0026#34;, \u0026#34;代码注释\u0026#34;, \u0026#34;f-string 格式化\u0026#34;] duration_minutes = 90 # 输出课程信息 print(f\u0026#34;课程名称：{COURSE_NAME}\u0026#34;) print(f\u0026#34;课时：第 {LESSON_NUMBER} 课\u0026#34;) print(f\u0026#34;预计时长：{duration_minutes} 分钟\u0026#34;) print(\u0026#34;-\u0026#34; * 40) print(\u0026#34;本课主题：\u0026#34;) for i, topic in enumerate(topics, 1): print(f\u0026#34; {i}. {topic}\u0026#34;) 常见错误与调试 错误一：SyntaxError（语法错误） 如果你的代码有语法错误，Python 会报 SyntaxError。来看几个常见的例子：\n# 错误：字符串没有关闭引号 print(\u0026#34;你好) # SyntaxError: EOL while scanning string literal # 错误：括号不匹配 print(\u0026#34;Hello\u0026#34; # SyntaxError: unexpected EOF while parsing # 错误：使用了中文标点符号 print（\u0026#34;你好\u0026#34;） # SyntaxError: invalid character \u0026#39;（\u0026#39; 错误二：NameError（名称错误） # 错误：变量未定义就使用 print(message) # NameError: name \u0026#39;message\u0026#39; is not defined 错误三：TypeError（类型错误） # 错误：数据类型不支持某种操作 print(\u0026#34;年龄：\u0026#34; + 25) # TypeError: can only concatenate str (not \u0026#34;int\u0026#34;) to \u0026#34;str\u0026#34; 正确的方式是使用 f-string 或类型转换：\nprint(f\u0026#34;年龄：{25}\u0026#34;) # 方式一：使用 f-string print(\u0026#34;年龄：\u0026#34; + str(25)) # 方式二：使用 str() 转换 Python 3.11 小技巧 1. 使用 python3 -v 查看版本信息 $ python3 -v Python 3.11.0 (main, Oct 24 2022, 18:15:42) [GCC 11.2.0] 2. 使用 -X dev 选项开启开发模式 $ python3 -X dev script.py 开发模式会开启额外的运行时检查，如资源泄漏警告等。\n3. 使用 -b 选项避免字节字符串警告 $ python3 -b script.py 本章小结 今天我们学习了 Python 编程的第一步，包括：\nprint() 函数：Python 中用于输出信息的基本函数，支持多种参数如 sep 和 end。 代码注释：使用 # 创建单行注释，使用三引号 \u0026quot;\u0026quot;\u0026quot;...\u0026quot;\u0026quot;\u0026quot; 创建文档字符串。 f-string：Python 3.6 引入的现代字符串格式化方式，在 Python 3.11 中功能更加丰富。 Python 3.11 的新特性：更快的执行速度、更好的错误提示、f-string 调试表达式等。 通过今天的练习，你应该已经能够编写简单的 Python 程序来输出信息和格式化文本了。下一节课我们将学习 Python 中的变量、数据类型以及类型转换，敬请期待！\n延伸阅读 Python Official Documentation PEP 498 - Literal String Interpolation (f-strings) What\u0026rsquo;s New In Python 3.11 Python 3.11 Release Notes ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-01-py-basics-hello/","summary":"\u003ch1 id=\"python-基础第一课你好世界\"\u003ePython 基础第一课：你好世界\u003c/h1\u003e\n\u003ch2 id=\"课程概述\"\u003e课程概述\u003c/h2\u003e\n\u003cp\u003e欢迎来到 Python 编程系列课程的第一天！本节课我们将一起踏入 Python 编程的精彩世界。今天的学习内容包括：Python 语言简介、安装与运行环境、print() 函数的标准输出、代码注释的写法，以及现代 Python 中最常用的 f-string（格式化字符串字面量）。本课程内容基于 \u003cstrong\u003ePython 3.11\u003c/strong\u003e 编写，涵盖了 Python 3.11 中引入的最新语法特性与最佳实践。无论你是完全没有编程经验的初学者，还是从其他语言转来的开发者，本课程都将帮助你建立扎实的基础。\u003c/p\u003e\n\u003cp\u003ePython 由荷兰程序员 Guido van Rossum 于 1991 年首次发布，至今已有超过 30 年的发展历史。Python 的设计哲学强调代码的可读性和简洁性，其核心原则之一就是\u0026quot;Readability counts\u0026quot;（可读性很重要）。Python 使用缩进（indentation）来划分代码块，而不是像许多其他语言那样使用大括号 \u003ccode\u003e{}\u003c/code\u003e 或 \u003ccode\u003ebegin/end\u003c/code\u003e 关键字。这种独特的设计使得 Python 代码在视觉上非常清晰，也强制开发者写出格式良好的代码。Python 的另一条著名的设计原则是\u0026quot;Simple is better than complex\u0026quot;（简单优于复杂），这使得 Python 成为最适合初学者入门的编程语言之一。\u003c/p\u003e\n\u003ch2 id=\"python-311-的新特性\"\u003ePython 3.11 的新特性\u003c/h2\u003e\n\u003cp\u003e在学习基础知识之前，我们有必要了解一下 Python 3.11 相比之前版本带来了哪些重要改进。Python 3.11 于 2022 年 10 月正式发布，被誉为\u0026quot;Python 史上最快的版本\u0026quot;，其解释器启动速度比 Python 3.10 快了 10-15%，而平均执行速度更是提升了 25%。这些性能的提升主要来自于对 Python 虚拟机（Virtual Machine）的深度优化和重构。Python 3.11 还引入了更为精确的错误提示信息（Better Error Messages），当程序出现异常时，Python 3.11 会显示更多上下文信息，帮助开发者更快地定位和修复问题。\u003c/p\u003e","tags":"Python, 编程","title":"Python 基础第一课：你好世界"},{"columns":"acp-course","content":" 来源：Notion ACP学习笔记 + 阿里云开发者社区 + 网络资料整理\n一、详细讲解 1.1 云计算的定义 云计算（Cloud Computing）是一种通过网络统一管理和调度的计算、存储、软件等资源，形成一个资源池，用户按需使用、按量付费的计算模式。\n核心特征：\n按需自助服务：用户无需人工干预即可获取资源 泛在网络接入：通过标准网络随时随地访问 资源池化：物理资源被抽象为池化资源池 快速弹性伸缩：资源可快速扩缩容 按使用量付费：用多少付多少，无浪费 1.2 三种服务模型（重点） 模型 全称 用户管理层次 阿里云产品举例 IaaS Infrastructure as a Service 基础设施（网络/存储/服务器） 云服务器ECS、块存储、vSwitch PaaS Platform as a Service 操作系统以上，中间件以上 数据库RDS、对象存储OSS、容器服务ACK SaaS Software as a Service 直接使用应用 钉钉、云效、DataV 考试口诀：\nIaaS = 你管啥都要管（除了机房硬件） PaaS = 你只管应用和数据（平台全管） SaaS = 你只用（啥都不用管） 阿里云各层典型产品：\nIaaS： ECS / ECS Bare Metal / 弹性裸金属 PaaS： RDS / OSS / ACK / 函数计算FC / API网关 SaaS： 钉钉 / 云效 / 瓴山羊1.3 四种部署模型 部署模型 说明 适用场景 公有云 第三方提供，多租户共享 中小企业、创业公司 私有云 企业自建，独占资源 金融、政府、大型企业的核心系统 社区云 多个组织共享建设的云 行业联盟、区域联盟 混合云 公有云 + 私有云组合 核心数据留私有云，业务弹性用公有云 1.4 阿里云全球化基础设施 阿里云在全球 28 个地域（Region）运营，拥有 86 个可用区（Zone）。\n地域（Region）：数据中心所在的地理区域，如华东1（杭州）、华北2（北京）、新加坡、美西等 可用区（Zone）：同一地域内电力和网络互相独立的物理区域，可用区内延迟 \u0026lt; 2ms 边缘节点（Edge）：CDN 缓存节点，靠近用户，降低访问延迟 1.5 云计算的关键技术 虚拟化技术：将物理资源抽象成多个虚拟资源（CPU、内存、存储、网络） 容器技术：轻量级虚拟化，进程级隔离（Docker、ACK） 分布式存储：数据多副本冗余，保证可靠性（OSS 三副本） 多租户架构：同一资源池供多个用户/组织使用，通过权限隔离 自动化运维：API 驱动资源管理，运维自动化 1.6 按需付费模式 包年包月：适合长期稳定资源，有折扣 按量付费：按小时/秒计费，适合短期或波动性负载 抢占实例：成本最低 90%，适合无状态可中断任务 资源预留：承诺使用一定时长，享折扣优惠 二、背诵版（Night Before Exam） 云计算三模式 IaaS 管机房、PaaS 管平台、SaaS 管应用\nIaaS：ECS、块存储、VPC、vSwitch → 你管虚拟服务器 PaaS：RDS、OSS、ACK、FC → 你管应用和数据 SaaS：钉钉、云效 → 你只管用 云计算五特征 按需自服务、泛在网络接入、资源池化、快速弹性伸缩、按量付费\n部署模型 公、私、社、混 = 公有云、私有云、社区云、混合云\n阿里云地域可用区 Region = 地域（城市级）、Zone = 可用区（区域级）、同地域可用区之间网络延迟 \u0026lt; 2ms\n关键技术 虚拟化（底层）、容器（中间层）、分布式存储（数据层）、多租户（安全层）\n三、速记版（考前 5 分钟回忆） ✅ 云计算 = 网络 \u0026#43; 资源池 \u0026#43; 按需 \u0026#43; 按量付费 ✅ IaaS = 卖虚拟机（阿里云 ECS） ✅ PaaS = 卖平台服务（阿里云 RDS、OSS） ✅ SaaS = 卖软件（阿里云 钉钉） ✅ 公有云 = 多租户共享 ✅ 私有云 = 企业独占 ✅ 混合云 = 核心私有 \u0026#43; 弹性公有 ✅ 阿里云 Region = 地域，Zone = 可用区 ✅ 可用区之间延迟 \u0026lt; 2ms ✅ 阿里云全球 28 地域 / 86 可用区 四、测试练习题 单选题 1. 以下哪种服务模型下，用户需要管理操作系统和应用程序？\nA. IaaS ✅ B. PaaS C. SaaS D. FaaS 答案：A\n解析：IaaS 提供虚拟机，用户需要自行安装操作系统、配置应用。PaaS 提供运行时，用户只需部署代码。SaaS 直接提供完整应用。\n2. 阿里云的云服务器 ECS 属于云计算服务模型中的哪一种？\nA. SaaS B. PaaS C. IaaS ✅ D. 私有云 答案：C\n解析：ECS 是基础设施层服务，属于典型的 IaaS。\n3. 关于公有云和私有云的描述，错误的是？\nA. 公有云由第三方运营，多租户共享 B. 私有云为企业独占使用 C. 公有云比私有云更安全 D. 混合云结合两者优势 答案：C\n解析：安全性取决于具体配置，不能简单说公有云更安全。私有云在合规和数据控制方面反而更有优势。\n4. 阿里云中，同一地域的不同可用区之间，网络延迟一般控制在多少以内？\nA. 5ms B. 10ms C. 2ms ✅ D. 20ms 答案：C\n解析：同地域可用区之间网络延迟 \u0026lt; 2ms。\n5. 以下哪个不是云计算的关键特征？\nA. 资源池化 B. 快速弹性 C. 固定计费 D. 按需自助 答案：C\n解析：云计算是按使用量付费，不是固定计费。\n多选题 6. 云计算的三种服务模型包括？\nA. IaaS ✅ B. PaaS ✅ C. SaaS ✅ D. FaaS 答案：A、B、C\n解析：FaaS（函数即服务）是 PaaS 的一种细分，不属于三大基础模型。\n7. 阿里云的基础设施包括？\nA. Region（地域）✅ B. Zone（可用区）✅ C. Edge（边缘节点）✅ D. VPC（私有网络） 答案：A、B、C\n解析：VPC 是网络产品，不是基础设施地理概念。\n判断题 8. 混合云中，核心业务数据必须放在公有云上。\nA. 正确 B. 错误 ✅ 答案：B\n解析：混合云中核心数据通常放在私有云，公有云放弹性业务。\n9. 包年包月的计费方式适合有长期稳定资源需求的场景。\nA. 正确 ✅ B. 错误 答案：A\n解析：包年包月有折扣，适合长期稳定使用。\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-01-day1-%E4%BA%91%E8%AE%A1%E7%AE%97%E6%A6%82%E8%BF%B0/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：Notion ACP学习笔记 + 阿里云开发者社区 + 网络资料整理\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-云计算的定义\"\u003e1.1 云计算的定义\u003c/h3\u003e\n\u003cp\u003e云计算（Cloud Computing）是一种通过网络统一管理和调度的计算、存储、软件等资源，形成一个资源池，用户按需使用、按量付费的计算模式。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e核心特征\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e按需自助服务\u003c/strong\u003e：用户无需人工干预即可获取资源\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e泛在网络接入\u003c/strong\u003e：通过标准网络随时随地访问\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e资源池化\u003c/strong\u003e：物理资源被抽象为池化资源池\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e快速弹性伸缩\u003c/strong\u003e：资源可快速扩缩容\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e按使用量付费\u003c/strong\u003e：用多少付多少，无浪费\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"12-三种服务模型重点\"\u003e1.2 三种服务模型（重点）\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e模型\u003c/th\u003e\n          \u003cth\u003e全称\u003c/th\u003e\n          \u003cth\u003e用户管理层次\u003c/th\u003e\n          \u003cth\u003e阿里云产品举例\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eIaaS\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eInfrastructure as a Service\u003c/td\u003e\n          \u003ctd\u003e基础设施（网络/存储/服务器）\u003c/td\u003e\n          \u003ctd\u003e云服务器ECS、块存储、vSwitch\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePaaS\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003ePlatform as a Service\u003c/td\u003e\n          \u003ctd\u003e操作系统以上，中间件以上\u003c/td\u003e\n          \u003ctd\u003e数据库RDS、对象存储OSS、容器服务ACK\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eSaaS\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eSoftware as a Service\u003c/td\u003e\n          \u003ctd\u003e直接使用应用\u003c/td\u003e\n          \u003ctd\u003e钉钉、云效、DataV\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cstrong\u003e考试口诀\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eIaaS = 你管啥都要管（除了机房硬件）\u003c/li\u003e\n\u003cli\u003ePaaS = 你只管应用和数据（平台全管）\u003c/li\u003e\n\u003cli\u003eSaaS = 你只用（啥都不用管）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e阿里云各层典型产品\u003c/strong\u003e：\u003c/p\u003e\nIaaS： ECS / ECS Bare Metal / 弹性裸金属\nPaaS： RDS / OSS / ACK / 函数计算FC / API网关\nSaaS： 钉钉 / 云效 / 瓴山羊\u003ch3 id=\"13-四种部署模型\"\u003e1.3 四种部署模型\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e部署模型\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n          \u003cth\u003e适用场景\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e公有云\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e第三方提供，多租户共享\u003c/td\u003e\n          \u003ctd\u003e中小企业、创业公司\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e私有云\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e企业自建，独占资源\u003c/td\u003e\n          \u003ctd\u003e金融、政府、大型企业的核心系统\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e社区云\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e多个组织共享建设的云\u003c/td\u003e\n          \u003ctd\u003e行业联盟、区域联盟\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e混合云\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e公有云 + 私有云组合\u003c/td\u003e\n          \u003ctd\u003e核心数据留私有云，业务弹性用公有云\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"14-阿里云全球化基础设施\"\u003e1.4 阿里云全球化基础设施\u003c/h3\u003e\n\u003cp\u003e阿里云在全球 28 个地域（Region）运营，拥有 86 个可用区（Zone）。\u003c/p\u003e","tags":"ACP, 阿里云, 云计算","title":"Day1 云计算概述"},{"columns":"python-course","content":"Python 第二课：变量、数据类型与类型转换 课程概述 本节课我们将深入学习 Python 编程中最核心的概念之一——变量（Variables）。变量是存储数据的容器，是所有程序的基础构建块。我们还将全面介绍 Python 的内置数据类型（Built-in Data Types），包括整数（int）、浮点数（float）、字符串（str）、布尔值（bool）、列表（list）、元组（tuple）、字典（dict）和集合（set）。此外，我们还将学习 Python 中的类型转换（Type Conversion）和 f-string 高级格式化技巧。本课程所有内容基于 Python 3.11 标准，涵盖了 Python 3.11 中关于类型系统的新特性和改进。Python 是一门动态类型语言（dynamically typed language），这意味着变量不需要显式声明类型，Python 解释器会根据赋给变量的值自动推断类型。但与此同时，Python 也是一门强类型语言（strongly typed language），不同类型的数据不能随意进行混合运算，必须通过显式的类型转换来实现。\n变量详解 变量的基本概念 在 Python 中，变量是用于存储数据值的容器。你可以形象地将变量想象为一个贴有标签的盒子，盒子里存放着数据，而标签就是变量的名字。每次给变量赋值时，变量就会指向新的数据对象。\n# 变量的基本赋值 name = \u0026#34;张三\u0026#34; # 字符串变量 age = 25 # 整数变量 height = 1.75 # 浮点数变量 is_student = True # 布尔变量 print(f\u0026#34;姓名：{name}\u0026#34;) print(f\u0026#34;年龄：{age}\u0026#34;) print(f\u0026#34;身高：{height} 米\u0026#34;) print(f\u0026#34;是否学生：{is_student}\u0026#34;) 输出：\n姓名：张三 年龄：25 身高：1.75 米 是否学生：True变量的命名规则 Python 中的变量名必须遵守以下规则：\n变量名只能包含字母、数字和下划线（_），不能包含空格或特殊字符。 变量名不能以数字开头。 变量名不能使用 Python 的保留关键字（keywords）。 变量名区分大小写（name 和 Name 是两个不同的变量）。 # 合法的变量名 my_variable = 10 _private_data = \u0026#34;secret\u0026#34; camelCase = \u0026#34;驼峰命名\u0026#34; CONSTANT_VALUE = 100 # 常量习惯用全大写 # Python 3.11 中还可以使用 Unicode 字符作为变量名 姓名 = \u0026#34;李四\u0026#34; π = 3.14159 # 不合法的变量名（会导致 SyntaxError） # 2nd_value = 20 # 不能以数字开头 # my-var = 30 # 不能使用连字符 # class = \u0026#34;高级\u0026#34; # 不能使用保留关键字 Python 保留关键字 以下是 Python 3.11 中的所有保留关键字（35个），你不能将它们作为变量名使用：\nFalse None True and as assert async await break class continue def del elif else except finally for from global if import in is lambda nonlocal not or pass raise return try while with yield你可以通过以下代码查看当前的保留关键字列表：\nimport keyword print(keyword.kwlist) print(f\u0026#34;Python 3.11 共有 {len(keyword.kwlist)} 个保留关键字\u0026#34;) 变量的多重赋值 Python 支持同时给多个变量赋相同的值，也支持交换两个变量的值：\n# 多个变量赋相同值 x = y = z = 0 print(f\u0026#34;x={x}, y={y}, z={z}\u0026#34;) # 多个变量赋不同的值（解包赋值） a, b, c = 1, 2, 3 print(f\u0026#34;a={a}, b={b}, c={c}\u0026#34;) # 变量值交换（Pythonic 方式，无需临时变量） p, q = 10, 20 p, q = q, p # 交换 p 和 q 的值 print(f\u0026#34;交换后：p={p}, q={q}\u0026#34;) 变量的内存管理 Python 使用引用计数（reference counting）和垃圾回收（garbage collection）机制来管理内存。当你给变量赋一个新值时，Python 会先创建新的对象，然后让变量指向新对象，不再被引用的旧对象会被垃圾回收器自动回收：\na = [1, 2, 3] # 创建列表对象 [1,2,3]，a 指向它 b = a # b 也指向同一个列表对象 print(f\u0026#34;a 的 id：{id(a)}\u0026#34;) print(f\u0026#34;b 的 id：{id(b)}\u0026#34;) print(f\u0026#34;a is b：{a is b}\u0026#34;) # True，它们是同一个对象 c = a[:] # 创建列表的副本 print(f\u0026#34;c 的 id：{id(c)}\u0026#34;) print(f\u0026#34;a is c：{a is c}\u0026#34;) # False，它们是不同的对象 Python 内置数据类型详解 整数类型（int） 整数是 Python 中最基本的数据类型，用于表示没有小数部分的数值。Python 3 中的整数没有大小限制（受限于可用内存）。Python 3.11 对整数的处理做了多项优化，使得大整数的运算更加高效。\n# 整数的各种进制表示 decimal = 42 # 十进制（默认） binary = 0b101010 # 二进制，以 0b 开头 octal = 0o52 # 八进制，以 0o 开头 hexadecimal = 0x2A # 十六进制，以 0x 开头 print(f\u0026#34;十进制：{decimal}\u0026#34;) print(f\u0026#34;二进制：{binary}\u0026#34;) print(f\u0026#34;八进制：{octal}\u0026#34;) print(f\u0026#34;十六进制：{hexadecimal}\u0026#34;) print(f\u0026#34;二进制 101010 = {binary}\u0026#34;) # Python 会自动转换显示 # 进制转换函数 print(f\u0026#34;十进制 42 转二进制：{bin(42)}\u0026#34;) print(f\u0026#34;十进制 42 转八进制：{oct(42)}\u0026#34;) print(f\u0026#34;十进制 42 转十六进制：{hex(42)}\u0026#34;) # 整数计算 big_num = 10**100 # 10 的 100 次方 print(f\u0026#34;10 的 100 次方：{big_num}\u0026#34;) print(f\u0026#34;位数：{len(str(big_num))} 位\u0026#34;) 浮点数类型（float） 浮点数用于表示带小数部分的数值，基于 IEEE 754 双精度标准实现。Python 3.11 中的浮点数运算遵循 IEEE 754 标准，并且对一些常见的浮点数运算做了优化：\n# 浮点数的基本使用 price = 19.99 temperature = -5.5 scientific = 1.23e-5 # 科学计数法 print(f\u0026#34;价格：{price}\u0026#34;) print(f\u0026#34;温度：{temperature}°C\u0026#34;) print(f\u0026#34;科学计数：{scientific}\u0026#34;) # 浮点数的精度问题 a = 0.1 + 0.2 print(f\u0026#34;0.1 + 0.2 = {a}\u0026#34;) # 可能是 0.30000000000000004 print(f\u0026#34;精确比较：{a == 0.3}\u0026#34;) # False # 使用 math 模块处理精度问题 import math print(f\u0026#34;使用 math.isclose：{math.isclose(a, 0.3)}\u0026#34;) # True # Python 3.11 中浮点数的新表示方法 print(f\u0026#34;3.14 的类型：{type(3.14)}\u0026#34;) print(f\u0026#34;使用下划线分隔的大数字：{1_000_000.5}\u0026#34;) # 更易读 字符串类型（str） 字符串是 Python 中用于表示文本数据的数据类型。字符串是不可变的（immutable），这意味着一旦创建，就不能直接修改字符串的内容。Python 3.11 对字符串处理做了大量优化，UTF-8 编码成为默认编码，字符串操作的性能显著提升。\n# 字符串的创建 s1 = \u0026#39;单引号字符串\u0026#39; s2 = \u0026#34;双引号字符串\u0026#34; s3 = \u0026#34;\u0026#34;\u0026#34;多行字符串 可以跨越多行\u0026#34;\u0026#34;\u0026#34; s4 = \u0026#39;\u0026#39;\u0026#39;也可以使用 三个单引号\u0026#39;\u0026#39;\u0026#39; print(s3) print(s4) # 字符串的基本操作 text = \u0026#34;Hello, Python 3.11!\u0026#34; print(f\u0026#34;长度：{len(text)}\u0026#34;) print(f\u0026#34;首字母大写：{text.capitalize()}\u0026#34;) print(f\u0026#34;全部大写：{text.upper()}\u0026#34;) print(f\u0026#34;全部小写：{text.lower()}\u0026#34;) print(f\u0026#34;是否以 H 开头：{text.startswith(\u0026#39;H\u0026#39;)}\u0026#34;) print(f\u0026#34;是否以 ! 结尾：{text.endswith(\u0026#39;!\u0026#39;)}\u0026#34;) # 字符串的切片（Slice）操作 print(f\u0026#34;前5个字符：{text[:5]}\u0026#34;) # Hello print(f\u0026#34;第7到最后：{text[7:]}\u0026#34;) # Python 3.11! print(f\u0026#34;反转字符串：{text[::-1]}\u0026#34;) # !111.1 nohtyP ,olleH 布尔类型（bool） 布尔类型只有两个值：True（真）和 False（假）。在 Python 中，布尔类型是整数类型（int）的子类，True 等于整数 1，False 等于整数 0。这一特性在某些场景下非常有用：\n# 布尔值的基本使用 is_python_fun = True is_snake_dangerous = False print(f\u0026#34;Python 有趣吗？{is_python_fun}\u0026#34;) print(f\u0026#34;蛇危险吗？{is_snake_dangerous}\u0026#34;) # 布尔值与整数的转换 print(f\u0026#34;True 的整数值：{int(True)}\u0026#34;) print(f\u0026#34;False 的整数值：{int(False)}\u0026#34;) print(f\u0026#34;1 的布尔值：{bool(1)}\u0026#34;) print(f\u0026#34;0 的布尔值：{bool(0)}\u0026#34;) # 布尔值在条件判断中的应用 age = 20 is_adult = age \u0026gt;= 18 print(f\u0026#34;{age} 岁是否是成年人：{is_adult}\u0026#34;) # Python 3.11 中布尔运算的特点 print(f\u0026#34;True + True = {True + True}\u0026#34;) # 2 print(f\u0026#34;False + False = {False + False}\u0026#34;) # 0 列表类型（list） 列表是 Python 中最常用的可变序列（mutable sequence），可以存储任意类型的数据。列表使用方括号 [] 创建，元素之间用逗号分隔。列表是动态数组，支持索引、切片、添加、删除等操作。Python 3.11 对列表操作进行了多项优化，特别是列表的 sort() 方法在处理大规模数据时性能提升显著。\n# 列表的创建 fruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;, \u0026#34;葡萄\u0026#34;] numbers = [1, 2, 3, 4, 5] mixed = [1, \u0026#34;你好\u0026#34;, 3.14, True, None] empty = [] print(f\u0026#34;水果列表：{fruits}\u0026#34;) print(f\u0026#34;数字列表：{numbers}\u0026#34;) print(f\u0026#34;混合列表：{mixed}\u0026#34;) print(f\u0026#34;空列表：{empty}\u0026#34;) # 列表的索引和切片 print(f\u0026#34;第一个水果：{fruits[0]}\u0026#34;) print(f\u0026#34;最后一个水果：{fruits[-1]}\u0026#34;) print(f\u0026#34;前两个水果：{fruits[:2]}\u0026#34;) print(f\u0026#34;反序列表：{fruits[::-1]}\u0026#34;) # 列表的增删改查 fruits.append(\u0026#34;草莓\u0026#34;) # 在末尾添加元素 fruits.insert(1, \u0026#34;西瓜\u0026#34;) # 在指定位置插入元素 fruits.remove(\u0026#34;香蕉\u0026#34;) # 移除第一个匹配的元素 popped = fruits.pop() # 移除并返回末尾元素 print(f\u0026#34;修改后列表：{fruits}\u0026#34;) print(f\u0026#34;弹出的元素：{popped}\u0026#34;) 元组类型（tuple） 元组与列表非常相似，但元组是不可变的（immutable）。元组使用圆括号 () 创建（也可以不用括号）。由于元组不可变，它们通常用于存储不应该被修改的数据，如日期、坐标等。元组的不可变性也使得它们可以作为字典的键（dict keys）使用。\n# 元组的创建 point = (3, 4) dimensions = (1920, 1080) date = 2023, 12, 25 # 括号可以省略 single = (42,) # 单元素元组必须加逗号 print(f\u0026#34;坐标点：{point}\u0026#34;) print(f\u0026#34;分辨率：{dimensions}\u0026#34;) print(f\u0026#34;日期：{date}\u0026#34;) print(f\u0026#34;单个元素元组：{single}\u0026#34;) # 元组的解包（Unpacking） x, y = point print(f\u0026#34;解包：x={x}, y={y}\u0026#34;) # 使用解包交换变量 a, b = 1, 2 a, b = b, a print(f\u0026#34;交换后：a={a}, b={b}\u0026#34;) # 命名元组（Named Tuple）- Python 3.11 推荐用法 from collections import namedtuple Person = namedtuple(\u0026#39;Person\u0026#39;, [\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;, \u0026#39;city\u0026#39;]) p1 = Person(\u0026#34;张三\u0026#34;, 30, \u0026#34;北京\u0026#34;) print(f\u0026#34;命名元组：{p1.name}, {p1.age}, {p1.city}\u0026#34;) 字典类型（dict） 字典是 Python 中最强大的内置数据类型之一，用于存储键值对（key-value pairs）。字典使用大括号 {} 创建，键值对之间用冒号 : 分隔。字典的键必须是可哈希的（hashable），即不可变类型；值可以是任意类型。Python 3.11 对字典操作做了大量优化，内存使用效率提升了约 20-25%。\n# 字典的创建 student = { \u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 20, \u0026#34;major\u0026#34;: \u0026#34;计算机科学\u0026#34;, \u0026#34;gpa\u0026#34;: 3.8 } print(f\u0026#34;学生信息：{student}\u0026#34;) print(f\u0026#34;学生姓名：{student[\u0026#39;name\u0026#39;]}\u0026#34;) # 使用 dict() 构造函数创建字典 pairs = [(\u0026#34;a\u0026#34;, 1), (\u0026#34;b\u0026#34;, 2), (\u0026#34;c\u0026#34;, 3)] d = dict(pairs) print(f\u0026#34;从键值对列表创建：{d}\u0026#34;) # 使用关键字参数创建（Python 3.11 新特性，支持更简洁的语法） config = dict( host=\u0026#34;localhost\u0026#34;, port=8080, debug=True ) print(f\u0026#34;配置字典：{config}\u0026#34;) # 字典的方法 print(f\u0026#34;所有键：{list(student.keys())}\u0026#34;) print(f\u0026#34;所有值：{list(student.values())}\u0026#34;) print(f\u0026#34;所有键值对：{list(student.items())}\u0026#34;) print(f\u0026#34;是否存在 \u0026#39;name\u0026#39; 键：{\u0026#39;name\u0026#39; in student}\u0026#34;) 集合类型（set） 集合是无序的、不重复的元素集。集合使用大括号 {} 创建（但不同于字典，集合只有元素没有键值对）。集合的主要用途包括去重、成员测试和数学集合运算（交集、并集、差集等）。\n# 集合的创建 s1 = {1, 2, 3, 4, 5} s2 = {4, 5, 6, 7, 8} print(f\u0026#34;集合1：{s1}\u0026#34;) print(f\u0026#34;集合2：{s2}\u0026#34;) # 集合的去重功能 numbers_with_dup = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] unique_numbers = set(numbers_with_dup) print(f\u0026#34;去重：{unique_numbers}\u0026#34;) # 集合运算 print(f\u0026#34;交集：{s1 \u0026amp; s2}\u0026#34;) # {4, 5} print(f\u0026#34;并集：{s1 | s2}\u0026#34;) # {1, 2, 3, 4, 5, 6, 7, 8} print(f\u0026#34;差集：{s1 - s2}\u0026#34;) # {1, 2, 3} print(f\u0026#34;对称差集：{s1 ^ s2}\u0026#34;) # {1, 2, 3, 6, 7, 8} # Python 3.11 中集合的新方法 s1.add(10) # 添加元素 s1.discard(1) # 移除元素（不存在不报错） s1.remove(2) # 移除元素（不存在则 KeyError） print(f\u0026#34;添加 10 后：{s1}\u0026#34;) 类型转换详解 Python 是一门强类型语言，不同类型的数据不能直接混合运算。因此，我们需要显式地进行类型转换。\n隐式类型转换（自动转换） Python 在某些情况下会自动进行类型转换，例如在混合整数和浮点数的运算中：\n# 整数自动转换为浮点数 result = 10 + 3.14 print(f\u0026#34;10 + 3.14 = {result}\u0026#34;) print(f\u0026#34;结果类型：{type(result)}\u0026#34;) # \u0026lt;class \u0026#39;float\u0026#39;\u0026gt; # 布尔值自动转换为整数 result2 = True + 5 print(f\u0026#34;True + 5 = {result2}\u0026#34;) # 6 # 小整数复用（Python 3.11 的优化） a = 256 b = 256 print(f\u0026#34;256 is 256: {a is b}\u0026#34;) # True（Python 缓存了 -5 到 256 的整数） 显式类型转换（强制转换） Python 提供了多个内置函数来进行显式类型转换：\n# int() - 转换为整数 print(f\u0026#34;int(3.7) = {int(3.7)}\u0026#34;) # 3（截断，不是四舍五入） print(f\u0026#34;int(\u0026#39;42\u0026#39;) = {int(\u0026#39;42\u0026#39;)}\u0026#34;) # 42 print(f\u0026#34;int(\u0026#39;1010\u0026#39;, 2) = {int(\u0026#39;1010\u0026#39;, 2)}\u0026#34;) # 10（二进制转十进制） print(f\u0026#34;int(\u0026#39;FF\u0026#39;, 16) = {int(\u0026#39;FF\u0026#39;, 16)}\u0026#34;) # 255（十六进制转十进制） # float() - 转换为浮点数 print(f\u0026#34;float(10) = {float(10)}\u0026#34;) # 10.0 print(f\u0026#34;float(\u0026#39;3.14\u0026#39;) = {float(\u0026#39;3.14\u0026#39;)}\u0026#34;) # 3.14 print(f\u0026#34;float(\u0026#39;1e-5\u0026#39;) = {float(\u0026#39;1e-5\u0026#39;)}\u0026#34;) # 1e-05 # str() - 转换为字符串 print(f\u0026#34;str(42) = {str(42)}\u0026#34;) print(f\u0026#34;str(3.14) = {str(3.14)}\u0026#34;) print(f\u0026#34;str([1,2,3]) = {str([1,2,3])}\u0026#34;) # bool() - 转换为布尔值 print(f\u0026#34;bool(0) = {bool(0)}\u0026#34;) # False print(f\u0026#34;bool(1) = {bool(1)}\u0026#34;) # True print(f\u0026#34;bool(\u0026#39;\u0026#39;) = {bool(\u0026#39;\u0026#39;)}\u0026#34;) # False（空字符串） print(f\u0026#34;bool(\u0026#39; \u0026#39;) = {bool(\u0026#39; \u0026#39;)}\u0026#34;) # True（空格字符串） print(f\u0026#34;bool(None) = {bool(None)}\u0026#34;) # False print(f\u0026#34;bool([]) = {bool([])}\u0026#34;) # False（空列表） print(f\u0026#34;bool([0]) = {bool([0])}\u0026#34;) # True（非空列表） 列表、元组、集合之间的转换 # 各种序列类型之间的转换 original = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] to_tuple = tuple(original) print(f\u0026#34;列表转元组：{to_tuple}\u0026#34;) to_set = set(original) print(f\u0026#34;列表转集合（自动去重）：{to_set}\u0026#34;) to_list = list(to_set) print(f\u0026#34;集合转列表：{to_list}\u0026#34;) # 使用列表推导式进行复杂转换 squares = [x**2 for x in range(1, 11)] print(f\u0026#34;1-10 的平方列表：{squares}\u0026#34;) even_squares = [x**2 for x in range(1, 11) if x % 2 == 0] print(f\u0026#34;1-10 偶数的平方：{even_squares}\u0026#34;) 字符串与其他类型的转换 # 字符串到数字的转换 num_str = \u0026#34;123\u0026#34; print(f\u0026#34;int(\u0026#39;{num_str}\u0026#39;) + 10 = {int(num_str) + 10}\u0026#34;) # 使用 map() 进行批量转换 str_numbers = [\u0026#34;1\u0026#34;, \u0026#34;2\u0026#34;, \u0026#34;3\u0026#34;, \u0026#34;4\u0026#34;, \u0026#34;5\u0026#34;] int_numbers = list(map(int, str_numbers)) print(f\u0026#34;批量转换：{int_numbers}\u0026#34;) # 使用 split() 和 map() 读取输入 user_input = \u0026#34;10 20 30 40 50\u0026#34; numbers = list(map(int, user_input.split())) print(f\u0026#34;解析输入：{numbers}, 和={sum(numbers)}\u0026#34;) # 格式化数字（千位分隔符） big_num = 1234567890 print(f\u0026#34;带千位分隔符：{big_num:,}\u0026#34;) print(f\u0026#34;科学计数法：{big_num:.2e}\u0026#34;) 字典的键和值的类型转换 # 将两个列表转换为字典 keys = [\u0026#34;name\u0026#34;, \u0026#34;age\u0026#34;, \u0026#34;city\u0026#34;] values = [\u0026#34;张三\u0026#34;, 25, \u0026#34;北京\u0026#34;] data_dict = dict(zip(keys, values)) print(f\u0026#34;合并为字典：{data_dict}\u0026#34;) # 字典键值角色互换（值必须可哈希且唯一） original = {\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2, \u0026#34;c\u0026#34;: 3} inverted = {v: k for k, v in original.items()} print(f\u0026#34;键值互换：{inverted}\u0026#34;) Python 3.11 中的类型提示（Type Hints） Python 3.11 引入了对类型系统的重要改进，类型提示现在更加简洁和强大。类型提示不会影响程序运行时的行为，但可以与 IDE、类型检查器（如 mypy）配合使用，提供更好的开发体验。\n基本类型提示 # Python 3.11 之前的类型提示 def greet(name: str) -\u0026gt; str: return f\u0026#34;Hello, {name}\u0026#34; # Python 3.11 新增的 Self 类型支持 from typing import Self class Builder: def set_name(self, name: str) -\u0026gt; Self: self.name = name return self # Python 3.11 中可以使用变量注解类型 x: int = 10 y: float = 3.14 name: str = \u0026#34;Python\u0026#34; is_active: bool = True items: list[int] = [1, 2, 3] # Python 3.9+ coordinates: tuple[int, int] = (10, 20) config: dict[str, str] = {\u0026#34;host\u0026#34;: \u0026#34;localhost\u0026#34;} 联合类型与可选类型 from typing import Union, Optional # Union 表示多种可能的类型 def process_value(value: Union[int, float, str]) -\u0026gt; str: return str(value) # Optional 等价于 Union[X, None] def find_user(user_id: int) -\u0026gt; Optional[str]: if user_id \u0026gt; 0: return \u0026#34;张三\u0026#34; return None # Python 3.10+ 引入了更简洁的 union 语法 def process(value: int | float | str) -\u0026gt; str: return str(value) 运行时类型检查 # 使用 assert 进行运行时类型检查 def add_numbers(a: int, b: int) -\u0026gt; int: assert isinstance(a, int) and isinstance(b, int), \u0026#34;参数必须是整数\u0026#34; return a + b # Python 3.11 中的类型自省改进 from typing import get_type_hints def greet(name: str, times: int = 1) -\u0026gt; str: return (f\u0026#34;Hello, {name}! \u0026#34; * times).strip() hints = get_type_hints(greet) print(f\u0026#34;类型提示：{hints}\u0026#34;) f-string 高级格式化 数值格式化 # 固定小数位数 pi = 3.141592653589793 print(f\u0026#34;π 保留 2 位：{pi:.2f}\u0026#34;) print(f\u0026#34;π 保留 4 位：{pi:.4f}\u0026#34;) # 百分数格式化 ratio = 0.256789 print(f\u0026#34;百分比：{ratio:.2%}\u0026#34;) print(f\u0026#34;百分比（无小数）：{ratio:.0%}\u0026#34;) # 货币格式化 price = 1234.56 print(f\u0026#34;价格：${price:,.2f}\u0026#34;) print(f\u0026#34;人民币：¥{price:,.2f}\u0026#34;) # 零填充 num = 42 print(f\u0026#34;零填充到 5 位：{num:05d}\u0026#34;) print(f\u0026#34;二进制：{num:08b}\u0026#34;) print(f\u0026#34;十六进制：{num:08X}\u0026#34;) 条件表达式在 f-string 中的应用 score = 85 grade = \u0026#34;A\u0026#34; if score \u0026gt;= 90 else \u0026#34;B\u0026#34; if score \u0026gt;= 80 else \u0026#34;C\u0026#34; if score \u0026gt;= 70 else \u0026#34;D\u0026#34; print(f\u0026#34;成绩 {score} 分，等级：{grade}\u0026#34;) # Python 3.11 中更清晰的多条件表达 def get_grade(score: int) -\u0026gt; str: return ( \u0026#34;A+\u0026#34; if score \u0026gt;= 95 else \u0026#34;A\u0026#34; if score \u0026gt;= 90 else \u0026#34;B+\u0026#34; if score \u0026gt;= 85 else \u0026#34;B\u0026#34; if score \u0026gt;= 80 else \u0026#34;C\u0026#34; if score \u0026gt;= 70 else \u0026#34;D\u0026#34; ) print(f\u0026#34;分数 87 分 = {get_grade(87)}\u0026#34;) 综合练习题 练习一：个人资料管理系统 \u0026#34;\u0026#34;\u0026#34; 个人资料管理系统 练习变量、数据类型和 f-string 格式化 \u0026#34;\u0026#34;\u0026#34; # 基本信息 name = \u0026#34;李明\u0026#34; age = 28 height = 1.78 weight = 70.5 is_employed = True skills = [\u0026#34;Python\u0026#34;, \u0026#34;JavaScript\u0026#34;, \u0026#34;SQL\u0026#34;, \u0026#34;Git\u0026#34;] contact = { \u0026#34;email\u0026#34;: \u0026#34;liming@example.com\u0026#34;, \u0026#34;phone\u0026#34;: \u0026#34;138-0013-8000\u0026#34;, \u0026#34;city\u0026#34;: \u0026#34;上海\u0026#34; } # 使用 f-string 输出个人资料卡 print(\u0026#34;=\u0026#34; * 50) print(f\u0026#34; 个 人 资 料 卡\u0026#34;) print(\u0026#34;=\u0026#34; * 50) print(f\u0026#34;姓名：{name}\u0026#34;) print(f\u0026#34;年龄：{age} 岁\u0026#34;) print(f\u0026#34;身高：{height} 米\u0026#34;) print(f\u0026#34;体重：{weight} 公斤\u0026#34;) print(f\u0026#34;BMI：{weight / height**2:.2f}\u0026#34;) print(f\u0026#34;在职状态：{\u0026#39;是\u0026#39; if is_employed else \u0026#39;否\u0026#39;}\u0026#34;) print(\u0026#34;-\u0026#34; * 50) print(\u0026#34;技能清单：\u0026#34;) for i, skill in enumerate(skills, 1): print(f\u0026#34; {i}. {skill}\u0026#34;) print(\u0026#34;-\u0026#34; * 50) print(\u0026#34;联系方式：\u0026#34;) print(f\u0026#34; 邮箱：{contact[\u0026#39;email\u0026#39;]}\u0026#34;) print(f\u0026#34; 电话：{contact[\u0026#39;phone\u0026#39;]}\u0026#34;) print(f\u0026#34; 城市：{contact[\u0026#39;city\u0026#39;]}\u0026#34;) print(\u0026#34;=\u0026#34; * 50) 练习二：温度单位转换器 \u0026#34;\u0026#34;\u0026#34; 温度单位转换器 练习类型转换和格式化输出 \u0026#34;\u0026#34;\u0026#34; def celsius_to_fahrenheit(c: float) -\u0026gt; float: \u0026#34;\u0026#34;\u0026#34;将摄氏度转换为华氏度\u0026#34;\u0026#34;\u0026#34; return c * 9/5 + 32 def celsius_to_kelvin(c: float) -\u0026gt; float: \u0026#34;\u0026#34;\u0026#34;将摄氏度转换为开尔文\u0026#34;\u0026#34;\u0026#34; return c + 273.15 def fahrenheit_to_celsius(f: float) -\u0026gt; float: \u0026#34;\u0026#34;\u0026#34;将华氏度转换为摄氏度\u0026#34;\u0026#34;\u0026#34; return (f - 32) * 5/9 # 测试各种温度值 temps_c = [-40, 0, 20, 37, 100] print(\u0026#34;=\u0026#34; * 60) print(f\u0026#34;{\u0026#39;°C\u0026#39;:\u0026gt;8} | {\u0026#39;°F\u0026#39;:\u0026gt;8} | {\u0026#39;K\u0026#39;:\u0026gt;10} | {\u0026#39;状态\u0026#39;:\u0026gt;15}\u0026#34;) print(\u0026#34;-\u0026#34; * 60) for c in temps_c: f = celsius_to_fahrenheit(c) k = celsius_to_kelvin(c) if c \u0026lt;= 0: status = \u0026#34;结冰 ❄️\u0026#34; elif c \u0026lt; 100: status = \u0026#34;液态 💧\u0026#34; else: status = \u0026#34;气态 🔥\u0026#34; print(f\u0026#34;{c:\u0026gt;8.1f} | {f:\u0026gt;8.1f} | {k:\u0026gt;10.2f} | {status:\u0026gt;15}\u0026#34;) print(\u0026#34;=\u0026#34; * 60) 练习三：购物车计算器 \u0026#34;\u0026#34;\u0026#34; 购物车计算器 练习列表、字典、类型转换和格式化 \u0026#34;\u0026#34;\u0026#34; # 购物车中的商品 cart = [ {\u0026#34;name\u0026#34;: \u0026#34;Python 入门书籍\u0026#34;, \u0026#34;price\u0026#34;: 89.00, \u0026#34;quantity\u0026#34;: 1}, {\u0026#34;name\u0026#34;: \u0026#34;机械键盘\u0026#34;, \u0026#34;price\u0026#34;: 299.00, \u0026#34;quantity\u0026#34;: 1}, {\u0026#34;name\u0026#34;: \u0026#34;鼠标垫\u0026#34;, \u0026#34;price\u0026#34;: 29.90, \u0026#34;quantity\u0026#34;: 2}, {\u0026#34;name\u0026#34;: \u0026#34;耳机\u0026#34;, \u0026#34;price\u0026#34;: 159.00, \u0026#34;quantity\u0026#34;: 1}, ] # 计算总价和商品数量 total_items = sum(item[\u0026#34;quantity\u0026#34;] for item in cart) subtotal = sum(item[\u0026#34;price\u0026#34;] * item[\u0026#34;quantity\u0026#34;] for item in cart) discount = subtotal * 0.1 if subtotal \u0026gt; 500 else 0 # 满500打9折 tax = (subtotal - discount) * 0.13 # 13% 税 total = subtotal - discount + tax # 输出购物小票 print(\u0026#34;=\u0026#34; * 60) print(\u0026#34; 购 物 小 票\u0026#34;) print(\u0026#34;=\u0026#34; * 60) print(f\u0026#34;{\u0026#39;商品名称\u0026#39;:\u0026lt;20} {\u0026#39;单价\u0026#39;:\u0026gt;10} {\u0026#39;数量\u0026#39;:\u0026gt;5} {\u0026#39;小计\u0026#39;:\u0026gt;10}\u0026#34;) print(\u0026#34;-\u0026#34; * 60) for item in cart: subtotal_item = item[\u0026#34;price\u0026#34;] * item[\u0026#34;quantity\u0026#34;] print(f\u0026#34;{item[\u0026#39;name\u0026#39;]:\u0026lt;20} ¥{item[\u0026#39;price\u0026#39;]:\u0026gt;8.2f} {item[\u0026#39;quantity\u0026#39;]:\u0026gt;5} ¥{subtotal_item:\u0026gt;9.2f}\u0026#34;) print(\u0026#34;-\u0026#34; * 60) print(f\u0026#34;{\u0026#39;商品总数：\u0026#39;:\u0026lt;20}{total_items:\u0026gt;30}\u0026#34;) print(f\u0026#34;{\u0026#39;小计：\u0026#39;:\u0026lt;20}¥{subtotal:\u0026gt;29.2f}\u0026#34;) if discount \u0026gt; 0: print(f\u0026#34;{\u0026#39;折扣（9折）：\u0026#39;:\u0026lt;20}¥{-discount:\u0026gt;29.2f}\u0026#34;) print(f\u0026#34;{\u0026#39;税额（13%）：\u0026#39;:\u0026lt;20}¥{tax:\u0026gt;29.2f}\u0026#34;) print(\u0026#34;=\u0026#34; * 60) print(f\u0026#34;{\u0026#39;应付总额：\u0026#39;:\u0026lt;20}¥{total:\u0026gt;29.2f}\u0026#34;) print(\u0026#34;=\u0026#34; * 60) Python 3.11 类型系统的新特性 类型别名 # Python 3.11 中的类型别名 from typing import TypeAlias Vector: TypeAlias = list[float] Matrix: TypeAlias = list[list[float]] def scale_vector(v: Vector, scalar: float) -\u0026gt; Vector: return [x * scalar for x in v] def multiply_matrices(a: Matrix, b: Matrix) -\u0026gt; Matrix: # 矩阵乘法简化实现 result = [[0.0] * len(b[0]) for _ in range(len(a))] for i in range(len(a)): for j in range(len(b[0])): for k in range(len(b)): result[i][j] += a[i][k] * b[k][j] return result TypeGuard（类型守卫） from typing import TypeGuard def is_str_list(val: list[object]) -\u0026gt; TypeGuard[list[str]]: \u0026#34;\u0026#34;\u0026#34;检查列表是否全是字符串\u0026#34;\u0026#34;\u0026#34; return all(isinstance(x, str) for x in val) data: list[object] = [\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;] if is_str_list(data): # 在这个分支中，mypy 知道 data 是 list[str] print(f\u0026#34;全部是字符串，长度：{len(data)}\u0026#34;) 常见错误与调试 错误一：TypeError 类型不匹配 # 错误示例 age = 25 print(\u0026#34;年龄：\u0026#34; + age) # TypeError: can only concatenate str # 正确做法 print(f\u0026#34;年龄：{age}\u0026#34;) print(\u0026#34;年龄：\u0026#34; + str(age)) 错误二：KeyError 字典键不存在 config = {\u0026#34;host\u0026#34;: \u0026#34;localhost\u0026#34;, \u0026#34;port\u0026#34;: 8080} # print(config[\u0026#34;username\u0026#34;]) # KeyError: \u0026#39;username\u0026#39; # 安全访问方式 print(config.get(\u0026#34;username\u0026#34;, \u0026#34;未设置\u0026#34;)) # 输出：未设置 错误三：IndexError 列表索引越界 items = [\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;] # print(items[5]) # IndexError: list index out of range # 安全访问方式 print(items[5] if len(items) \u0026gt; 5 else \u0026#34;索引超出范围\u0026#34;) 本章小结 今天我们学习了以下核心内容：\n变量：Python 变量的命名规则、多重赋值、内存管理机制。 数据类型：整数、浮点数、字符串、布尔值、列表、元组、字典、集合的详细介绍。 类型转换：隐式转换和显式转换，各种数据类型之间的转换方法。 f-string 高级格式化：数值格式化、条件表达式、字典和列表在 f-string 中的使用。 Python 3.11 类型提示：类型别名、TypeGuard、类型守卫等新特性。 下一节课我们将学习 Python 的运算符、运算符优先级以及 Python 3.8 引入的 walrus operator（海象运算符），敬请期待！\n延伸阅读 Python Official Documentation - Data Types Python 3.11 Type hints PEP 673 - Type Self PEP 675 - Arbitrary Literal String Type Guard Real Python - Python Type Checking ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-02-variables-datatypes/","summary":"\u003ch1 id=\"python-第二课变量数据类型与类型转换\"\u003ePython 第二课：变量、数据类型与类型转换\u003c/h1\u003e\n\u003ch2 id=\"课程概述\"\u003e课程概述\u003c/h2\u003e\n\u003cp\u003e本节课我们将深入学习 Python 编程中最核心的概念之一——变量（Variables）。变量是存储数据的容器，是所有程序的基础构建块。我们还将全面介绍 Python 的内置数据类型（Built-in Data Types），包括整数（int）、浮点数（float）、字符串（str）、布尔值（bool）、列表（list）、元组（tuple）、字典（dict）和集合（set）。此外，我们还将学习 Python 中的类型转换（Type Conversion）和 f-string 高级格式化技巧。本课程所有内容基于 \u003cstrong\u003ePython 3.11\u003c/strong\u003e 标准，涵盖了 Python 3.11 中关于类型系统的新特性和改进。Python 是一门动态类型语言（dynamically typed language），这意味着变量不需要显式声明类型，Python 解释器会根据赋给变量的值自动推断类型。但与此同时，Python 也是一门强类型语言（strongly typed language），不同类型的数据不能随意进行混合运算，必须通过显式的类型转换来实现。\u003c/p\u003e\n\u003ch2 id=\"变量详解\"\u003e变量详解\u003c/h2\u003e\n\u003ch3 id=\"变量的基本概念\"\u003e变量的基本概念\u003c/h3\u003e\n\u003cp\u003e在 Python 中，变量是用于存储数据值的容器。你可以形象地将变量想象为一个贴有标签的盒子，盒子里存放着数据，而标签就是变量的名字。每次给变量赋值时，变量就会指向新的数据对象。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 变量的基本赋值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ename \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e       \u003cspan style=\"color:#75715e\"\u003e# 字符串变量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eage \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e25\u003c/span\u003e            \u003cspan style=\"color:#75715e\"\u003e# 整数变量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eheight \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1.75\u003c/span\u003e       \u003cspan style=\"color:#75715e\"\u003e# 浮点数变量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eis_student \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# 布尔变量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;姓名：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;年龄：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eage\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;身高：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eheight\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 米\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;是否学生：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eis_student\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输出：\u003c/p\u003e\n姓名：张三\n年龄：25\n身高：1.75 米\n是否学生：True\u003ch3 id=\"变量的命名规则\"\u003e变量的命名规则\u003c/h3\u003e\n\u003cp\u003ePython 中的变量名必须遵守以下规则：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e变量名只能包含字母、数字和下划线（_），不能包含空格或特殊字符。\u003c/li\u003e\n\u003cli\u003e变量名不能以数字开头。\u003c/li\u003e\n\u003cli\u003e变量名不能使用 Python 的保留关键字（keywords）。\u003c/li\u003e\n\u003cli\u003e变量名区分大小写（\u003ccode\u003ename\u003c/code\u003e 和 \u003ccode\u003eName\u003c/code\u003e 是两个不同的变量）。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 合法的变量名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emy_variable \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e_private_data \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;secret\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecamelCase \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;驼峰命名\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eCONSTANT_VALUE \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 常量习惯用全大写\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Python 3.11 中还可以使用 Unicode 字符作为变量名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e姓名 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;李四\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eπ \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3.14159\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 不合法的变量名（会导致 SyntaxError）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 2nd_value = 20      # 不能以数字开头\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# my-var = 30         # 不能使用连字符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# class = \u0026#34;高级\u0026#34;       # 不能使用保留关键字\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"python-保留关键字\"\u003ePython 保留关键字\u003c/h3\u003e\n\u003cp\u003e以下是 Python 3.11 中的所有保留关键字（35个），你不能将它们作为变量名使用：\u003c/p\u003e","tags":"Python, 编程","title":"Python 第二课：变量、数据类型与类型转换"},{"columns":"acp-course","content":" 来源：Notion ACP学习笔记 + 阿里云开发者社区 + 网络资料整理\n一、详细讲解 1.1 虚拟化概述 **虚拟化（Virtualization）**是将物理计算资源（CPU、内存、存储、网络）抽象成虚拟资源池的技术，使得一个物理服务器可以同时运行多个相互隔离的虚拟机。\n虚拟化的核心价值：\n资源利用率提升：一台物理机跑多个 VM，充分利用 CPU 空闲算力 成本降低：减少物理服务器采购，降低机房空间和电力消耗 隔离性强：每个 VM 独立运行，故障互不影响 快速部署：分钟级创建 VM vs 传统物理机数天交付 弹性伸缩：根据负载动态创建/销毁 VM 1.2 CPU 虚拟化（重点） CPU 虚拟化的原理 CPU 虚拟化让一个物理 CPU 模拟出多个虚拟 CPU（vCPU），每个 VM 认为自己独占一个完整的 CPU。\n两种 CPU 虚拟化架构：\n架构 说明 特点 全虚拟化 VM 通过二进制翻译模拟硬件，Guest OS 无需修改 性能损耗较大，但兼容性好 半虚拟化 Guest OS 经过修改，主动配合 Hypervisor 性能好，但需要修改 Guest OS 硬件辅助虚拟化 CPU 提供 VT-x/AMD-V 硬件支持，Guest OS 无需修改 性能接近物理机，主流方案 阿里云 ECS 使用的虚拟化技术：\n基于 KVM（Kernel-based Virtual Machine）+ 硬件辅助虚拟化（Intel VT-x / AMD-V） 通过 virtio 驱动优化 I/O 性能 vCPU 算力计算 单核 vCPU 算力 ≈ 1 个物理 CPU 超线程的算力\n1 个物理核心（Core）= 2 个逻辑核心（Thread，超线程） 1 个 vCPU ≈ 1 个超线程的算力 ECS 实例规格与 vCPU 的关系：\necs.g6.large = 2 vCPU \u0026#43; 8 GiB 内存 ecs.g6.xlarge = 4 vCPU \u0026#43; 16 GiB 内存 ecs.c6.2xlarge= 8 vCPU \u0026#43; 16 GiB 内存CPU QoS（服务质量）三种控制策略 策略 说明 场景 Guaranteed（保证型） 100% 保证规格，性能稳定 核心数据库、中间件 Burstable（突发型） 基准算力低，可突发向上 开发测试、Web 应用 Shared（共享型） 多个实例共享物理资源 轻量级应用、爬虫 1.3 内存虚拟化（重点） 内存虚拟化的原理 内存虚拟化将物理内存抽象为虚拟内存空间，每个 VM 被赋予一块连续、超大的虚拟内存地址。\n内存虚拟化的两种模式：\n模式 说明 特点 软件模拟 Hypervisor 模拟虚拟内存地址到物理地址的映射表 灵活但性能损耗大 硬件辅助（EPT/NPT） CPU 自动完成两级地址转换（VA → PA → MA） 性能接近物理机 地址翻译三级跳：\n虚拟地址 (VA) → 物理地址 (PA) → 机器地址 (MA) （VM 视角） （Hypervisor 分配） （实际硬件）内存气泡（Memory Ballooning） Hypervisor 通过内存气泡机制，从内存使用率低的 VM 借调内存给内存紧张的 VM，提高整体内存利用率。\n内存复用技术：\n内存气泡：动态回收空闲 VM 内存 内存压缩：对不活跃内存页面进行压缩 Swap：将内存换出到磁盘（性能会下降） 1.4 NUMA 架构与 vCPU 绑定 NUMA（Non-Uniform Memory Access）：非统一内存访问架构\n每个 NUMA 节点 = 1 组 CPU + 本地内存 跨 NUMA 访问内存延迟远高于本地访问 阿里云 ECS 大规格实例（≥ 8 vCPU）默认采用 NUMA 架构 性能优化建议：\n对延迟敏感的应用：将进程绑定到本地 NUMA 节点 ECS 开启 NUMA 功能：让 VM 的 vCPU 和内存尽量在同一 NUMA 节点 1.5 I/O 虚拟化 技术 说明 virtio 半虚拟化 I/O 驱动，VM 无需模拟真实硬件，Hypervisor 提供虚拟设备，性能好 SR-IOV 单根 I/O 虚拟化，让 VM 直接访问物理网卡，绕过 Hypervisor，性能最优 VF（Virtual Function） SR-IOV 虚拟出的功能接口，一个物理网卡可虚拟出多个 VF 1.6 阿里云 ECS 实例分类 实例族 特点 适用场景 通用型（g） 平衡 CPU 和内存 Web 应用、中等负载 计算型（c） CPU 占比高 高性能计算、批量处理 内存型（r） 内存占比高 数据库、缓存 本地 SSD 型（i） 高性能本地盘 低延迟数据库 GPU/FPGA 型（gn） 异构计算 AI 推理、深度学习 弹性裸金属（ebm） 物理机体验 核心数据库、需物理隔离 二、背诵版（Night Before Exam） CPU 虚拟化 KVM + VT-x = 阿里云 ECS 的底层虚拟化技术\n全虚拟化 = 二进制翻译（慢） 半虚拟化 = 修改 Guest OS（快但不通用） 硬件辅助虚拟化 = VT-x/AMD-V = 主流 = 快 vCPU 算力 1 vCPU ≈ 1 个物理 CPU 超线程的算力 1 物理核 = 2 vCPU（超线程）\nCPU QoS 三种策略 Guaranteed（保证）/ Burstable（突发）/ Shared（共享）\n保证型：金融数据库，要稳定 突发型：Web 开发测试，省钱 共享型：爬虫、离线任务 内存虚拟化 地址翻译：VA → PA → MA（虚拟→物理→机器） EPT/NPT = 硬件辅助内存虚拟化 = 主流方案 内存气泡 = Hypervisor 动态回收空闲 VM 内存\nNUMA NUMA = 非统一内存访问 = 本地访问快、跨节点访问慢 大规格 ECS（≥ 8 vCPU）默认 NUMA 架构\n三、速记版（考前 5 分钟回忆） ✅ 虚拟化 = 一台物理机变多台虚拟机 ✅ KVM = 阿里云 ECS 底层虚拟化引擎 ✅ VT-x/AMD-V = CPU 硬件辅助虚拟化 = 主流 ✅ 1 vCPU ≈ 1 超线程算力 ✅ 1 物理核 = 2 vCPU（超线程） ✅ EPT = 硬件辅助内存虚拟化 = 零损耗 ✅ 内存气泡 = 动态回收空闲 VM 内存 ✅ NUMA = 本地访问快，跨节点慢 ✅ virtio = 半虚拟化 I/O 驱动 = 性能好 ✅ SR-IOV = 网卡硬件虚拟化 = 最高性能 ✅ 通用型 g = 平衡，计算型 c = CPU 高，内存型 r = 内存高 四、测试练习题 单选题 1. 阿里云 ECS 底层使用的虚拟化技术是？\nA. VMware ESXi B. Xen C. KVM + 硬件辅助虚拟化 ✅ D. Hyper-V 答案：C\n解析：阿里云使用 KVM（Kernel-based Virtual Machine）配合 Intel VT-x / AMD-V 硬件辅助虚拟化。\n2. 关于 vCPU 和物理 CPU 的关系，以下说法正确的是？\nA. 1 个 vCPU = 1 个物理核心 B. 1 个物理核心 = 1 个 vCPU C. 1 个物理核心 = 2 个 vCPU（超线程）✅ D. vCPU 和物理 CPU 没有对应关系 答案：C\n解析：现代 CPU 超线程技术让每个物理核心提供 2 个逻辑线程（vCPU）。\n3. 内存虚拟化中，VA → PA → MA 的三级地址翻译中，PA 代表什么地址？\nA. 虚拟地址 B. 物理地址（Hypervisor 分配的）✅ C. 机器地址 D. 磁盘地址 答案：B\n解析：VA 是 VM 看到的虚拟地址，PA 是 Hypervisor 分配给 VM 的物理地址，MA 是实际硬件机器地址。\n4. EPT/NPT 技术的作用是？\nA. 加速 CPU 虚拟化 B. 加速内存虚拟化 ✅ C. 加速网络 I/O D. 实现存储虚拟化 答案：B\n解析：EPT（Extended Page Table）/ NPT（Nested Page Table）是 CPU 硬件辅助的内存虚拟化技术，自动完成两级地址转换。\n5. NUMA 架构中，跨 NUMA 节点访问内存的延迟？\nA. 和本地访问一样 B. 比本地访问慢很多 ✅ C. 比本地访问快 D. 不确定 答案：B\n解析：NUMA 的设计目标是让 CPU 访问本地节点内存更快，跨节点访问有显著延迟惩罚。\n6. 以下哪种 CPU QoS 策略适合开发测试环境？\nA. Guaranteed B. Burstable ✅ C. Dedicated D. Reserved 答案：B\n解析：突发型（Burstable）价格低，有突发能力，适合负载波动大的开发测试环境。\n多选题 7. 阿里云 ECS 的内存复用技术包括？\nA. 内存气泡 ✅ B. 内存压缩 ✅ C. 内存交换（Swap） ✅ D. 内存硬分片 答案：A、B、C\n解析：内存气泡、内存压缩、Swap 都是 Hypervisor 层的内存复用技术。硬分片不是标准复用技术。\n8. virtio 和 SR-IOV 的区别包括？\nA. virtio 是软件模拟的虚拟化驱动 B. SR-IOV 让 VM 直接访问物理网卡 ✅ C. virtio 性能优于 SR-IOV D. SR-IOV 需要硬件支持 ✅ 答案：B、D\n解析：virtio 是半虚拟化驱动（软件），性能好但不如 SR-IOV。SR-IOV 需要网卡硬件支持，性能最优。\n判断题 9. 在阿里云 ECS 中，1 个 ecs.c6.2xlarge 实例拥有 2 个物理 CPU 核心，共 4 个 vCPU。\nA. 正确 B. 错误 ✅ 答案：B\n解析：2xlarge = 8 vCPU，约等于 4 个物理核心（超线程后）。\n10. 内存气泡技术可以无限从空闲 VM 借调内存。\nA. 正确 B. 错误 答案：A\n解析：内存气泡由 Hypervisor 控制，只能回收 VM 实际空闲的内存，不能超量借用。\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-02-day2-%E8%AE%A1%E7%AE%97%E8%99%9A%E6%8B%9F%E5%8C%96-cpu%E5%86%85%E5%AD%98%E8%99%9A%E6%8B%9F%E5%8C%96/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：Notion ACP学习笔记 + 阿里云开发者社区 + 网络资料整理\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-虚拟化概述\"\u003e1.1 虚拟化概述\u003c/h3\u003e\n\u003cp\u003e**虚拟化（Virtualization）**是将物理计算资源（CPU、内存、存储、网络）抽象成虚拟资源池的技术，使得一个物理服务器可以同时运行多个相互隔离的虚拟机。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e虚拟化的核心价值\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e资源利用率提升\u003c/strong\u003e：一台物理机跑多个 VM，充分利用 CPU 空闲算力\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e成本降低\u003c/strong\u003e：减少物理服务器采购，降低机房空间和电力消耗\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e隔离性强\u003c/strong\u003e：每个 VM 独立运行，故障互不影响\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e快速部署\u003c/strong\u003e：分钟级创建 VM vs 传统物理机数天交付\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e弹性伸缩\u003c/strong\u003e：根据负载动态创建/销毁 VM\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"12-cpu-虚拟化重点\"\u003e1.2 CPU 虚拟化（重点）\u003c/h3\u003e\n\u003ch4 id=\"cpu-虚拟化的原理\"\u003eCPU 虚拟化的原理\u003c/h4\u003e\n\u003cp\u003eCPU 虚拟化让一个物理 CPU 模拟出多个虚拟 CPU（vCPU），每个 VM 认为自己独占一个完整的 CPU。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e两种 CPU 虚拟化架构\u003c/strong\u003e：\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e架构\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n          \u003cth\u003e特点\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e全虚拟化\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eVM 通过二进制翻译模拟硬件，Guest OS 无需修改\u003c/td\u003e\n          \u003ctd\u003e性能损耗较大，但兼容性好\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e半虚拟化\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eGuest OS 经过修改，主动配合 Hypervisor\u003c/td\u003e\n          \u003ctd\u003e性能好，但需要修改 Guest OS\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e硬件辅助虚拟化\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eCPU 提供 VT-x/AMD-V 硬件支持，Guest OS 无需修改\u003c/td\u003e\n          \u003ctd\u003e性能接近物理机，主流方案\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cstrong\u003e阿里云 ECS 使用的虚拟化技术\u003c/strong\u003e：\u003c/p\u003e","tags":"ACP, 阿里云, 虚拟化","title":"Day2 计算虚拟化 + CPU内存虚拟化"},{"columns":"python-course","content":"Python 第三课：运算符、优先级与海象运算符 课程概述 本节课我们将全面学习 Python 中的运算符（Operators）。运算符是用于执行各种运算操作的符号，Python 提供了丰富的运算符，包括算术运算符、比较运算符、逻辑运算符、位运算符、赋值运算符、身份运算符和成员运算符。我们还将深入探讨运算符的优先级（Operator Precedence），理解 Python 如何按照固定的规则计算包含多个运算符的表达式。此外，本课将重点介绍 Python 3.8 引入的海象运算符（Walrus Operator），即赋值表达式（Assignment Expression），它允许在表达式内部进行变量赋值，是一个非常强大且实用的特性。本课程所有内容基于 Python 3.11 编写，涵盖了 Python 3.11 中运算符语法的最新变化和最佳实践。\nPython 的运算符系统设计得既强大又优雅。Python 支持运算符重载（Operator Overloading），这意味着同一个运算符在不同数据类型上可能有不同的行为。例如，+ 运算符可以用于数字相加、字符串拼接、列表合并等多种场景，这种设计被称为\u0026quot;魔法方法\u0026quot;（Dunder Methods）或运算符重载。理解运算符的工作原理对于编写高效、简洁的 Python 代码至关重要。\n算术运算符 算术运算符是最常用的运算符类型，用于执行基本的数学运算。\n基本算术运算符 # 加减乘除 a, b = 15, 4 print(f\u0026#34;a = {a}, b = {b}\u0026#34;) print(f\u0026#34;a + b = {a + b}\u0026#34;) # 19 print(f\u0026#34;a - b = {a - b}\u0026#34;) # 11 print(f\u0026#34;a * b = {a * b}\u0026#34;) # 60 print(f\u0026#34;a / b = {a / b:.4f}\u0026#34;) # 3.7500（浮点除法） # 整除（向下取整） print(f\u0026#34;a // b = {a // b}\u0026#34;) # 3 # 取余（模运算） print(f\u0026#34;a % b = {a % b}\u0026#34;) # 3（15 = 4 * 3 + 3） # 幂运算（指数运算） print(f\u0026#34;a ** b = {a ** b}\u0026#34;) # 15^4 = 50625 # 负数运算 print(f\u0026#34;-a = {-a}\u0026#34;) # -15 print(f\u0026#34;+a = {+a}\u0026#34;) # 15（正号，一元运算符） 整数除法的特殊情况 # Python 3.11 中整数除法的行为 print(f\u0026#34;5 / 2 = {5 / 2}\u0026#34;) # 2.5（总是返回浮点数） print(f\u0026#34;5 // 2 = {5 // 2}\u0026#34;) # 2（向下取整） print(f\u0026#34;-5 // 2 = {-5 // 2}\u0026#34;) # -3（向下取整，负数向更小的整数取整） print(f\u0026#34;5 // -2 = {5 // -2}\u0026#34;) # -3 print(f\u0026#34;-5 // -2 = {-5 // -2}\u0026#34;) # 2 # 模运算与整除的关系 print(f\u0026#34;5 % 2 = {5 % 2}\u0026#34;) # 1 print(f\u0026#34;-5 % 2 = {-5 % 2}\u0026#34;) # 1（Python 保证 a % b 的符号与 b 相同） print(f\u0026#34;5 % -2 = {5 % -2}\u0026#34;) # -1 print(f\u0026#34;-5 % -2 = {-5 % -2}\u0026#34;) # -1 算术运算符的组合赋值 # 组合赋值运算符 x = 10 print(f\u0026#34;初始 x = {x}\u0026#34;) x += 5 # 等价于 x = x + 5 print(f\u0026#34;x += 5 后，x = {x}\u0026#34;) x -= 3 # 等价于 x = x - 3 print(f\u0026#34;x -= 3 后，x = {x}\u0026#34;) x *= 2 # 等价于 x = x * 2 print(f\u0026#34;x *= 2 后，x = {x}\u0026#34;) x /= 4 # 等价于 x = x / 4 print(f\u0026#34;x /= 4 后，x = {x}\u0026#34;) x //= 2 # 等价于 x = x // 2 print(f\u0026#34;x //= 2 后，x = {x}\u0026#34;) x **= 3 # 等价于 x = x ** 3 print(f\u0026#34;x **= 3 后，x = {x}\u0026#34;) x %= 10 # 等价于 x = x % 10 print(f\u0026#34;x %= 10 后，x = {x}\u0026#34;) 算术运算符的字符串和序列操作 # 字符串的乘法运算 text = \u0026#34;Python \u0026#34; print(f\u0026#34;text * 3 = \u0026#39;{text * 3}\u0026#39;\u0026#34;) # 列表的加法和乘法 list1 = [1, 2, 3] list2 = [4, 5, 6] print(f\u0026#34;list1 + list2 = {list1 + list2}\u0026#34;) # 列表拼接 print(f\u0026#34;list1 * 2 = {list1 * 2}\u0026#34;) # 列表重复 # 元组的加法和乘法 t1 = (1, 2, 3) t2 = (4, 5, 6) print(f\u0026#34;t1 + t2 = {t1 + t2}\u0026#34;) print(f\u0026#34;t1 * 3 = {t1 * 3}\u0026#34;) 比较运算符 比较运算符用于比较两个值的大小或相等性，返回布尔值（True 或 False）。\n基本比较运算符 a, b = 10, 20 print(f\u0026#34;a = {a}, b = {b}\u0026#34;) print(f\u0026#34;a == b : {a == b}\u0026#34;) # False（相等） print(f\u0026#34;a != b : {a != b}\u0026#34;) # True（不相等） print(f\u0026#34;a \u0026lt; b : {a \u0026lt; b}\u0026#34;) # True（小于） print(f\u0026#34;a \u0026gt; b : {a \u0026gt; b}\u0026#34;) # False（大于） print(f\u0026#34;a \u0026lt;= b : {a \u0026lt;= b}\u0026#34;) # True（小于等于） print(f\u0026#34;a \u0026gt;= b : {a \u0026gt;= b}\u0026#34;) # False（大于等于） # 链式比较（Python 特有） x = 15 print(f\u0026#34;10 \u0026lt; x \u0026lt; 20 : {10 \u0026lt; x \u0026lt; 20}\u0026#34;) # True，等价于 (10 \u0026lt; x) and (x \u0026lt; 20) print(f\u0026#34;10 \u0026lt; x \u0026lt; 15 : {10 \u0026lt; x \u0026lt; 15}\u0026#34;) # False 比较运算符的字符串比较 s1, s2 = \u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34; print(f\u0026#34;s1 = \u0026#39;{s1}\u0026#39;, s2 = \u0026#39;{s2}\u0026#39;\u0026#34;) print(f\u0026#34;s1 == s2 : {s1 == s2}\u0026#34;) # False print(f\u0026#34;s1 \u0026lt; s2 : {s1 \u0026lt; s2}\u0026#34;) # True（字典序比较） print(f\u0026#34;s1 \u0026gt; s2 : {s1 \u0026gt; s2}\u0026#34;) # False # 字符串比较是按字符逐个比较的 print(f\u0026#34;\u0026#39;apple\u0026#39; \u0026lt; \u0026#39;apricot\u0026#39; : {\u0026#39;apple\u0026#39; \u0026lt; \u0026#39;apricot\u0026#39;}\u0026#34;) # True # 不同类型之间的比较（谨慎使用） print(f\u0026#34;10 \u0026lt; \u0026#39;20\u0026#39; : {10 \u0026lt; \u0026#39;20\u0026#39;}\u0026#34;) # TypeError in Python 3.11 比较运算符的链式调用 Python 的链式比较是一个非常强大且优雅的特性，它不仅限于数值比较：\n# 数值链式比较 x = 7 print(f\u0026#34;1 \u0026lt; x \u0026lt; 10 : {1 \u0026lt; x \u0026lt; 10}\u0026#34;) # True print(f\u0026#34;1 \u0026lt; x \u0026lt; 5 : {1 \u0026lt; x \u0026lt; 5}\u0026#34;) # False # 链式比较的原理 # 1 \u0026lt; x \u0026lt; 10 等价于 (1 \u0026lt; x) and (x \u0026lt; 10) print(f\u0026#34;等价于：(1 \u0026lt; x) and (x \u0026lt; 10) = {(1 \u0026lt; x) and (x \u0026lt; 10)}\u0026#34;) # 三个以上的链式比较 y = 15 print(f\u0026#34;0 \u0026lt; x \u0026lt; 10 \u0026lt; y \u0026lt; 20 : {0 \u0026lt; x \u0026lt; 10 \u0026lt; y \u0026lt; 20}\u0026#34;) 逻辑运算符 Python 提供了三个逻辑运算符：and（逻辑与）、or（逻辑或）和 not（逻辑非）。Python 3.11 对逻辑运算符的行为做了明确定义，特别是短路求值（Short-circuit Evaluation）的行为。\n基本逻辑运算符 a, b = True, False print(f\u0026#34;a = {a}, b = {b}\u0026#34;) print(f\u0026#34;a and b = {a and b}\u0026#34;) # False print(f\u0026#34;a or b = {a or b}\u0026#34;) # True print(f\u0026#34;not a = {not a}\u0026#34;) # False print(f\u0026#34;not b = {not b}\u0026#34;) # True # 逻辑运算符的优先级：not \u0026gt; and \u0026gt; or print(f\u0026#34;not True or True : {not True or True}\u0026#34;) # True print(f\u0026#34;not (True or True) : {not (True or True)}\u0026#34;) # False 短路求值（Short-circuit Evaluation） 短路求值是逻辑运算符的重要特性：对于 and 表达式，如果第一个值为 False，则不再计算第二个值，直接返回 False；对于 or 表达式，如果第一个值为 True，则不再计算第二个值，直接返回 True。\n# and 的短路行为 def return_false(): print(\u0026#34; [调用 return_false()]\u0026#34;) return False def return_true(): print(\u0026#34; [调用 return_true()]\u0026#34;) return True print(\u0026#34;测试 and 的短路求值：\u0026#34;) result = return_false() and return_true() print(f\u0026#34;结果：{result}\u0026#34;) print() print(\u0026#34;由于第一个值为 False，return_true() 不会被调用\u0026#34;) print() # or 的短路行为 print(\u0026#34;测试 or 的短路求值：\u0026#34;) result = return_true() or return_false() print(f\u0026#34;结果：{result}\u0026#34;) print() print(\u0026#34;由于第一个值为 True，return_false() 不会被调用\u0026#34;) 逻辑运算符的应用场景 # 应用一：默认值赋值 name = None # 如果 name 为 None 或空字符串，则使用 \u0026#34;Guest\u0026#34; display_name = name or \u0026#34;Guest\u0026#34; print(f\u0026#34;display_name = \u0026#39;{display_name}\u0026#39;\u0026#34;) name = \u0026#34;张三\u0026#34; display_name = name or \u0026#34;Guest\u0026#34; print(f\u0026#34;display_name = \u0026#39;{display_name}\u0026#39;\u0026#34;) # 应用二：链式条件检查 user_age = 25 has_license = True if user_age \u0026gt;= 18 and has_license: print(\u0026#34;可以租车\u0026#34;) # 应用三：简化条件判断 is_weekend = False is_holiday = True is_vacation = False if is_weekend or is_holiday or is_vacation: print(\u0026#34;今天休息\u0026#34;) # 应用四：区间判断 score = 85 if 60 \u0026lt;= score \u0026lt;= 100: print(\u0026#34;及格\u0026#34;) 位运算符 位运算符用于对整数的二进制位进行操作，是低级编程和算法实现中的重要工具。Python 3.11 对位运算符的处理做了大量优化，特别是在处理大整数时。\n基本位运算符 a, b = 10, 7 # a = 0b1010, b = 0b0111 print(f\u0026#34;a = {a} (二进制: {bin(a)})\u0026#34;) print(f\u0026#34;b = {b} (二进制: {bin(b)})\u0026#34;) print() print(f\u0026#34;a \u0026amp; b = {a \u0026amp; b} (二进制: {bin(a \u0026amp; b)})\u0026#34;) # 0b0010 = 2，按位与 print(f\u0026#34;a | b = {a | b} (二进制: {bin(a | b)})\u0026#34;) # 0b1111 = 15，按位或 print(f\u0026#34;a ^ b = {a ^ b} (二进制: {bin(a ^ b)})\u0026#34;) # 0b1101 = 13，按位异或 print(f\u0026#34;~a = {~a} (二进制: {bin(~a)})\u0026#34;) # -11，按位取反 print(f\u0026#34;a \u0026lt;\u0026lt; 1 = {a \u0026lt;\u0026lt; 1} (二进制: {bin(a \u0026lt;\u0026lt; 1)})\u0026#34;) # 0b10100 = 20，左移 print(f\u0026#34;a \u0026gt;\u0026gt; 1 = {a \u0026gt;\u0026gt; 1} (二进制: {bin(a \u0026gt;\u0026gt; 1)})\u0026#34;) # 0b0101 = 5，右移 位运算的实战应用 # 判断奇偶数（比 % 2 更快） num = 42 is_even = (num \u0026amp; 1) == 0 print(f\u0026#34;{num} 是偶数：{is_even}\u0026#34;) # 快速乘除 2 的幂 n = 8 print(f\u0026#34;{n} \u0026lt;\u0026lt; 2 = {n \u0026lt;\u0026lt; 2}\u0026#34;) # 乘以 4 print(f\u0026#34;{n} \u0026gt;\u0026gt; 2 = {n \u0026gt;\u0026gt; 2}\u0026#34;) # 除以 4 # 交换两个整数（不使用临时变量） x, y = 5, 9 x = x ^ y y = x ^ y x = x ^ y print(f\u0026#34;交换后：x = {x}, y = {y}\u0026#34;) # 判断某个位是否为 1 flags = 0b10110010 bit_position = 3 is_set = (flags \u0026gt;\u0026gt; bit_position) \u0026amp; 1 print(f\u0026#34;第 {bit_position} 位是否为 1：{bool(is_set)}\u0026#34;) # 设置某个位为 1 flags = 0b10110010 bit_position = 1 flags = flags | (1 \u0026lt;\u0026lt; bit_position) print(f\u0026#34;设置第 {bit_position} 位为 1 后：{bin(flags)}\u0026#34;) 赋值运算符（Assignment Operators） 基本赋值运算符 # 最基本的赋值 x = 10 print(f\u0026#34;x = {x}\u0026#34;) # 同时给多个变量赋值 a, b, c = 1, 2, 3 print(f\u0026#34;a, b, c = {a}, {b}, {c}\u0026#34;) # 链式赋值 x = y = z = 0 print(f\u0026#34;x = y = z = 0 =\u0026gt; x={x}, y={y}, z={z}\u0026#34;) 身份运算符（Identity Operators） 身份运算符用于比较两个对象的内存地址（id），判断它们是否是同一个对象。\nis 与 is not a = [1, 2, 3] b = a # b 指向与 a 相同的对象 c = [1, 2, 3] # c 指向一个新创建的对象，内容相同但不是同一个对象 print(f\u0026#34;a = {a}\u0026#34;) print(f\u0026#34;b = a\u0026#34;) print(f\u0026#34;c = [1, 2, 3]\u0026#34;) print() print(f\u0026#34;a is b : {a is b}\u0026#34;) # True（同一对象） print(f\u0026#34;a is c : {a is c}\u0026#34;) # False（不同对象） print(f\u0026#34;a == c : {a == c}\u0026#34;) # True（内容相同） print(f\u0026#34;a is not c : {a is not c}\u0026#34;) # True（不是同一对象） Python 3.11 中整数和字符串的小整数池 # Python 会缓存小的整数和短字符串 x = 256 y = 256 print(f\u0026#34;256 is 256 : {x is y}\u0026#34;) # True（Python 缓存了 -5 到 256 的整数） x = 257 y = 257 print(f\u0026#34;257 is 257 : {x is y}\u0026#34;) # 可能为 False（取决于实现） # 字符串 interning s1 = \u0026#34;hello\u0026#34; s2 = \u0026#34;hello\u0026#34; print(f\u0026#34;\u0026#39;hello\u0026#39; is \u0026#39;hello\u0026#39; : {s1 is s2}\u0026#34;) # True（短字符串被缓存） # 复杂表达式不会被 intern s1 = \u0026#34;hello world\u0026#34; s2 = \u0026#34;hello world\u0026#34; print(f\u0026#34;\u0026#39;hello world\u0026#39; is \u0026#39;hello world\u0026#39; : {s1 is s2}\u0026#34;) # 通常为 False 成员运算符（Membership Operators） 成员运算符用于检查某个值是否存在于序列（列表、元组、字符串等）或集合中。\nin 与 not in # 列表中的成员检查 fruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;, \u0026#34;葡萄\u0026#34;] print(f\u0026#34;fruits = {fruits}\u0026#34;) print(f\u0026#34;\u0026#39;香蕉\u0026#39; in fruits : {\u0026#39;香蕉\u0026#39; in fruits}\u0026#34;) # True print(f\u0026#34;\u0026#39;西瓜\u0026#39; in fruits : {\u0026#39;西瓜\u0026#39; in fruits}\u0026#34;) # False print(f\u0026#34;\u0026#39;西瓜\u0026#39; not in fruits : {\u0026#39;西瓜\u0026#39; not in fruits}\u0026#34;) # True # 字符串中的成员检查 text = \u0026#34;Hello, Python 3.11!\u0026#34; print(f\u0026#34;\\ntext = \u0026#39;{text}\u0026#39;\u0026#34;) print(f\u0026#34;\u0026#39;Python\u0026#39; in text : {\u0026#39;Python\u0026#39; in text}\u0026#34;) # True print(f\u0026#34;\u0026#39;Java\u0026#39; in text : {\u0026#39;Java\u0026#39; in text}\u0026#34;) # False # 字典中检查的是键，不是值 person = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25, \u0026#34;city\u0026#34;: \u0026#34;北京\u0026#34;} print(f\u0026#34;\\nperson = {person}\u0026#34;) print(f\u0026#34;\u0026#39;name\u0026#39; in person : {\u0026#39;name\u0026#39; in person}\u0026#34;) # True print(f\u0026#34;\u0026#39;张三\u0026#39; in person : {\u0026#39;张三\u0026#39; in person}\u0026#34;) # False（检查键而非值） # 集合中的成员检查（非常高效） prime_numbers = {2, 3, 5, 7, 11, 13} print(f\u0026#34;\\nprime_numbers = {prime_numbers}\u0026#34;) print(f\u0026#34;7 in prime_numbers : {7 in prime_numbers}\u0026#34;) # True print(f\u0026#34;4 in prime_numbers : {4 in prime_numbers}\u0026#34;) # False 运算符优先级（Operator Precedence） 运算符优先级决定了表达式中多个运算符同时存在时的计算顺序。Python 按照从高到低的优先级计算表达式。了解运算符优先级对于正确理解复杂表达式至关重要。\n完整优先级表 以下是从高到低的运算符优先级（同一行从左到右结合）：\n1. () 括号（最高优先级） 2. ** 幂运算（右结合） 3. \u0026#43;x, -x, ~x 一元正号、一元负号、按位取反 4. *, /, //, % 乘、除、整除、取余 5. \u0026#43;, - 加、减 6. \u0026lt;\u0026lt;, \u0026gt;\u0026gt; 位左移、位右移 7. \u0026amp; 按位与 8. ^ 按位异或 9. | 按位或 10. ==, !=, \u0026gt;, \u0026gt;=, \u0026lt;, \u0026lt;= 比较运算符 11. is, is not 身份运算符 12. in, not in 成员运算符 13. not 逻辑非 14. and 逻辑与 15. or 逻辑或 16. := 赋值表达式（海象运算符）（最低优先级之一）优先级示例 # 示例 1：幂运算的优先级高于乘法 result = 2 ** 3 * 2 print(f\u0026#34;2 ** 3 * 2 = {result}\u0026#34;) # 8 * 2 = 16 print(f\u0026#34;等价于：(2 ** 3) * 2 = {(2 ** 3) * 2}\u0026#34;) # 示例 2：乘除优先于加减 result = 10 + 20 * 3 - 40 / 5 print(f\u0026#34;\\n10 + 20 * 3 - 40 / 5 = {result}\u0026#34;) print(f\u0026#34;等价于：10 + (20 * 3) - (40 / 5) = {10 + (20 * 3) - (40 / 5)}\u0026#34;) # 示例 3：逻辑运算符的优先级 result = not True and False or True print(f\u0026#34;\\nnot True and False or True = {result}\u0026#34;) print(f\u0026#34;等价于：((not True) and False) or True = {((not True) and False) or True}\u0026#34;) # 示例 4：使用括号明确优先级 result = (2 + 3) * 4 ** 2 / (5 - 3) print(f\u0026#34;\\n(2 + 3) * 4 ** 2 / (5 - 3) = {result}\u0026#34;) # 示例 5：复杂的位运算优先级 a, b, c = 8, 4, 2 result = a | b ^ c \u0026amp; a print(f\u0026#34;\\na | b ^ c \u0026amp; a = {result}\u0026#34;) print(f\u0026#34;等价于：a | (b ^ (c \u0026amp; a)) = {a | (b ^ (c \u0026amp; a))}\u0026#34;) 使用括号提高可读性 # 不好的写法（依赖优先级） result = 10 + 20 * 2 ** 3 / 4 - 5 \u0026gt; 15 and True or False # 好的写法（使用括号） result = ((10 + (20 * (2 ** 3) / 4) - 5) \u0026gt; 15) and True or False # 更可读的版本 left_side = 10 + (20 * (2 ** 3) / 4) - 5 condition = left_side \u0026gt; 15 result = condition and True or False 海象运算符（Walrus Operator）:= 海象运算符（:=）是 Python 3.8 引入的赋值表达式（Assignment Expression）特性。它的名字来源于运算符的形状像一只海象侧躺的样子（:=）。海象运算符允许在表达式内部给变量赋值，从而可以编写更加简洁和优雅的代码。\n为什么需要海象运算符？ 在没有海象运算符之前，如果我们需要在一个条件判断中使用一个计算结果，必须先计算并存储到变量中，然后再使用这个变量进行判断：\n# 没有海象运算符时的写法（Python 3.7 及之前） data = [1, 5, 3, 9, 2, 8, 7] result = [x for x in data if x \u0026gt; (sum(data) / len(data))] # 或者需要分两行： avg = sum(data) / len(data) result = [x for x in data if x \u0026gt; avg] 海象运算符的基本用法 # 使用海象运算符，可以在列表推导式中同时计算和赋值 data = [1, 5, 3, 9, 2, 8, 7] result = [x for x in data if x \u0026gt; (avg := sum(data) / len(data))] print(f\u0026#34;平均值 = {avg:.2f}\u0026#34;) print(f\u0026#34;大于平均值的元素 = {result}\u0026#34;) # 在 while 循环中使用 # 没有海象运算符： # line = input(\u0026#34;\u0026gt; \u0026#34;) # while line != \u0026#34;quit\u0026#34;: # print(f\u0026#34;你输入了：{line}\u0026#34;) # line = input(\u0026#34;\u0026gt; \u0026#34;) # 使用海象运算符： while (line := input(\u0026#34;\u0026gt; \u0026#34;)) != \u0026#34;quit\u0026#34;: print(f\u0026#34;你输入了：{line}\u0026#34;) # 正则表达式匹配中使用 import re text = \u0026#34;Python 3.11 是 2022 年发布的\u0026#34; pattern = r\u0026#34;Python (\\d+\\.\\d+)\u0026#34; match = re.search(pattern, text) if match: version = match.group(1) print(f\u0026#34;找到 Python 版本：{version}\u0026#34;) # 使用海象运算符简化 if (match := re.search(pattern, text)): print(f\u0026#34;找到 Python 版本：{match.group(1)}\u0026#34;) 海象运算符的详细示例 # 示例 1：文件处理 # 传统写法： with open(\u0026#34;/tmp/test.txt\u0026#34;, \u0026#34;w\u0026#34;) as f: for line in f: line = line.strip() if line: print(line) # 更简洁的写法（海象运算符） with open(\u0026#34;/tmp/test.txt\u0026#34;, \u0026#34;w\u0026#34;) as f: while (line := f.readline()): line = line.strip() if line: print(line) # 示例 2：字典的 get 方法配合海象运算符 data = {\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2, \u0026#34;c\u0026#34;: 3} if (value := data.get(\u0026#34;d\u0026#34;)) is not None: print(f\u0026#34;找到值：{value}\u0026#34;) else: print(\u0026#34;键 \u0026#39;d\u0026#39; 不存在，使用默认值 0\u0026#34;) value = 0 # 示例 3：重复调用函数时避免重复计算 import math def expensive_computation(n): \u0026#34;\u0026#34;\u0026#34;模拟一个耗时的计算\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34; [执行耗计算：sqrt({n})]\u0026#34;) return math.sqrt(n) threshold = 10 numbers = [25, 4, 16, 100, 9] # 传统写法：每次循环都调用函数 for n in numbers: if expensive_computation(n) \u0026gt; threshold: print(f\u0026#34; {n} 的平方根大于 {threshold}\u0026#34;) print() # 使用海象运算符：只计算一次 for n in numbers: if (result := expensive_computation(n)) \u0026gt; threshold: print(f\u0026#34; {n} 的平方根（{result:.2f}）大于 {threshold}\u0026#34;) 海象运算符的注意事项 # 注意 1：海象运算符有最低优先级之一 # x := a + b 会被解析为 x := (a + b) # 而 x = a + b 也会被解析为 x = (a + b) # 注意 2：在列表推导式中的变量作用域 # Python 3.11 中，列表推导式中的赋值表达式会让变量泄漏到外部作用域 result = [y := x**2 for x in range(5)] print(f\u0026#34;结果：{result}\u0026#34;) print(f\u0026#34;y 的值：{y}\u0026#34;) # y = 4**2 = 16（在 Python 3.11 中） # 注意 3：不能在顶级表达式中使用（在交互式解释器中除外） # print(y := 10) # 这是合法的 # 注意 4：不能在函数参数默认值中使用 # def func(x = y := 10): # SyntaxError # 注意 5：不能在 lambda 表达式的主表达式中使用 # func = lambda x: y := x + 1 # SyntaxError func = lambda x: (y := x + 1, y)[1] # 合法但不推荐 print(f\u0026#34;lambda: {func(5)}\u0026#34;) 海象运算符的实际应用场景 # 场景 1：缓存计算结果 def fibonacci(n): \u0026#34;\u0026#34;\u0026#34;计算斐波那契数（带缓存的递归实现）\u0026#34;\u0026#34;\u0026#34; cache = {} def _fib(n): if n in cache: return cache[n] if n \u0026lt;= 1: return n cache[n] = _fib(n-1) + _fib(n-2) return cache[n] return _fib(n) # 场景 2：条件表达式中的重复计算 # 没有海象运算符： content = fetch_data() # 假设这是一个耗时的操作 if len(content) \u0026gt; 100: print(f\u0026#34;数据过长：{len(content)} 个字符\u0026#34;) process(content) else: print(\u0026#34;数据为空或太短\u0026#34;) # 使用海象运算符（Python 3.8+） if (content := fetch_data()) and len(content) \u0026gt; 100: print(f\u0026#34;数据过长：{len(content)} 个字符\u0026#34;) process(content) elif content: print(\u0026#34;数据为空或太短\u0026#34;) # 场景 3：循环中的模式匹配 data = [1, 2, 3, \u0026#34;error\u0026#34;, 4, 5, None, 6] while (item := data.pop()) is not None: print(f\u0026#34;处理数据：{item}\u0026#34;) Python 3.11 中的运算符改进 比较运算符的优化 Python 3.11 对比较运算符的实现进行了优化，特别是对于链式比较和复杂表达式的处理。以下是一些 Python 3.11 中值得注意的改进：\n# Python 3.11 中链式比较的优化 a, b, c, d = 1, 2, 3, 4 # 链式比较现在有更清晰的错误信息 # 在 Python 3.11 中运行以下代码： # 1 \u0026lt; \u0026#34;2\u0026#34; # TypeError: \u0026#39;\u0026lt;\u0026#39; not supported between instances of \u0026#39;int\u0026#39; and \u0026#39;str\u0026#39; f-string 中的赋值表达式 Python 3.11 增强了 f-string 功能，其中一个重要的改进是支持在 f-string 中使用赋值表达式（海象运算符）：\n# Python 3.11 中 f-string 与海象运算符结合 name = \u0026#34;Python\u0026#34; # 注意：在 f-string 中使用 := 有一些限制 # Python 3.11 中 f-string 的 := 用法： x = 10 print(f\u0026#34;{x=}\u0026#34;) print(f\u0026#34;{x+5=}\u0026#34;) 综合练习题 练习一：运算符综合应用 \u0026#34;\u0026#34;\u0026#34; 运算符综合练习 练习各种运算符的使用和优先级 \u0026#34;\u0026#34;\u0026#34; def demonstrate_operators(): print(\u0026#34;=\u0026#34; * 60) print(\u0026#34; Python 运算符综合演示\u0026#34;) print(\u0026#34;=\u0026#34; * 60) # 算术运算符 print(\u0026#34;\\n【1. 算术运算符】\u0026#34;) a, b = 17, 5 print(f\u0026#34;a = {a}, b = {b}\u0026#34;) print(f\u0026#34;a + b = {a + b}\u0026#34;) print(f\u0026#34;a - b = {a - b}\u0026#34;) print(f\u0026#34;a * b = {a * b}\u0026#34;) print(f\u0026#34;a / b = {a / b:.4f}\u0026#34;) print(f\u0026#34;a // b = {a // b}\u0026#34;) print(f\u0026#34;a % b = {a % b}\u0026#34;) print(f\u0026#34;a ** b = {a ** b}\u0026#34;) # 比较运算符 print(\u0026#34;\\n【2. 比较运算符】\u0026#34;) print(f\u0026#34;a == b : {a == b}\u0026#34;) print(f\u0026#34;a != b : {a != b}\u0026#34;) print(f\u0026#34;a \u0026lt; b : {a \u0026lt; b}\u0026#34;) print(f\u0026#34;a \u0026gt; b : {a \u0026gt; b}\u0026#34;) print(f\u0026#34;a \u0026lt;= b : {a \u0026lt;= b}\u0026#34;) print(f\u0026#34;a \u0026gt;= b : {a \u0026gt;= b}\u0026#34;) # 逻辑运算符 print(\u0026#34;\\n【3. 逻辑运算符】\u0026#34;) x, y, z = 10, 20, 30 print(f\u0026#34;x = {x}, y = {y}, z = {z}\u0026#34;) print(f\u0026#34;(x \u0026lt; y) and (y \u0026lt; z) : {(x \u0026lt; y) and (y \u0026lt; z)}\u0026#34;) # True print(f\u0026#34;(x \u0026gt; y) or (y \u0026lt; z) : {(x \u0026gt; y) or (y \u0026lt; z)}\u0026#34;) # True print(f\u0026#34;not (x \u0026lt; y) : {not (x \u0026lt; y)}\u0026#34;) # False # 位运算符 print(\u0026#34;\\n【4. 位运算符】\u0026#34;) m, n = 12, 10 # 12 = 0b1100, 10 = 0b1010 print(f\u0026#34;m = {m} (0b{m:04b}), n = {n} (0b{n:04b})\u0026#34;) print(f\u0026#34;m \u0026amp; n = {m \u0026amp; n} (0b{m \u0026amp; n:04b})\u0026#34;) # 0b1000 = 8 print(f\u0026#34;m | n = {m | n} (0b{m | n:04b})\u0026#34;) # 0b1110 = 14 print(f\u0026#34;m ^ n = {m ^ n} (0b{m ^ n:04b})\u0026#34;) # 0b0110 = 6 demonstrate_operators() 练习二：海象运算符实战 \u0026#34;\u0026#34;\u0026#34; 海象运算符实战练习 演示 := 的各种使用场景 \u0026#34;\u0026#34;\u0026#34; def walrus_operator_demo(): print(\u0026#34;=\u0026#34; * 60) print(\u0026#34; 海象运算符（:=）实战演示\u0026#34;) print(\u0026#34;=\u0026#34; * 60) # 场景 1：列表推导式中的重复计算 print(\u0026#34;\\n【场景 1：避免重复计算】\u0026#34;) scores = [85, 92, 78, 95, 88, 73, 91, 80] # 不使用海象运算符：avg 需要先计算 avg = sum(scores) / len(scores) above_avg = [s for s in scores if s \u0026gt; avg] print(f\u0026#34;分数列表：{scores}\u0026#34;) print(f\u0026#34;平均分：{avg:.2f}\u0026#34;) print(f\u0026#34;高于平均分的分数：{above_avg}\u0026#34;) # 使用海象运算符（一行搞定） above_avg_v2 = [s for s in scores if s \u0026gt; (avg := sum(scores) / len(scores))] print(f\u0026#34;使用海象运算符：{above_avg_v2}\u0026#34;) # 场景 2：while 循环中的输入处理 print(\u0026#34;\\n【场景 2：简化 while 循环】\u0026#34;) print(\u0026#34;传统写法：\u0026#34;) print(\u0026#34; line = input(\u0026#39;\u0026gt; \u0026#39;)\u0026#34;) print(\u0026#34; while line != \u0026#39;quit\u0026#39;:\u0026#34;) print(\u0026#34; print(f\u0026#39;你输入了：{line}\u0026#39;)\u0026#34;) print(\u0026#34; line = input(\u0026#39;\u0026gt; \u0026#39;)\u0026#34;) print(\u0026#34;\\n海象运算符写法：\u0026#34;) print(\u0026#34; while (line := input(\u0026#39;\u0026gt; \u0026#39;)) != \u0026#39;quit\u0026#39;:\u0026#34;) print(\u0026#34; print(f\u0026#39;你输入了：{line}\u0026#39;)\u0026#34;) # 场景 3：条件表达式中的赋值 print(\u0026#34;\\n【场景 3：条件赋值】\u0026#34;) data = {\u0026#34;x\u0026#34;: 10, \u0026#34;y\u0026#34;: 20, \u0026#34;z\u0026#34;: 30} # 查找并处理 if (value := data.get(\u0026#34;x\u0026#34;)) is not None: print(f\u0026#34;找到 x = {value}, 平方 = {value**2}\u0026#34;) else: print(\u0026#34;未找到 x\u0026#34;) # 场景 4：with 语句中的资源管理 print(\u0026#34;\\n【场景 4：简化 with 语句】\u0026#34;) import io buffer = io.StringIO() buffer.write(\u0026#34;Hello, \u0026#34;) buffer.write(\u0026#34;Python!\u0026#34;) buffer.seek(0) content = buffer.read() print(f\u0026#34;StringIO 内容：{content}\u0026#34;) walrus_operator_demo() 练习三：运算符优先级挑战 \u0026#34;\u0026#34;\u0026#34; 运算符优先级挑战 通过实例理解复杂的运算符优先级 \u0026#34;\u0026#34;\u0026#34; def precedence_challenges(): print(\u0026#34;=\u0026#34; * 60) print(\u0026#34; 运算符优先级挑战\u0026#34;) print(\u0026#34;=\u0026#34; * 60) # 挑战 1 result = 2 ** 3 ** 2 print(f\u0026#34;\\n2 ** 3 ** 2 = {result}\u0026#34;) # 2 ** 9 = 512（右结合） print(f\u0026#34;等价于：2 ** (3 ** 2) = {2 ** (3 ** 2)}\u0026#34;) # 挑战 2 result = -3 ** 2 print(f\u0026#34;\\n-3 ** 2 = {result}\u0026#34;) # -(3 ** 2) = -9（幂运算优先于一元负号） print(f\u0026#34;等价于：-(3 ** 2) = {-(3 ** 2)}\u0026#34;) print(f\u0026#34;注意：(-3) ** 2 = {(-3) ** 2}\u0026#34;) # 9 # 挑战 3 result = 5 - 3 + 2 print(f\u0026#34;\\n5 - 3 + 2 = {result}\u0026#34;) # (5 - 3) + 2 = 4（左结合） print(f\u0026#34;5 - 3 - 2 = {5 - 3 - 2}\u0026#34;) # (5 - 3) - 2 = 0 # 挑战 4 result = 10 / 3 + 3 * 2 ** 2 - 8 // 3 print(f\u0026#34;\\n10 / 3 + 3 * 2 ** 2 - 8 // 3 = {result}\u0026#34;) print(f\u0026#34;等价于：(10 / 3) + (3 * (2 ** 2)) - (8 // 3)\u0026#34;) print(f\u0026#34; = {10 / 3} + {3 * 2 ** 2} - {8 // 3}\u0026#34;) print(f\u0026#34; = {10 / 3 + 3 * 2 ** 2 - 8 // 3}\u0026#34;) # 挑战 5 a = [1, 2, 3] b = a b[0] = 10 print(f\u0026#34;\\n浅拷贝效果：a = {a}, b = {b}\u0026#34;) print(f\u0026#34;a == b : {a == b}\u0026#34;) # True print(f\u0026#34;a is b : {a is b}\u0026#34;) # True（同一对象） precedence_challenges() 常见错误与调试 错误一：浮点数比较 # 错误：直接比较浮点数 a = 0.1 + 0.2 print(f\u0026#34;a = {a}\u0026#34;) print(f\u0026#34;a == 0.3 : {a == 0.3}\u0026#34;) # False # 正确：使用 math.isclose 或 round import math print(f\u0026#34;math.isclose(a, 0.3) : {math.isclose(a, 0.3)}\u0026#34;) # True print(f\u0026#34;round(a, 10) == 0.3 : {round(a, 10) == 0.3}\u0026#34;) # True 错误二：短路求值导致的变量未定义 # 错误：依赖短路求值但变量在条件分支中都未定义 # x = 10 # if x \u0026gt; 0 and y \u0026gt; 0: # NameError: name \u0026#39;y\u0026#39; is not defined # pass # 正确：先检查变量是否存在 x, y = 10, 5 if x \u0026gt; 0 and y \u0026gt; 0: print(f\u0026#34;x * y = {x * y}\u0026#34;) 错误三：海象运算符优先级误解 # 错误理解 x = 5 # 期望：比较 x 和 3 + 2，然后赋值给 y # 实际： y := x \u0026gt; (3 + 2) # y 被赋值为 False print(f\u0026#34;y = {y}\u0026#34;) # 正确理解：:= 的优先级很低 (y := x \u0026gt; 3) + 2 # y = True (即 1)，1 + 2 = 3 print(f\u0026#34;y = {y}\u0026#34;) 本章小结 今天我们学习了以下核心内容：\n算术运算符：加、减、乘、除、整除、取余、幂运算及其组合赋值形式。 比较运算符：相等、不等、小于、大于等，以及 Python 特有的链式比较。 逻辑运算符：and、or、not，以及短路求值机制。 位运算符：按位与、或、异或、取反、左移、右移。 身份运算符：is、is not，用于比较对象的内存地址。 成员运算符：in、not in，用于检查成员资格。 运算符优先级：完整的优先级表和实际应用中的注意事项。 海象运算符（:=）：Python 3.8 引入的赋值表达式，简化代码编写。 下一节课我们将学习 Python 的条件语句（if-elif-else）和 Python 3.10 引入的结构化模式匹配（match-case），敬请期待！\n延伸阅读 Python Official Documentation - Operators PEP 572 - Assignment Expressions (Walrus Operator) Python 3.11 What\u0026rsquo;s New Real Python - Python Operators ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-03-operators-precedence/","summary":"\u003ch1 id=\"python-第三课运算符优先级与海象运算符\"\u003ePython 第三课：运算符、优先级与海象运算符\u003c/h1\u003e\n\u003ch2 id=\"课程概述\"\u003e课程概述\u003c/h2\u003e\n\u003cp\u003e本节课我们将全面学习 Python 中的运算符（Operators）。运算符是用于执行各种运算操作的符号，Python 提供了丰富的运算符，包括算术运算符、比较运算符、逻辑运算符、位运算符、赋值运算符、身份运算符和成员运算符。我们还将深入探讨运算符的优先级（Operator Precedence），理解 Python 如何按照固定的规则计算包含多个运算符的表达式。此外，本课将重点介绍 Python 3.8 引入的海象运算符（Walrus Operator），即赋值表达式（Assignment Expression），它允许在表达式内部进行变量赋值，是一个非常强大且实用的特性。本课程所有内容基于 \u003cstrong\u003ePython 3.11\u003c/strong\u003e 编写，涵盖了 Python 3.11 中运算符语法的最新变化和最佳实践。\u003c/p\u003e\n\u003cp\u003ePython 的运算符系统设计得既强大又优雅。Python 支持运算符重载（Operator Overloading），这意味着同一个运算符在不同数据类型上可能有不同的行为。例如，\u003ccode\u003e+\u003c/code\u003e 运算符可以用于数字相加、字符串拼接、列表合并等多种场景，这种设计被称为\u0026quot;魔法方法\u0026quot;（Dunder Methods）或运算符重载。理解运算符的工作原理对于编写高效、简洁的 Python 代码至关重要。\u003c/p\u003e\n\u003ch2 id=\"算术运算符\"\u003e算术运算符\u003c/h2\u003e\n\u003cp\u003e算术运算符是最常用的运算符类型，用于执行基本的数学运算。\u003c/p\u003e\n\u003ch3 id=\"基本算术运算符\"\u003e基本算术运算符\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 加减乘除\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ea, b \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e15\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e, b = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eb\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a + b = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e b\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)    \u003cspan style=\"color:#75715e\"\u003e# 19\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a - b = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e b\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)    \u003cspan style=\"color:#75715e\"\u003e# 11\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a * b = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e b\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)    \u003cspan style=\"color:#75715e\"\u003e# 60\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a / b = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e b\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.4f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)    \u003cspan style=\"color:#75715e\"\u003e# 3.7500（浮点除法）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 整除（向下取整）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a // b = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea \u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003e b\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)   \u003cspan style=\"color:#75715e\"\u003e# 3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 取余（模运算）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a % b = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea \u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e b\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)     \u003cspan style=\"color:#75715e\"\u003e# 3（15 = 4 * 3 + 3）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 幂运算（指数运算）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a ** b = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e b\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)   \u003cspan style=\"color:#75715e\"\u003e# 15^4 = 50625\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 负数运算\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;-a = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003ea\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)           \u003cspan style=\"color:#75715e\"\u003e# -15\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;+a = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003ea\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)           \u003cspan style=\"color:#75715e\"\u003e# 15（正号，一元运算符）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"整数除法的特殊情况\"\u003e整数除法的特殊情况\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Python 3.11 中整数除法的行为\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;5 / 2 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)          \u003cspan style=\"color:#75715e\"\u003e# 2.5（总是返回浮点数）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;5 // 2 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)        \u003cspan style=\"color:#75715e\"\u003e# 2（向下取整）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;-5 // 2 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)      \u003cspan style=\"color:#75715e\"\u003e# -3（向下取整，负数向更小的整数取整）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;5 // -2 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)      \u003cspan style=\"color:#75715e\"\u003e# -3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;-5 // -2 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)    \u003cspan style=\"color:#75715e\"\u003e# 2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 模运算与整除的关系\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;5 % 2 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)          \u003cspan style=\"color:#75715e\"\u003e# 1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;-5 % 2 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)        \u003cspan style=\"color:#75715e\"\u003e# 1（Python 保证 a % b 的符号与 b 相同）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;5 % -2 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)        \u003cspan style=\"color:#75715e\"\u003e# -1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;-5 % -2 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)      \u003cspan style=\"color:#75715e\"\u003e# -1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"算术运算符的组合赋值\"\u003e算术运算符的组合赋值\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 组合赋值运算符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ex \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;初始 x = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ex\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ex \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# 等价于 x = x + 5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;x += 5 后，x = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ex\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ex \u003cspan style=\"color:#f92672\"\u003e-=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# 等价于 x = x - 3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;x -= 3 后，x = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ex\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ex \u003cspan style=\"color:#f92672\"\u003e*=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# 等价于 x = x * 2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;x *= 2 后，x = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ex\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ex \u003cspan style=\"color:#f92672\"\u003e/=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# 等价于 x = x / 4\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;x /= 4 后，x = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ex\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ex \u003cspan style=\"color:#f92672\"\u003e//=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# 等价于 x = x // 2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;x //= 2 后，x = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ex\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ex \u003cspan style=\"color:#f92672\"\u003e**=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# 等价于 x = x ** 3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;x **= 3 后，x = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ex\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ex \u003cspan style=\"color:#f92672\"\u003e%=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# 等价于 x = x % 10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;x %= 10 后，x = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ex\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"算术运算符的字符串和序列操作\"\u003e算术运算符的字符串和序列操作\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 字符串的乘法运算\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Python \u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;text * 3 = \u0026#39;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etext \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 列表的加法和乘法\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elist1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elist2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;list1 + list2 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003elist1 \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e list2\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)   \u003cspan style=\"color:#75715e\"\u003e# 列表拼接\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;list1 * 2 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003elist1 \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)           \u003cspan style=\"color:#75715e\"\u003e# 列表重复\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 元组的加法和乘法\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003et1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003et2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;t1 + t2 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003et1 \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e t2\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;t1 * 3 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003et1 \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"比较运算符\"\u003e比较运算符\u003c/h2\u003e\n\u003cp\u003e比较运算符用于比较两个值的大小或相等性，返回布尔值（True 或 False）。\u003c/p\u003e","tags":"Python, 编程","title":"Python 第三课：运算符、优先级与海象运算符"},{"columns":"acp-course","content":" 来源：Notion ACP学习笔记\nACP Day 3｜阿里云综述 今日主题 Day 3：阿里云综述\n对应资料：1-04-阿里云综述.pdf\n重点整理 阿里云创立于 2009 年，是全球领先的云计算与人工智能科技公司。\n核心定位：通过在线公共服务提供安全、可靠的计算与数据处理能力。\n关键发展脉络：成立 → 对外服务 → 海外布局 → 城市大脑 → 数据库与云原生成熟 → 倚天 710 / 一云多芯 → 冬奥全面上云与 CIPU 架构。\n能力版图覆盖：计算、存储、数据库、网络、安全、大数据、AI、云原生、物联网。\n全球化能力体现为多区域、多可用区和全球 CDN 节点布局。\n三条生命线：坚持自主研发之路、与合作伙伴共生共存、坚决不碰客户数据。\n整体架构可理解为：基础设施层 + 平台产品层 + 行业解决方案层。\n背诵版 阿里云成立于 2009 年。\n阿里云提供安全、可靠的计算和数据处理能力。\n阿里云既有 IaaS，也有数据库、安全、AI、大数据、云原生等平台能力。\n阿里云具备全球化部署能力。\n三条生命线：自主研发、合作共赢、不碰客户数据。\n整体架构：基础设施层、平台产品层、行业解决方案层。\n自测题 阿里云成立于哪一年？\n阿里云的三条生命线分别是什么？\n阿里云整体架构可以概括为哪三层？\n为什么说阿里云不是单一产品，而是完整平台？\n口语化背诵版 阿里云成立于 2009 年，它是全球领先的云计算和人工智能科技公司。它的核心作用，就是通过在线公共服务的方式，给客户提供安全、可靠的计算和数据处理能力。\n阿里云不是只有一两个产品，它是一整套完整的平台，能力覆盖计算、存储、数据库、网络、安全、大数据、AI、云原生和物联网。所以考试里如果问阿里云是什么，不要只答“卖服务器的”，要答它是完整的云平台和数字化基础设施。\n阿里云的发展有几个关键节点：2009 年成立，开始研发飞天；之后具备对外服务能力；再往后开始全球化布局；然后在城市大脑、数据库、云原生、芯片这些方向不断增强；后面又有倚天 710、冬奥全面上云、CIPU 新架构这些代表性成果。这里不用死记所有年份，记住“不断从基础云服务走向全球化、平台化、智能化”就行。\n阿里云还有一个特别重要的考点，就是三条生命线：第一，坚持自主研发之路；第二，与合作伙伴共生共存；第三，坚决不碰客户数据。这三条里面，最容易被单独拿出来考的就是“不碰客户数据”，因为它和云上安全、客户信任、责任边界都很相关。\n阿里云的整体架构，也可以用一个很简单的方法记：最下面是基础设施层，也就是计算、存储、网络这些基础资源；中间是平台产品层，比如数据库、安全、大数据、AI、云原生这些服务；最上面是行业解决方案层，也就是面向具体业务场景和行业需求的解决方案。所以你可以把它理解成：底层给资源，中间给能力，上层给方案。\n另外，阿里云还有很强的全球化能力，有很多区域和可用区，也有全球 CDN 节点。这个点通常不是让你背数字，而是让你理解它代表了全球部署能力、高可用能力、容灾能力和海外业务支撑能力。\n超短压缩背诵 阿里云成立于 2009 年。\n阿里云是全球领先的云计算和人工智能科技公司。\n阿里云通过在线公共服务方式，提供安全、可靠的计算和数据处理能力。\n阿里云不是单一产品，而是覆盖计算、存储、数据库、网络、安全、大数据、AI、云原生、物联网的完整云平台。\n三条生命线：自主研发、合作共赢、不碰客户数据。\n整体架构：基础设施层、平台产品层、行业解决方案层。\nDay 3｜阿里云综述 资料：1-04-阿里云综述.pdf\n重点整理 阿里云创立于 2009 年，是全球领先的云计算及人工智能科技公司，核心目标是以在线公共服务方式提供安全、可靠的计算与数据处理能力。\n阿里云被视为社会治理、数字生活、经济发展的基础设施。\n发展时间线：2009 成立；2011 首个企业客户上云；2013 飞天单集群超 5K；2015 新加坡数据中心；2016 城市大脑；2017 奥运全球指定云服务商；2020 云钉一体；2021 倚天710；2022 云上冬奥与 CIPU 架构。\n市场地位：2021 年全球公共云 IaaS 份额第三、亚太第一；中国 IaaS+PaaS 市场份额领先。\n全球布局：28 个区域、85 个可用区、覆盖 200+ 国家和地区、2800+ CDN 节点。\n三条生命线：坚持自主研发、与合作伙伴共生共存、坚决不碰客户数据。\n背诵版 2009 成立，2015 出海，2021 倚天710，2022 CIPU + 云上冬奥。\n市场地位：全球第三，亚太第一，中国领先。\n三条生命线：自主研发、伙伴合作、不碰客户数据。\n自测题 阿里云成立于哪一年？\n第一座海外数据中心设立在哪里？\n倚天 710 对应哪一年发布？\n阿里云三条生命线分别是什么？\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-03-acp-day-3-%E9%98%BF%E9%87%8C%E4%BA%91%E7%BB%BC%E8%BF%B0/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：Notion ACP学习笔记\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"acp-day-3阿里云综述\"\u003eACP Day 3｜阿里云综述\u003c/h2\u003e\n\u003ch3 id=\"今日主题\"\u003e今日主题\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eDay 3：阿里云综述\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e对应资料：1-04-阿里云综述.pdf\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"重点整理\"\u003e重点整理\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e阿里云创立于 2009 年，是全球领先的云计算与人工智能科技公司。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e核心定位：通过在线公共服务提供安全、可靠的计算与数据处理能力。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e关键发展脉络：成立 → 对外服务 → 海外布局 → 城市大脑 → 数据库与云原生成熟 → 倚天 710 / 一云多芯 → 冬奥全面上云与 CIPU 架构。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e能力版图覆盖：计算、存储、数据库、网络、安全、大数据、AI、云原生、物联网。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e全球化能力体现为多区域、多可用区和全球 CDN 节点布局。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e三条生命线：坚持自主研发之路、与合作伙伴共生共存、坚决不碰客户数据。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e整体架构可理解为：基础设施层 + 平台产品层 + 行业解决方案层。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"背诵版\"\u003e背诵版\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e阿里云成立于 2009 年。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e阿里云提供安全、可靠的计算和数据处理能力。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e阿里云既有 IaaS，也有数据库、安全、AI、大数据、云原生等平台能力。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e阿里云具备全球化部署能力。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e三条生命线：自主研发、合作共赢、不碰客户数据。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e整体架构：基础设施层、平台产品层、行业解决方案层。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"自测题\"\u003e自测题\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e阿里云成立于哪一年？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e阿里云的三条生命线分别是什么？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e阿里云整体架构可以概括为哪三层？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为什么说阿里云不是单一产品，而是完整平台？\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"口语化背诵版\"\u003e口语化背诵版\u003c/h3\u003e\n\u003cp\u003e阿里云成立于 2009 年，它是全球领先的云计算和人工智能科技公司。它的核心作用，就是通过在线公共服务的方式，给客户提供安全、可靠的计算和数据处理能力。\u003c/p\u003e\n\u003cp\u003e阿里云不是只有一两个产品，它是一整套完整的平台，能力覆盖计算、存储、数据库、网络、安全、大数据、AI、云原生和物联网。所以考试里如果问阿里云是什么，不要只答“卖服务器的”，要答它是完整的云平台和数字化基础设施。\u003c/p\u003e\n\u003cp\u003e阿里云的发展有几个关键节点：2009 年成立，开始研发飞天；之后具备对外服务能力；再往后开始全球化布局；然后在城市大脑、数据库、云原生、芯片这些方向不断增强；后面又有倚天 710、冬奥全面上云、CIPU 新架构这些代表性成果。这里不用死记所有年份，记住“不断从基础云服务走向全球化、平台化、智能化”就行。\u003c/p\u003e\n\u003cp\u003e阿里云还有一个特别重要的考点，就是三条生命线：第一，坚持自主研发之路；第二，与合作伙伴共生共存；第三，坚决不碰客户数据。这三条里面，最容易被单独拿出来考的就是“不碰客户数据”，因为它和云上安全、客户信任、责任边界都很相关。\u003c/p\u003e\n\u003cp\u003e阿里云的整体架构，也可以用一个很简单的方法记：最下面是基础设施层，也就是计算、存储、网络这些基础资源；中间是平台产品层，比如数据库、安全、大数据、AI、云原生这些服务；最上面是行业解决方案层，也就是面向具体业务场景和行业需求的解决方案。所以你可以把它理解成：底层给资源，中间给能力，上层给方案。\u003c/p\u003e\n\u003cp\u003e另外，阿里云还有很强的全球化能力，有很多区域和可用区，也有全球 CDN 节点。这个点通常不是让你背数字，而是让你理解它代表了全球部署能力、高可用能力、容灾能力和海外业务支撑能力。\u003c/p\u003e","tags":"ACP, 阿里云","title":"ACP Day 3 阿里云综述"},{"columns":"python-course","content":"Python 第四课：条件语句与结构化模式匹配 课程概述 本节课我们将学习 Python 中最重要的控制流工具之一——条件语句（Conditional Statements）。条件语句允许程序根据特定条件的真假来选择执行不同的代码路径。我们将详细学习 if、elif（else if 的缩写）和 else 语句的用法，以及条件表达式（三元运算符）的使用。此外，本课还将重点介绍 Python 3.10 引入的革命性新特性——match-case 结构化模式匹配（Structural Pattern Matching）。match-case 是 Python 历史上最重要的语法特性之一，它借鉴自函数式编程语言如 Haskell 和 OCaml，允许开发者以声明式的方式对值、结构和类型进行匹配和解析。本课程所有内容基于 Python 3.11 编写，涵盖了 Python 3.10 和 Python 3.11 中 match-case 的最新改进。\n条件语句是编程的基础构建块，几乎所有程序都需要根据不同的条件做出不同的决策。在 Python 中，条件语句不仅支持简单的布尔判断，还支持复杂的表达式、多重条件判断，以及与循环、异常处理等控制流工具的组合使用。Python 的条件语句设计得非常优雅，使用缩进而不是大括号来划分代码块，这使得代码既简洁又具有良好的可读性。\nif 语句基础 最基本的 if 语句 if 语句是最简单的条件语句，其基本语法如下：\n# 基本语法 if 条件: 条件为真时执行的代码 # 示例 age = 20 if age \u0026gt;= 18: print(\u0026#34;你已经成年了！\u0026#34;) print(\u0026#34;可以观看这部电影\u0026#34;) print(\u0026#34;程序继续执行...\u0026#34;) 在 Python 中，if 语句后的条件表达式不需要使用括号（虽然技术上可以使用括号），条件的真假由 Python 的布尔规则决定。如果条件为真（True），则执行缩进后的代码块；如果为假（False），则跳过该代码块。\n条件表达式与布尔值 在 Python 中，以下值在布尔上下文中被视为假（False）：\n布尔值 False 整数 0（包括 0、0L、0.0、0j） 空字符串 '' 和空字节串 b'' 空列表 []、空元组 ()、空字典 {}、空集合 set() None 所有其他值都被视为真（True）。\n# 各种条件测试 print(\u0026#34;测试各种值的布尔值：\u0026#34;) print(f\u0026#34;bool(0) = {bool(0)}\u0026#34;) print(f\u0026#34;bool(1) = {bool(1)}\u0026#34;) print(f\u0026#34;bool(\u0026#39;\u0026#39;) = {bool(\u0026#39;\u0026#39;)}\u0026#34;) print(f\u0026#34;bool(\u0026#39;hello\u0026#39;) = {bool(\u0026#39;hello\u0026#39;)}\u0026#34;) print(f\u0026#34;bool([]) = {bool([])}\u0026#34;) print(f\u0026#34;bool([1,2]) = {bool([1,2])}\u0026#34;) print(f\u0026#34;bool(None) = {bool(None)}\u0026#34;) print(f\u0026#34;bool({}) = {bool({})}\u0026#34;) # 字符串非空判断 username = \u0026#34;张三\u0026#34; if username: print(f\u0026#34;用户名：{username}\u0026#34;) if-else 语句 else 子句在 if 条件为假时执行：\nage = 15 if age \u0026gt;= 18: print(\u0026#34;你已经成年了\u0026#34;) else: print(\u0026#34;你还未成年\u0026#34;) print(\u0026#34;程序结束\u0026#34;) if-elif-else 链 当需要判断多个条件时，可以使用 elif（else if 的缩写）：\nscore = 85 if score \u0026gt;= 90: grade = \u0026#34;A\u0026#34; print(\u0026#34;优秀！\u0026#34;) elif score \u0026gt;= 80: grade = \u0026#34;B\u0026#34; print(\u0026#34;良好！\u0026#34;) elif score \u0026gt;= 70: grade = \u0026#34;C\u0026#34; print(\u0026#34;中等！\u0026#34;) elif score \u0026gt;= 60: grade = \u0026#34;D\u0026#34; print(\u0026#34;及格\u0026#34;) else: grade = \u0026#34;F\u0026#34; print(\u0026#34;需要继续努力\u0026#34;) print(f\u0026#34;你的等级是：{grade}\u0026#34;) 多重条件判断 一个 if 语句可以包含多个 elif 子句：\nmonth = 6 if month == 1: print(\u0026#34;一月\u0026#34;) elif month == 2: print(\u0026#34;二月\u0026#34;) elif month == 3: print(\u0026#34;三月\u0026#34;) elif month == 4: print(\u0026#34;四月\u0026#34;) elif month == 5: print(\u0026#34;五月\u0026#34;) elif month == 6: print(\u0026#34;六月\u0026#34;) elif month == 7: print(\u0026#34;七月\u0026#34;) elif month == 8: print(\u0026#34;八月\u0026#34;) elif month == 9: print(\u0026#34;九月\u0026#34;) elif month == 10: print(\u0026#34;十月\u0026#34;) elif month == 11: print(\u0026#34;十一月\u0026#34;) elif month == 12: print(\u0026#34;十二月\u0026#34;) else: print(\u0026#34;无效的月份\u0026#34;) 条件表达式（三元运算符） Python 提供了一个简洁的单行条件表达式，语法为：value_if_true if condition else value_if_false\n# 基本语法 age = 20 status = \u0026#34;成年\u0026#34; if age \u0026gt;= 18 else \u0026#34;未成年\u0026#34; print(f\u0026#34;status = {status}\u0026#34;) # 在表达式中使用 x, y = 10, 20 max_val = x if x \u0026gt; y else y print(f\u0026#34;max_val = {max_val}\u0026#34;) # 嵌套条件表达式（不推荐过于嵌套） score = 85 grade = \u0026#34;A\u0026#34; if score \u0026gt;= 90 else \u0026#34;B\u0026#34; if score \u0026gt;= 80 else \u0026#34;C\u0026#34; if score \u0026gt;= 70 else \u0026#34;D\u0026#34; print(f\u0026#34;grade = {grade}\u0026#34;) # 条件表达式的实际应用 def get_tax_rate(income): \u0026#34;\u0026#34;\u0026#34;根据收入计算税率\u0026#34;\u0026#34;\u0026#34; return ( 0.45 if income \u0026gt; 1000000 else 0.35 if income \u0026gt; 500000 else 0.25 if income \u0026gt; 200000 else 0.15 if income \u0026gt; 100000 else 0.05 ) for income in [50000, 150000, 300000, 700000, 2000000]: rate = get_tax_rate(income) print(f\u0026#34;收入 {income:,} 元，税率 {rate:.0%}，税额 {income * rate:,.0f} 元\u0026#34;) 逻辑运算符在条件中的应用 and 和 or 的组合使用 # and 组合多个条件 age = 25 income = 50000 if age \u0026gt;= 18 and income \u0026gt; 30000: print(\u0026#34;符合申请条件\u0026#34;) # or 组合多个条件 day = \u0026#34;周六\u0026#34; is_holiday = True if day == \u0026#34;周六\u0026#34; or day == \u0026#34;周日\u0026#34; or is_holiday: print(\u0026#34;今天休息\u0026#34;) # 复杂的条件组合 age = 30 has_job = True has_savings = False credit_score = 750 if (age \u0026gt;= 21 and age \u0026lt;= 65) and (has_job or has_savings) and credit_score \u0026gt;= 700: print(\u0026#34;贷款申请通过\u0026#34;) else: print(\u0026#34;贷款申请被拒绝\u0026#34;) 使用括号明确优先级 # 没有括号时的优先级 if age \u0026gt; 18 and not has_license or is_supervised: pass # 使用括号明确优先级 if (age \u0026gt; 18 and not has_license) or is_supervised: pass pass 语句 pass 是一个空操作语句，当语法上需要一条语句但程序不需要任何操作时使用：\n# 使用 pass 占位 if condition: pass # 稍后实现 else: print(\u0026#34;条件为假\u0026#34;) # pass 常用于定义空函数或空类 class EmptyClass: pass def TODO(): pass match-case 结构化模式匹配 match-case 是 Python 3.10 引入的最重要的新语法特性。它的设计理念来自函数式编程语言中的模式匹配（Pattern Matching），允许你将一个值与一系列模式（patterns）进行比较，并在匹配成功时执行相应的代码。match-case 不仅可以匹配字面值，还可以匹配复杂的数据结构、序列、字典，甚至可以绑定变量。\nmatch-case 的基本语法 # 基本语法 match subject: case pattern1: # 匹配 pattern1 时执行的代码 case pattern2: # 匹配 pattern2 时执行的代码 case _: # 默认情况（相当于 else） # 示例：简单的 HTTP 方法路由 def handle_request(method): match method: case \u0026#34;GET\u0026#34;: return \u0026#34;获取资源\u0026#34; case \u0026#34;POST\u0026#34;: return \u0026#34;创建资源\u0026#34; case \u0026#34;PUT\u0026#34;: return \u0026#34;更新资源\u0026#34; case \u0026#34;DELETE\u0026#34;: return \u0026#34;删除资源\u0026#34; case _: return \u0026#34;未知方法\u0026#34; print(handle_request(\u0026#34;GET\u0026#34;)) # 获取资源 print(handle_request(\u0026#34;POST\u0026#34;)) # 创建资源 print(handle_request(\u0026#34;PATCH\u0026#34;)) # 未知方法 匹配字面值 # 匹配字符串字面值 def get_day_type(day): match day: case \u0026#34;Saturday\u0026#34; | \u0026#34;Sunday\u0026#34;: # 使用 | 连接多个字面值（OR 模式） return \u0026#34;周末\u0026#34; case \u0026#34;Monday\u0026#34; | \u0026#34;Tuesday\u0026#34; | \u0026#34;Wednesday\u0026#34; | \u0026#34;Thursday\u0026#34; | \u0026#34;Friday\u0026#34;: return \u0026#34;工作日\u0026#34; case _: return \u0026#34;无效日期\u0026#34; print(get_day_type(\u0026#34;Saturday\u0026#34;)) # 周末 print(get_day_type(\u0026#34;Monday\u0026#34;)) # 工作日 print(get_day_type(\u0026#34;随便输入\u0026#34;)) # 无效日期 # 匹配数字 def get_grade_message(score): match score: case 100: return \u0026#34;满分！太棒了！\u0026#34; case 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99: return \u0026#34;优秀！\u0026#34; case 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89: return \u0026#34;良好！\u0026#34; case _ if 60 \u0026lt;= score \u0026lt; 80: return \u0026#34;及格\u0026#34; case _ if 0 \u0026lt;= score \u0026lt; 60: return \u0026#34;需要努力\u0026#34; case _: return \u0026#34;无效分数\u0026#34; print(get_grade_message(100)) # 满分！太棒了！ print(get_grade_message(85)) # 良好！ print(get_grade_message(65)) # 及格 捕获变量（Capture Patterns） 在 match-case 中，你可以使用变量名捕获匹配的值：\n# 捕获变量 def describe_point(point): match point: case (0, 0): return \u0026#34;原点\u0026#34; case (x, 0): return f\u0026#34;X 轴上的点，x = {x}\u0026#34; case (0, y): return f\u0026#34;Y 轴上的点，y = {y}\u0026#34; case (x, y): return f\u0026#34;平面上的点，x = {x}, y = {y}\u0026#34; case _: return \u0026#34;无效坐标\u0026#34; print(describe_point((0, 0))) # 原点 print(describe_point((5, 0))) # X 轴上的点，x = 5 print(describe_point((0, -3))) # Y 轴上的点，y = -3 print(describe_point((3, 4))) # 平面上的点，x = 3, y = 4 通配符模式（Wildcard Pattern） 使用下划线 _ 作为通配符，匹配任意值但不绑定到变量：\ndef process_message(msg_type, data): match (msg_type, data): case (\u0026#34;text\u0026#34;, _): return \u0026#34;文本消息\u0026#34; case (\u0026#34;image\u0026#34;, _): return \u0026#34;图片消息\u0026#34; case (\u0026#34;file\u0026#34;, _): return \u0026#34;文件消息\u0026#34; case _: return \u0026#34;未知消息类型\u0026#34; print(process_message((\u0026#34;text\u0026#34;, \u0026#34;Hello\u0026#34;))) # 文本消息 print(process_message((\u0026#34;image\u0026#34;, \u0026#34;photo.jpg\u0026#34;))) # 图片消息 序列模式（Sequence Patterns） # 匹配列表或元组 def describe_list(items): match items: case []: return \u0026#34;空列表\u0026#34; case [x]: return f\u0026#34;只有一个元素：{x}\u0026#34; case [x, y]: return f\u0026#34;两个元素：{x} 和 {y}\u0026#34; case [x, y, z]: return f\u0026#34;三个元素：{x}、{y} 和 {z}\u0026#34; case [x, *rest]: # *pattern 捕获剩余元素 return f\u0026#34;第一个元素是 {x}，还有 {len(rest)} 个其他元素\u0026#34; case _: return \u0026#34;更多元素\u0026#34; print(describe_list([])) # 空列表 print(describe_list([1])) # 只有一个元素：1 print(describe_list([1, 2])) # 两个元素：1 和 2 print(describe_list([1, 2, 3, 4, 5])) # 第一个元素是 1，还有 4 个其他元素 # 匹配固定长度的序列 def parse_command(cmd): match cmd.split(): case [\u0026#34;ls\u0026#34;]: return \u0026#34;列出文件\u0026#34; case [\u0026#34;ls\u0026#34;, *files]: return f\u0026#34;列出指定文件：{files}\u0026#34; case [\u0026#34;cd\u0026#34;, dir_name]: return f\u0026#34;切换到目录：{dir_name}\u0026#34; case [\u0026#34;rm\u0026#34;, *files]: return f\u0026#34;删除文件：{files}\u0026#34; case _: return \u0026#34;未知命令\u0026#34; print(parse_command(\u0026#34;ls\u0026#34;)) print(parse_command(\u0026#34;ls file1.txt file2.txt\u0026#34;)) print(parse_command(\u0026#34;cd /home\u0026#34;)) print(parse_command(\u0026#34;rm a.txt b.txt c.txt\u0026#34;)) 字典模式（Mapping Patterns） # 匹配字典（映射） def describe_config(config): match config: case {\u0026#34;host\u0026#34;: host, \u0026#34;port\u0026#34;: port}: return f\u0026#34;主机：{host}，端口：{port}\u0026#34; case {\u0026#34;host\u0026#34;: host}: return f\u0026#34;主机：{host}，使用默认端口\u0026#34; case {\u0026#34;port\u0026#34;: port}: return f\u0026#34;使用默认主机，端口：{port}\u0026#34; case {}: return \u0026#34;空配置\u0026#34; case _: return \u0026#34;无效配置\u0026#34; print(describe_config({\u0026#34;host\u0026#34;: \u0026#34;localhost\u0026#34;, \u0026#34;port\u0026#34;: 8080})) print(describe_config({\u0026#34;host\u0026#34;: \u0026#34;example.com\u0026#34;})) print(describe_config({\u0026#34;port\u0026#34;: 3000})) print(describe_config({})) # Python 3.11 中字典模式支持 **rest 捕获 def parse_http_headers(headers): match headers: case {\u0026#34;Content-Type\u0026#34;: ct, \u0026#34;Content-Length\u0026#34;: cl, **rest}: return f\u0026#34;内容类型：{ct}，长度：{cl}，其他头：{list(rest.keys())}\u0026#34; case {\u0026#34;Content-Type\u0026#34;: ct, **rest}: return f\u0026#34;内容类型：{ct}，其他头：{list(rest.keys())}\u0026#34; case _: return \u0026#34;无内容相关信息\u0026#34; headers1 = {\u0026#34;Content-Type\u0026#34;: \u0026#34;text/html\u0026#34;, \u0026#34;Content-Length\u0026#34;: 1234, \u0026#34;X-Custom\u0026#34;: \u0026#34;value\u0026#34;} headers2 = {\u0026#34;Content-Type\u0026#34;: \u0026#34;application/json\u0026#34;} print(parse_http_headers(headers1)) print(parse_http_headers(headers2)) 类模式（Class Patterns） # 匹配类实例的属性 from dataclasses import dataclass @dataclass class Point: x: int y: int @dataclass class Circle: center: Point radius: int def describe_shape(shape): match shape: case Point(0, 0): return \u0026#34;原点\u0026#34; case Point(x, 0): return f\u0026#34;X轴上的点 (x={x})\u0026#34; case Point(0, y): return f\u0026#34;Y轴上的点 (y={y})\u0026#34; case Point(x, y): return f\u0026#34;平面点 (x={x}, y={y})\u0026#34; case Circle(Point(x, y), r): return f\u0026#34;圆心在({x},{y})，半径为{r}的圆\u0026#34; case _: return \u0026#34;未知形状\u0026#34; p1 = Point(0, 0) p2 = Point(5, 0) c1 = Circle(Point(1, 2), 10) print(describe_shape(p1)) # 原点 print(describe_shape(p2)) # X轴上的点 (x=5) print(describe_shape(c1)) # 圆心在(1,2)，半径为10的圆 带有守卫条件（Guard Clauses） 在 match-case 中，可以使用 if 语句添加额外的条件（称为守卫）：\n# 守卫条件 def classify_number(n): match n: case x if x \u0026lt; 0: return \u0026#34;负数\u0026#34; case 0: return \u0026#34;零\u0026#34; case x if x % 2 == 0: return f\u0026#34;正偶数 ({x})\u0026#34; case x if x % 2 != 0: return f\u0026#34;正奇数 ({x})\u0026#34; print(classify_number(-5)) # 负数 print(classify_number(0)) # 零 print(classify_number(4)) # 正偶数 (4) print(classify_number(7)) # 正奇数 (7) # 复杂的多条件匹配 def process_api_response(response): match response: case {\u0026#34;status\u0026#34;: 200, \u0026#34;data\u0026#34;: data} if len(data) \u0026gt; 0: return f\u0026#34;成功返回 {len(data)} 条数据\u0026#34; case {\u0026#34;status\u0026#34;: 200, \u0026#34;data\u0026#34;: []}: return \u0026#34;成功但无数据\u0026#34; case {\u0026#34;status\u0026#34;: 400, \u0026#34;error\u0026#34;: error_msg}: return f\u0026#34;客户端错误：{error_msg}\u0026#34; case {\u0026#34;status\u0026#34;: 401 | 403}: return \u0026#34;认证/授权失败\u0026#34; case {\u0026#34;status\u0026#34;: 500, \u0026#34;error\u0026#34;: err}: return f\u0026#34;服务器错误：{err}\u0026#34; case {\u0026#34;status\u0026#34;: s} if 400 \u0026lt;= s \u0026lt; 600: return f\u0026#34;HTTP错误：{s}\u0026#34; case _: return \u0026#34;无效响应\u0026#34; print(process_api_response({\u0026#34;status\u0026#34;: 200, \u0026#34;data\u0026#34;: [1, 2, 3]})) print(process_api_response({\u0026#34;status\u0026#34;: 400, \u0026#34;error\u0026#34;: \u0026#34;Bad Request\u0026#34;})) match-case 的实际应用场景 应用一：JSON 解析 def parse_json_value(value): \u0026#34;\u0026#34;\u0026#34;简化的 JSON 值解析\u0026#34;\u0026#34;\u0026#34; match value: case None: return \u0026#34;null\u0026#34; case bool() as b: return f\u0026#34;布尔值: {b}\u0026#34; case int() | float() as n: return f\u0026#34;数字: {n}\u0026#34; case str() as s: return f\u0026#34;字符串: {s}\u0026#34; case list() as items: return f\u0026#34;数组[{len(items)}项]\u0026#34; case dict() as obj: return f\u0026#34;对象[{len(obj)}键]\u0026#34; case _: return \u0026#34;未知类型\u0026#34; data = [ None, True, 42, 3.14, \u0026#34;hello\u0026#34;, [1, 2, 3], {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25} ] for item in data: print(f\u0026#34;{str(item):\u0026lt;20} =\u0026gt; {parse_json_value(item)}\u0026#34;) 应用二：命令处理器 def execute_command(command, args): \u0026#34;\u0026#34;\u0026#34;简化的命令处理器\u0026#34;\u0026#34;\u0026#34; match (command, args): case (\u0026#34;quit\u0026#34;,): return \u0026#34;退出程序\u0026#34; case (\u0026#34;help\u0026#34;,): return \u0026#34;显示帮助信息\u0026#34; case (\u0026#34;echo\u0026#34;, [*msgs]): return \u0026#34; \u0026#34;.join(msgs) case (\u0026#34;repeat\u0026#34;, [n, msg]) if n.isdigit(): return msg * int(n) case (\u0026#34;print\u0026#34;, {\u0026#34;text\u0026#34;: text}): return text case (\u0026#34;print\u0026#34;, {\u0026#34;text\u0026#34;: text, \u0026#34;count\u0026#34;: c}) if c.isdigit(): return text * int(c) case (cmd, _) if cmd.startswith(\u0026#34;:\u0026#34;): return f\u0026#34;元命令: {cmd}\u0026#34; case _: return f\u0026#34;未知命令: {command}\u0026#34; print(execute_command(\u0026#34;quit\u0026#34;, [])) print(execute_command(\u0026#34;echo\u0026#34;, [\u0026#34;Hello\u0026#34;, \u0026#34;World\u0026#34;])) print(execute_command(\u0026#34;repeat\u0026#34;, [\u0026#34;3\u0026#34;, \u0026#34;Hi\u0026#34;])) print(execute_command(\u0026#34;print\u0026#34;, {\u0026#34;text\u0026#34;: \u0026#34;Hi\u0026#34;, \u0026#34;count\u0026#34;: \u0026#34;2\u0026#34;})) 应用三：状态机 from enum import Enum from typing import Optional class State(Enum): IDLE = \u0026#34;idle\u0026#34; RUNNING = \u0026#34;running\u0026#34; PAUSED = \u0026#34;paused\u0026#34; STOPPED = \u0026#34;stopped\u0026#34; class Event(Enum): START = \u0026#34;start\u0026#34; PAUSE = \u0026#34;pause\u0026#34; RESUME = \u0026#34;resume\u0026#34; STOP = \u0026#34;stop\u0026#34; def transition(state: State, event: Event) -\u0026gt; Optional[State]: \u0026#34;\u0026#34;\u0026#34;有限状态机的状态转换\u0026#34;\u0026#34;\u0026#34; match (state, event): case (State.IDLE, Event.START): return State.RUNNING case (State.RUNNING, Event.PAUSE): return State.PAUSED case (State.PAUSED, Event.RESUME): return State.RUNNING case (State.RUNNING | State.PAUSED, Event.STOP): return State.STOPPED case (State.STOPPED, Event.START): return State.RUNNING case _: return None # 无效转换 # 测试状态机 current = State.IDLE print(f\u0026#34;初始状态：{current.value}\u0026#34;) transitions = [ (Event.START, State.RUNNING), (Event.PAUSE, State.PAUSED), (Event.RESUME, State.RUNNING), (Event.STOP, State.STOPPED), ] for event, expected in transitions: current = transition(current, event) print(f\u0026#34;事件 {event.value} =\u0026gt; {current.value if current else \u0026#39;无效转换\u0026#39;}\u0026#34;) match-case vs if-elif-else 什么时候应该使用 match-case 而不是 if-elif-else？\n# if-elif-else 适合简单的值比较 def route_http_method_if(method): if method == \u0026#34;GET\u0026#34;: return \u0026#34;获取\u0026#34; elif method == \u0026#34;POST\u0026#34;: return \u0026#34;创建\u0026#34; elif method == \u0026#34;PUT\u0026#34;: return \u0026#34;更新\u0026#34; elif method == \u0026#34;DELETE\u0026#34;: return \u0026#34;删除\u0026#34; else: return \u0026#34;未知\u0026#34; # match-case 适合： # 1. 需要解构复杂数据结构时 def route_http_method_match(method): match method: case \u0026#34;GET\u0026#34;: return \u0026#34;获取\u0026#34; case \u0026#34;POST\u0026#34;: return \u0026#34;创建\u0026#34; case \u0026#34;PUT\u0026#34;: return \u0026#34;更新\u0026#34; case \u0026#34;DELETE\u0026#34;: return \u0026#34;删除\u0026#34; case _: return \u0026#34;未知\u0026#34; # 2. 需要匹配多种值的联合时 def validate_input_if(value): if value in (0, 1, 2): return \u0026#34;小数字\u0026#34; elif value in range(3, 10): return \u0026#34;中等数字\u0026#34; else: return \u0026#34;大数字\u0026#34; def validate_input_match(value): match value: case 0 | 1 | 2: return \u0026#34;小数字\u0026#34; case 3 | 4 | 5 | 6 | 7 | 8 | 9: return \u0026#34;中等数字\u0026#34; case _: return \u0026#34;大数字\u0026#34; # 3. 需要解构元组或序列时 def process_point_if(point): if len(point) \u0026gt;= 2: x, y = point[0], point[1] return f\u0026#34;x={x}, y={y}\u0026#34; return \u0026#34;无效点\u0026#34; def process_point_match(point): match point: case [x, y, *rest]: return f\u0026#34;x={x}, y={y}, extra={rest}\u0026#34; case [x, y]: return f\u0026#34;x={x}, y={y}\u0026#34; case _: return \u0026#34;无效点\u0026#34; Python 3.11 中 match-case 的改进 Python 3.11 对 match-case 做了一些改进，包括更好的错误信息和性能优化：\n# Python 3.11 中 match-case 的特性 # 1. 更清晰的错误信息 # 当 case 模式有语法错误时，Python 3.11 会给出更精确的错误位置 # 2. 性能优化 # Python 3.11 的字节码编译器对 match-case 进行了优化 # 3. 支持 AS 模式（用于给模式绑定别名） def process(data): match data: case [x, y] as pair: print(f\u0026#34;pair = {pair}, x = {x}, y = {y}\u0026#34;) case _: print(\u0026#34;不是长度为2的序列\u0026#34;) process([1, 2]) 综合练习题 练习一：计算器程序 \u0026#34;\u0026#34;\u0026#34; 计算器程序 练习 if-elif-else 和 match-case 的结合使用 \u0026#34;\u0026#34;\u0026#34; def calculator_if(operation, a, b): \u0026#34;\u0026#34;\u0026#34;使用 if-elif-else 的计算器\u0026#34;\u0026#34;\u0026#34; if operation == \u0026#34;add\u0026#34;: return a + b elif operation == \u0026#34;subtract\u0026#34;: return a - b elif operation == \u0026#34;multiply\u0026#34;: return a * b elif operation == \u0026#34;divide\u0026#34;: if b == 0: return \u0026#34;错误：除数不能为零\u0026#34; return a / b elif operation == \u0026#34;power\u0026#34;: return a ** b elif operation == \u0026#34;mod\u0026#34;: if b == 0: return \u0026#34;错误：除数不能为零\u0026#34; return a % b else: return f\u0026#34;未知操作：{operation}\u0026#34; def calculator_match(operation, a, b): \u0026#34;\u0026#34;\u0026#34;使用 match-case 的计算器\u0026#34;\u0026#34;\u0026#34; match operation: case \u0026#34;add\u0026#34;: return a + b case \u0026#34;subtract\u0026#34;: return a - b case \u0026#34;multiply\u0026#34;: return a * b case \u0026#34;divide\u0026#34; if b != 0: return a / b case \u0026#34;divide\u0026#34;: return \u0026#34;错误：除数不能为零\u0026#34; case \u0026#34;power\u0026#34;: return a ** b case \u0026#34;mod\u0026#34; if b != 0: return a % b case \u0026#34;mod\u0026#34;: return \u0026#34;错误：除数不能为零\u0026#34; case _: return f\u0026#34;未知操作：{operation}\u0026#34; # 测试两种实现 operations = [\u0026#34;add\u0026#34;, \u0026#34;subtract\u0026#34;, \u0026#34;multiply\u0026#34;, \u0026#34;divide\u0026#34;, \u0026#34;power\u0026#34;, \u0026#34;mod\u0026#34;] a, b = 10, 3 print(\u0026#34;=\u0026#34; * 60) print(\u0026#34; 计算器测试\u0026#34;) print(f\u0026#34; {a} 和 {b}\u0026#34;) print(\u0026#34;=\u0026#34; * 60) print(f\u0026#34;{\u0026#39;操作\u0026#39;:\u0026lt;12} {\u0026#39;if-elif\u0026#39;:\u0026lt;15} {\u0026#39;match-case\u0026#39;:\u0026lt;15}\u0026#34;) print(\u0026#34;-\u0026#34; * 60) for op in operations: result_if = calculator_if(op, a, b) result_match = calculator_match(op, a, b) print(f\u0026#34;{op:\u0026lt;12} {str(result_if):\u0026lt;15} {str(result_match):\u0026lt;15}\u0026#34;) 练习二：学生成绩管理系统 \u0026#34;\u0026#34;\u0026#34; 学生成绩管理系统 练习 match-case 处理复杂数据结构 \u0026#34;\u0026#34;\u0026#34; from dataclasses import dataclass from typing import Optional @dataclass class Student: name: str student_id: str scores: dict[str, int] def get_student_report(student: Student, course: Optional[str] = None): \u0026#34;\u0026#34;\u0026#34;生成学生成绩报告\u0026#34;\u0026#34;\u0026#34; match (course, student.scores): case (None, {}): return f\u0026#34;{student.name}（学号：{student.id}）：暂无成绩记录\u0026#34; case (None, scores): total = sum(scores.values()) count = len(scores) avg = total / count if count \u0026gt; 0 else 0 return ( f\u0026#34;{student.name}（学号：{student.student_id}）\\n\u0026#34; f\u0026#34; 课程数：{count}\\n\u0026#34; f\u0026#34; 总分：{total}\\n\u0026#34; f\u0026#34; 平均分：{avg:.1f}\u0026#34; ) case (c, {c: score, **rest}): grade = ( \u0026#34;A+\u0026#34; if score \u0026gt;= 95 else \u0026#34;A\u0026#34; if score \u0026gt;= 90 else \u0026#34;B+\u0026#34; if score \u0026gt;= 85 else \u0026#34;B\u0026#34; if score \u0026gt;= 80 else \u0026#34;C+\u0026#34; if score \u0026gt;= 75 else \u0026#34;C\u0026#34; if score \u0026gt;= 70 else \u0026#34;D\u0026#34; if score \u0026gt;= 60 else \u0026#34;F\u0026#34; ) return f\u0026#34;{student.name} - {c}：{score}分（{grade}）\u0026#34; case (c, _): return f\u0026#34;{student.name} 未选修 {c} 课程\u0026#34; # 测试数据 student1 = Student(\u0026#34;张三\u0026#34;, \u0026#34;2023001\u0026#34;, {\u0026#34;Python\u0026#34;: 92, \u0026#34;数学\u0026#34;: 88, \u0026#34;英语\u0026#34;: 85}) student2 = Student(\u0026#34;李四\u0026#34;, \u0026#34;2023002\u0026#34;, {}) print(get_student_report(student1)) print() print(get_student_report(student1, \u0026#34;Python\u0026#34;)) print() print(get_student_report(student2)) 练习三：URL 路由解析 \u0026#34;\u0026#34;\u0026#34; URL 路由解析器 练习 match-case 解析复杂字符串模式 \u0026#34;\u0026#34;\u0026#34; def parse_url(url): \u0026#34;\u0026#34;\u0026#34;解析 URL 并返回路由信息\u0026#34;\u0026#34;\u0026#34; # 移除协议前缀 match url.removeprefix(\u0026#34;https://\u0026#34;).removeprefix(\u0026#34;http://\u0026#34;).split(\u0026#34;/\u0026#34;, 2): case [host]: return {\u0026#34;type\u0026#34;: \u0026#34;domain\u0026#34;, \u0026#34;host\u0026#34;: host} case [host, path] if \u0026#34;?\u0026#34; in path: path, query = path.split(\u0026#34;?\u0026#34;, 1) return {\u0026#34;type\u0026#34;: \u0026#34;page\u0026#34;, \u0026#34;host\u0026#34;: host, \u0026#34;path\u0026#34;: path, \u0026#34;query\u0026#34;: query} case [host, path]: return {\u0026#34;type\u0026#34;: \u0026#34;page\u0026#34;, \u0026#34;host\u0026#34;: host, \u0026#34;path\u0026#34;: path} case _: return {\u0026#34;type\u0026#34;: \u0026#34;unknown\u0026#34;} urls = [ \u0026#34;https://example.com\u0026#34;, \u0026#34;https://example.com/api/users\u0026#34;, \u0026#34;https://example.com/search?q=python\u0026#34;, \u0026#34;ftp://invalid.com/file\u0026#34;, ] print(\u0026#34;URL 路由解析测试\u0026#34;) print(\u0026#34;=\u0026#34; * 60) for url in urls: result = parse_url(url) print(f\u0026#34;URL: {url}\u0026#34;) print(f\u0026#34;解析结果: {result}\u0026#34;) print() Python 3.10 match-case 的限制 需要注意的是，Python 的 match-case 与真正的函数式语言模式匹配有一些区别：\n# 1. match-case 不能直接用于赋值 # 这是无效的： # match value: # case x = 10: # 错误 # pass # 正确做法： match value: case 10 as x: # 使用 as 捕获 print(f\u0026#34;x = {x}\u0026#34;) # 2. match-case 是语句，不是表达式 # 它不能直接返回值（但可以用作函数体） # 这是无效的： # result = match x: # case 1: 1 # case 2: 2 # 正确做法： def get_value(x): match x: case 1: return 1 case 2: return 2 常见错误与调试 错误一：缺少冒号 # 错误：if 条件后缺少冒号 # if x \u0026gt; 0 # print(\u0026#34;正数\u0026#34;) # 正确： if x \u0026gt; 0: print(\u0026#34;正数\u0026#34;) 错误二：Match-case 字面值重复 # 在 Python 3.10 中，同一个值不能出现多次 # 这是无效的： # match x: # case 1 | 1: # 重复的字面值 # pass # 正确： match x: case 1: pass 错误三：守卫条件中的变量作用域 # 守卫条件中的变量绑定问题 def check(x): match x: case y if y \u0026gt; 0: # y 是在守卫中绑定的 return f\u0026#34;正数 y={y}\u0026#34; case y: # 这里的 y 不会被守卫中的绑定影响 return f\u0026#34;非正数 y={y}\u0026#34; # 注意：每个 case 都有自己的作用域 错误四：类型注解与 match-case 的混淆 from typing import Union def process_value(value: Union[int, str, list]): # 这不是类型注解，而是 match-case 模式 match value: case int() as n: return f\u0026#34;整数: {n}\u0026#34; case str() as s: return f\u0026#34;字符串: {s}\u0026#34; case list() as items: return f\u0026#34;列表: {items}\u0026#34; 本章小结 今天我们学习了以下核心内容：\nif 语句基础：条件判断、布尔值、缩进规则。 if-elif-else 链：多重条件判断、嵌套条件。 条件表达式：三元运算符、嵌套条件表达式。 逻辑运算符组合：and、or、not 的组合使用。 pass 语句：空操作占位符的使用。 match-case 结构化模式匹配： 基本语法和字面值匹配 捕获变量（Capture Patterns） 序列模式（List/Tuple Patterns） 字典模式（Mapping Patterns） 类模式（Class Patterns） 守卫条件（Guard Clauses） match-case vs if-elif-else：何时使用哪种方式。 Python 3.11 中的改进：更好的错误信息和性能优化。 下一节课我们将学习 Python 的逻辑运算符（and、or、not）、短路求值机制以及链式比较的深入理解，敬请期待！\n延伸阅读 PEP 634 - Structural Pattern Matching Specification PEP 635 - Structural Pattern Matching: Motivation and Rationale PEP 636 - Structural Pattern Matching: Tutorial Python Official Documentation - match statement Python 3.10 What\u0026rsquo;s New - Pattern Matching ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-04-if-elif-else-match-case/","summary":"\u003ch1 id=\"python-第四课条件语句与结构化模式匹配\"\u003ePython 第四课：条件语句与结构化模式匹配\u003c/h1\u003e\n\u003ch2 id=\"课程概述\"\u003e课程概述\u003c/h2\u003e\n\u003cp\u003e本节课我们将学习 Python 中最重要的控制流工具之一——条件语句（Conditional Statements）。条件语句允许程序根据特定条件的真假来选择执行不同的代码路径。我们将详细学习 \u003ccode\u003eif\u003c/code\u003e、\u003ccode\u003eelif\u003c/code\u003e（else if 的缩写）和 \u003ccode\u003eelse\u003c/code\u003e 语句的用法，以及条件表达式（三元运算符）的使用。此外，本课还将重点介绍 Python 3.10 引入的革命性新特性——\u003ccode\u003ematch-case\u003c/code\u003e 结构化模式匹配（Structural Pattern Matching）。match-case 是 Python 历史上最重要的语法特性之一，它借鉴自函数式编程语言如 Haskell 和 OCaml，允许开发者以声明式的方式对值、结构和类型进行匹配和解析。本课程所有内容基于 \u003cstrong\u003ePython 3.11\u003c/strong\u003e 编写，涵盖了 Python 3.10 和 Python 3.11 中 match-case 的最新改进。\u003c/p\u003e\n\u003cp\u003e条件语句是编程的基础构建块，几乎所有程序都需要根据不同的条件做出不同的决策。在 Python 中，条件语句不仅支持简单的布尔判断，还支持复杂的表达式、多重条件判断，以及与循环、异常处理等控制流工具的组合使用。Python 的条件语句设计得非常优雅，使用缩进而不是大括号来划分代码块，这使得代码既简洁又具有良好的可读性。\u003c/p\u003e\n\u003ch2 id=\"if-语句基础\"\u003eif 语句基础\u003c/h2\u003e\n\u003ch3 id=\"最基本的-if-语句\"\u003e最基本的 if 语句\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003eif\u003c/code\u003e 语句是最简单的条件语句，其基本语法如下：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 基本语法\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e 条件:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    条件为真时执行的代码\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eage \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e age \u003cspan style=\"color:#f92672\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e18\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;你已经成年了！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;可以观看这部电影\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;程序继续执行...\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e在 Python 中，\u003ccode\u003eif\u003c/code\u003e 语句后的条件表达式不需要使用括号（虽然技术上可以使用括号），条件的真假由 Python 的布尔规则决定。如果条件为真（True），则执行缩进后的代码块；如果为假（False），则跳过该代码块。\u003c/p\u003e","tags":"Python, 编程","title":"Python 第四课：条件语句与结构化模式匹配"},{"columns":"acp-course","content":" 来源：Notion ACP学习笔记\nACP Day 4｜网络架构 + IP编址 今日主题 Day 4：网络架构 + IP编址\n对应资料：2-01-网络架构和网络设备详解 (1).pdf、2-02-IP编址 (1).pdf\n重点整理 最简单的网络由两个终端和一条能够承载数据传输的物理介质组成。\n数据通信网络由路由器、交换机、防火墙、无线控制器、无线接入点以及主机、服务器等设备组成，最基本功能是实现数据互通。\nOSI 七层模型要记住：物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。考试常问网络层负责逻辑地址与转发，传输层负责端到端传输。\nTCP/IP 参考模型是互联网主流模型，常见协议包括：应用层 HTTP/DNS/DHCP，传输层 TCP/UDP，网络层 IP/ICMP/IGMP，链路层 Ethernet/PPP。\n交换机可按网络构成分为接入层、汇聚层、核心层；按 TCP/IP 模型可分为二层交换机和三层交换机。\n路由器也可按网络构成分为接入层、汇聚层、核心层；作用是实现不同网络之间的互联。\n无线网络常见设备包括 AC（无线控制器）和 AP（无线接入点），其中 AP 分为胖 AP 和瘦 AP。\n防火墙的核心作用是控制两个网络之间的安全通信，实现访问控制、身份认证、远程接入、VPN、NAT 等安全功能。\nIP 地址由网络部分和主机部分组成，网络掩码用于区分网络部分与主机部分，例如 192.168.10.1/24。\n有类编址中：A 类默认 /8，B 类默认 /16，C 类默认 /24；D 类用于组播，E 类用于研究。\n私网地址要重点记忆：10.0.0.0/8、172.16.0.0/12、192.168.0.0/16。\n特殊 IP 地址要会辨认：255.255.255.255 是有限广播地址，0.0.0.0 是任意地址，127.0.0.0/8 是环回地址，169.254.0.0 段用于本地链路临时通信。\n划分子网的目的：减少地址浪费、缩小广播域、让网络规划更合理。\n子网划分的本质是向主机位借位，得到更多子网；同时每个子网的可用主机数会减少。\n网络工程不仅是设备堆叠，而是按标准、规范和需求完成规划、设计、实施、排错和优化。\n背诵版 OSI 七层：物链网传会表应。\n网络层管逻辑地址和转发，传输层管端到端传输。\nTCP/IP 是互联网主流参考模型。\n交换机偏二层/三层交换，路由器负责不同网络互联。\n防火墙核心关键词：安全通信、访问控制、NAT、VPN。\nIP = 网络部分 + 主机部分；掩码决定边界。\nA/B/C 默认掩码：/8、/16、/24。\n私网地址三段：10/8、172.16/12、192.168/16。\n特殊地址四个重点：255.255.255.255、0.0.0.0、127/8、169.254/16（课件写到 169.254.0.0 段）。\n子网划分的价值：省地址、控广播、好规划。\n自测题 OSI 七层模型从下到上分别是什么？ 网络层和传输层分别负责什么功能？ A/B/C 类地址默认掩码分别是多少？ 私网地址常见三段分别是什么？ 255.255.255.255、0.0.0.0、127.0.0.0/8、169.254.0.0 段分别表示什么？ 为什么要进行子网划分？ ","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-04-acp-day-4-%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84-ip%E7%BC%96%E5%9D%80/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：Notion ACP学习笔记\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"acp-day-4网络架构--ip编址\"\u003eACP Day 4｜网络架构 + IP编址\u003c/h2\u003e\n\u003ch3 id=\"今日主题\"\u003e今日主题\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eDay 4：网络架构 + IP编址\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e对应资料：2-01-网络架构和网络设备详解 (1).pdf、2-02-IP编址 (1).pdf\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"重点整理\"\u003e重点整理\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e最简单的网络由两个终端和一条能够承载数据传输的物理介质组成。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e数据通信网络由路由器、交换机、防火墙、无线控制器、无线接入点以及主机、服务器等设备组成，最基本功能是实现数据互通。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eOSI 七层模型要记住：物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。考试常问网络层负责逻辑地址与转发，传输层负责端到端传输。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eTCP/IP 参考模型是互联网主流模型，常见协议包括：应用层 HTTP/DNS/DHCP，传输层 TCP/UDP，网络层 IP/ICMP/IGMP，链路层 Ethernet/PPP。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e交换机可按网络构成分为接入层、汇聚层、核心层；按 TCP/IP 模型可分为二层交换机和三层交换机。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e路由器也可按网络构成分为接入层、汇聚层、核心层；作用是实现不同网络之间的互联。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e无线网络常见设备包括 AC（无线控制器）和 AP（无线接入点），其中 AP 分为胖 AP 和瘦 AP。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e防火墙的核心作用是控制两个网络之间的安全通信，实现访问控制、身份认证、远程接入、VPN、NAT 等安全功能。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eIP 地址由网络部分和主机部分组成，网络掩码用于区分网络部分与主机部分，例如 192.168.10.1/24。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e有类编址中：A 类默认 /8，B 类默认 /16，C 类默认 /24；D 类用于组播，E 类用于研究。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e私网地址要重点记忆：10.0.0.0/8、172.16.0.0/12、192.168.0.0/16。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e特殊 IP 地址要会辨认：255.255.255.255 是有限广播地址，0.0.0.0 是任意地址，127.0.0.0/8 是环回地址，169.254.0.0 段用于本地链路临时通信。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e划分子网的目的：减少地址浪费、缩小广播域、让网络规划更合理。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e子网划分的本质是向主机位借位，得到更多子网；同时每个子网的可用主机数会减少。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e网络工程不仅是设备堆叠，而是按标准、规范和需求完成规划、设计、实施、排错和优化。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"背诵版\"\u003e背诵版\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eOSI 七层：物链网传会表应。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e网络层管逻辑地址和转发，传输层管端到端传输。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eTCP/IP 是互联网主流参考模型。\u003c/p\u003e","tags":"ACP, 阿里云","title":"ACP Day 4 网络架构 + IP编址"},{"columns":"python-course","content":"Python 第五课：逻辑运算符、短路求值与链式比较 课程概述 本节课我们将深入探讨 Python 中三个最重要的逻辑运算符——and、or 和 not的工作原理，以及与它们密切相关的短路求值（Short-circuit Evaluation，也称为最小化求值）机制。我们还将详细学习 Python 特有的链式比较（Chained Comparisons）语法，这是 Python 语言中最优雅的特性之一。此外，本课还将涵盖 Python 中所有对象的布尔值规则、真值测试（Truth Value Testing），以及如何利用逻辑运算符的特性编写更加简洁、高效和安全的代码。本课程所有内容基于 Python 3.11 编写，涵盖了 Python 3.11 中关于布尔运算和比较操作的最新实现细节和优化。\n逻辑运算符是所有编程语言的基石之一，它们构成了条件判断、循环控制和程序逻辑的核心。Python 的逻辑运算符相比其他语言有一些独特的设计：Python 使用英语单词 and、or、not 而不是 \u0026amp;\u0026amp;、||、! 这样的符号，这使得代码更接近自然语言，可读性更强。更重要的是，Python 的逻辑运算符遵循短路求值原则，这不仅提高了代码效率，还为编写安全的代码提供了独特的手段。\n逻辑运算符基础 and（逻辑与） and 运算符当且仅当两个操作数都为 True 时结果才为 True。在任何其他情况下，结果都是 False。\n# and 运算符的真值表 print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;and 运算符真值表\u0026#34;) print(\u0026#34;=\u0026#34; * 50) print(f\u0026#34;True and True = {True and True}\u0026#34;) print(f\u0026#34;True and False = {True and False}\u0026#34;) print(f\u0026#34;False and True = {False and True}\u0026#34;) print(f\u0026#34;False and False = {False and False}\u0026#34;) print() # and 运算符返回的是最后一个求值的表达式，而不是单纯的 True/False print(\u0026#34;and 返回的值：\u0026#34;) print(f\u0026#34;1 and 2 = {1 and 2}\u0026#34;) # 返回 2 print(f\u0026#34;1 and 0 = {1 and 0}\u0026#34;) # 返回 0 print(f\u0026#34;0 and 1 = {0 and 1}\u0026#34;) # 返回 0 print(f\u0026#34;\u0026#39;a\u0026#39; and \u0026#39;b\u0026#39; = {\u0026#39;a\u0026#39; and \u0026#39;b\u0026#39;}\u0026#34;) # 返回 \u0026#39;b\u0026#39; print(f\u0026#34;\u0026#39;\u0026#39; and \u0026#39;b\u0026#39; = {\u0026#39;\u0026#39; and \u0026#39;b\u0026#39;}\u0026#34;) # 返回 \u0026#39;\u0026#39; or（逻辑或） or 运算符当任意一个操作数为 True 时结果就为 True。只有两个操作数都为 False 时结果才为 False。\n# or 运算符的真值表 print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;or 运算符真值表\u0026#34;) print(\u0026#34;=\u0026#34; * 50) print(f\u0026#34;True or True = {True or True}\u0026#34;) print(f\u0026#34;True or False = {True or False}\u0026#34;) print(f\u0026#34;False or True = {False or True}\u0026#34;) print(f\u0026#34;False or False = {False or False}\u0026#34;) print() # or 运算符返回的是第一个求值为真的表达式 print(\u0026#34;or 返回的值：\u0026#34;) print(f\u0026#34;1 or 2 = {1 or 2}\u0026#34;) # 返回 1 print(f\u0026#34;0 or 2 = {0 or 2}\u0026#34;) # 返回 2 print(f\u0026#34;0 or \u0026#39;\u0026#39; = {0 or \u0026#39;\u0026#39;}\u0026#34;) # 返回 \u0026#39;\u0026#39; print(f\u0026#34;\u0026#39;a\u0026#39; or \u0026#39;b\u0026#39; = {\u0026#39;a\u0026#39; or \u0026#39;b\u0026#39;}\u0026#34;) # 返回 \u0026#39;a\u0026#39; print(f\u0026#34;\u0026#39;\u0026#39; or \u0026#39;b\u0026#39; = {\u0026#39;\u0026#39; or \u0026#39;b\u0026#39;}\u0026#34;) # 返回 \u0026#39;b\u0026#39; not（逻辑非） not 运算符是一元运算符，用于取反布尔值。\n# not 运算符的真值表 print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;not 运算符真值表\u0026#34;) print(\u0026#34;=\u0026#34; * 50) print(f\u0026#34;not True = {not True}\u0026#34;) print(f\u0026#34;not False = {not False}\u0026#34;) print() # not 返回的是布尔值 print(\u0026#34;not 返回的值（总是布尔值）：\u0026#34;) print(f\u0026#34;not 1 = {not 1}\u0026#34;) # False print(f\u0026#34;not 0 = {not 0}\u0026#34;) # True print(f\u0026#34;not \u0026#39;a\u0026#39; = {not \u0026#39;a\u0026#39;}\u0026#34;) # False print(f\u0026#34;not \u0026#39;\u0026#39; = {not \u0026#39;\u0026#39;}\u0026#34;) # True 短路求值（Short-circuit Evaluation）详解 短路求值是逻辑运算符最重要的特性之一。理解短路求值对于编写高效、安全的 Python 代码至关重要。\nand 的短路行为 当使用 and 连接多个表达式时，Python 从左到右计算每个表达式。一旦遇到值为假的表达式，就立即返回该值，不再继续计算后续表达式。这是因为只要有一个操作数为 False，and 的结果就一定是 False。\nprint(\u0026#34;=\u0026#34; * 50) print(\u0026#34;and 的短路求值演示\u0026#34;) print(\u0026#34;=\u0026#34; * 50) def trace(value, name): \u0026#34;\u0026#34;\u0026#34;跟踪函数调用\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34; [调用 trace({value!r}, \u0026#39;{name}\u0026#39;)]\u0026#34;) return value print(\u0026#34;测试 1：trace(False, \u0026#39;a\u0026#39;) and trace(5, \u0026#39;b\u0026#39;)\u0026#34;) result = trace(False, \u0026#34;a\u0026#34;) and trace(5, \u0026#34;b\u0026#34;) print(f\u0026#34;结果：{result}\u0026#34;) print(\u0026#34;解释：第一个值为 False，直接返回，不再计算第二个表达式\\n\u0026#34;) print(\u0026#34;测试 2：trace(True, \u0026#39;a\u0026#39;) and trace(10, \u0026#39;b\u0026#39;)\u0026#34;) result = trace(True, \u0026#34;a\u0026#34;) and trace(10, \u0026#34;b\u0026#34;) print(f\u0026#34;结果：{result}\u0026#34;) print(\u0026#34;解释：第一个值为 True，继续计算第二个表达式\\n\u0026#34;) or 的短路行为 当使用 or 连接多个表达式时，Python 从左到右计算每个表达式。一旦遇到值为真的表达式，就立即返回该值，不再继续计算后续表达式。这是因为只要有一个操作数为 True，or 的结果就一定是 True。\nprint(\u0026#34;=\u0026#34; * 50) print(\u0026#34;or 的短路求值演示\u0026#34;) print(\u0026#34;=\u0026#34; * 50) def trace(value, name): \u0026#34;\u0026#34;\u0026#34;跟踪函数调用\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34; [调用 trace({value!r}, \u0026#39;{name}\u0026#39;)]\u0026#34;) return value print(\u0026#34;测试 1：trace(True, \u0026#39;a\u0026#39;) or trace(5, \u0026#39;b\u0026#39;)\u0026#34;) result = trace(True, \u0026#34;a\u0026#34;) or trace(5, \u0026#34;b\u0026#34;) print(f\u0026#34;结果：{result}\u0026#34;) print(\u0026#34;解释：第一个值为 True，直接返回，不再计算第二个表达式\\n\u0026#34;) print(\u0026#34;测试 2：trace(False, \u0026#39;a\u0026#39;) or trace(10, \u0026#39;b\u0026#39;)\u0026#34;) result = trace(False, \u0026#34;a\u0026#34;) or trace(10, \u0026#34;b\u0026#34;) print(f\u0026#34;结果：{result}\u0026#34;) print(\u0026#34;解释：第一个值为 False，继续计算第二个表达式\\n\u0026#34;) 短路求值的实际应用 应用一：安全的默认值赋值 # 场景：根据配置值或默认值进行初始化 # 不使用短路求值（不安全） # config = get_config() # 如果返回 None 会出问题 # timeout = config.timeout # AttributeError # 使用短路求值（安全） def get_config(): return None config = get_config() timeout = config.timeout if config else 30 print(f\u0026#34;超时时间：{timeout} 秒\u0026#34;) # 或者使用 or 运算符 config = {\u0026#34;timeout\u0026#34;: 60} # 模拟获取到的配置 timeout = config.get(\u0026#34;timeout\u0026#34;) or 30 print(f\u0026#34;超时时间：{timeout} 秒\u0026#34;) 应用二：避免除零错误 # 场景：计算比率，但要避免除数为零 def safe_divide(a, b): # 使用短路求值避免除零 return (b != 0) and (a / b) or \u0026#34;除数不能为零\u0026#34; print(safe_divide(10, 2)) # 5.0 print(safe_divide(10, 0)) # 除数不能为零 # 更推荐的方式 def safe_divide_v2(a, b): if b != 0: return a / b return \u0026#34;除数不能为零\u0026#34; print(safe_divide_v2(10, 2)) # 5.0 print(safe_divide_v2(10, 0)) # 除数不能为零 应用三：链式函数调用 # 场景：只有对象存在且有效时才调用其方法 class User: def __init__(self, profile): self.profile = profile def get_name(self): return self.profile.get(\u0026#34;name\u0026#34;) if self.profile else None user_data = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25} # 传统写法（不安全） # user = get_user(id) # name = user.get_name() # 如果 user 为 None 会崩溃 # 使用短路求值 user = User(user_data) name = user and user.profile and user.profile.get(\u0026#34;name\u0026#34;) print(f\u0026#34;用户名：{name}\u0026#34;) # 或者使用更清晰的写法 user = None name = user and user.profile and user.profile.get(\u0026#34;name\u0026#34;) print(f\u0026#34;用户名：{name}\u0026#34;) # None（不会报错） 应用四：条件执行 # 场景：只有在满足前置条件时才执行操作 def process_data(data): # 只有 data 非空且类型正确时才处理 return data and isinstance(data, list) and [x * 2 for x in data] print(process_data([1, 2, 3])) # [2, 4, 6] print(process_data([])) # []（空列表，但类型正确） print(process_data(\u0026#34;hello\u0026#34;)) # None（类型不对） 真值测试（Truth Value Testing） Python 中的所有对象都可以进行真值测试，即在布尔上下文中判断对象的真假。\n哪些值是假的？ print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;Python 中的假值（Falsy Values）\u0026#34;) print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;以下值在布尔测试中为 False：\u0026#34;) print() # 常数 print(\u0026#34;1. 常数：None, False\u0026#34;) print(f\u0026#34; bool(None) = {bool(None)}\u0026#34;) print(f\u0026#34; bool(False) = {bool(False)}\u0026#34;) print() # 数字类型 print(\u0026#34;2. 数字类型：0, 0.0, 0j, Decimal(0), Fraction(0, 1)\u0026#34;) print(f\u0026#34; bool(0) = {bool(0)}\u0026#34;) print(f\u0026#34; bool(0.0) = {bool(0.0)}\u0026#34;) print(f\u0026#34; bool(0j) = {bool(0j)}\u0026#34;) print() # 序列和集合 print(\u0026#34;3. 空序列/集合：\u0026#39;\u0026#39;, (), [], {{}}, set()\u0026#34;) print(f\u0026#34; bool(\u0026#39;\u0026#39;) = {bool(\u0026#39;\u0026#39;)}\u0026#34;) print(f\u0026#34; bool(()) = {bool(())}\u0026#34;) print(f\u0026#34; bool([]) = {bool([])}\u0026#34;) print(f\u0026#34; bool({{}}) = {bool({})}\u0026#34;) print(f\u0026#34; bool(set()) = {bool(set())}\u0026#34;) 哪些值是真的？ print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;Python 中的真值（Truthy Values）\u0026#34;) print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;除了上述假值以外，所有其他值都是真值：\u0026#34;) print() print(\u0026#34;1. 非零数字：\u0026#34;) print(f\u0026#34; bool(1) = {bool(1)}\u0026#34;) print(f\u0026#34; bool(-1) = {bool(-1)}\u0026#34;) print(f\u0026#34; bool(0.001) = {bool(0.001)}\u0026#34;) print() print(\u0026#34;2. 非空字符串：\u0026#34;) print(f\u0026#34; bool(\u0026#39; \u0026#39;) = {bool(\u0026#39; \u0026#39;)}\u0026#34;) # 注意：空格字符串也是真值 print(f\u0026#34; bool(\u0026#39;False\u0026#39;) = {bool(\u0026#39;False\u0026#39;)}\u0026#34;) # 字符串 \u0026#39;False\u0026#39; 也是真值 print() print(\u0026#34;3. 非空序列/集合：\u0026#34;) print(f\u0026#34; bool([0]) = {bool([0])}\u0026#34;) # 包含 0 的列表也是真值 print(f\u0026#34; bool(\u0026#39;hello\u0026#39;) = {bool(\u0026#39;hello\u0026#39;)}\u0026#34;) print(f\u0026#34; bool({{\u0026#39;a\u0026#39;: 1}}) = {bool({\u0026#39;a\u0026#39;: 1})}\u0026#34;) 自定义对象的真值测试 # 通过定义 __bool__ 方法来控制对象的真值 class MyClass: def __init__(self, value): self.value = value def __bool__(self): return self.value \u0026gt; 0 obj1 = MyClass(10) obj2 = MyClass(-5) obj3 = MyClass(0) print(f\u0026#34;obj1 (value=10) 的真值：{bool(obj1)}\u0026#34;) # True print(f\u0026#34;obj2 (value=-5) 的真值：{bool(obj2)}\u0026#34;) # False print(f\u0026#34;obj3 (value=0) 的真值：{bool(obj3)}\u0026#34;) # False # 如果没有定义 __bool__，Python 会使用 __len__ class MyList: def __init__(self, items): self.items = items def __len__(self): return len(self.items) lst = MyList([1, 2, 3]) print(f\u0026#34;MyList([1,2,3]) 的真值：{bool(lst)}\u0026#34;) # True（有 3 个元素） lst_empty = MyList([]) print(f\u0026#34;MyList([]) 的真值：{bool(lst_empty)}\u0026#34;) # False（没有元素） 链式比较（Chained Comparisons） 链式比较是 Python 最优雅的特性之一。它允许你将多个比较操作串联在一起，形成一个清晰、易读的比较表达式。\n链式比较的基本原理 print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;链式比较\u0026#34;) print(\u0026#34;=\u0026#34; * 50) # 基本链式比较 x = 5 print(f\u0026#34;x = {x}\u0026#34;) print(f\u0026#34;0 \u0026lt; x \u0026lt; 10 = {0 \u0026lt; x \u0026lt; 10}\u0026#34;) print(f\u0026#34;0 \u0026lt; x \u0026lt; 3 = {0 \u0026lt; x \u0026lt; 3}\u0026#34;) # Python 实际上将链式比较解释为： print(f\u0026#34;\\n等价于：(0 \u0026lt; x) and (x \u0026lt; 10) = {(0 \u0026lt; x) and (x \u0026lt; 10)}\u0026#34;) 链式比较的工作原理 # Python 对链式比较的特殊处理 # 0 \u0026lt; x \u0026lt; 10 不会先计算 (0 \u0026lt; x) 得到 True/False， # 然后再与 10 比较 # Python 会将其转换为 (0 \u0026lt; x) and (x \u0026lt; 10) # 重要：x 只会计算一次 print(\u0026#34;演示 x 只计算一次：\u0026#34;) x = 5 def get_x(): print(f\u0026#34; [调用 get_x()]\u0026#34;) return x print(\u0026#34;计算 0 \u0026lt; get_x() \u0026lt; 10：\u0026#34;) result = 0 \u0026lt; get_x() \u0026lt; 10 print(f\u0026#34;结果：{result}\u0026#34;) print(\u0026#34;注意：get_x() 只被调用了一次！\u0026#34;) 各种链式比较模式 # 1. 简单数值范围检查 age = 25 print(f\u0026#34;年龄 {age} 是否在 18-65 岁之间：{18 \u0026lt;= age \u0026lt;= 65}\u0026#34;) # 2. 多个连续比较 x = 5 print(f\u0026#34;x = {x}, 0 \u0026lt; x \u0026lt; 10 = {0 \u0026lt; x \u0026lt; 10}\u0026#34;) # 3. 三个以上的链式比较 y = 15 print(f\u0026#34;y = {y}, 0 \u0026lt; x \u0026lt; 10 \u0026lt; y \u0026lt; 20 = {0 \u0026lt; x \u0026lt; 10 \u0026lt; y \u0026lt; 20}\u0026#34;) # 4. 同一变量多次出现在链中 a = 10 print(f\u0026#34;a = {a}, 0 \u0026lt; a \u0026lt; 20 \u0026gt; 5 = {0 \u0026lt; a \u0026lt; 20 \u0026gt; 5}\u0026#34;) # 5. 不同比较运算符的链式组合 x = 5 print(f\u0026#34;x = {x}, x == 5 \u0026gt;= 3 != 0 = {x == 5 \u0026gt;= 3 != 0}\u0026#34;) 链式比较的实际应用 # 应用一：区间判断 def get_score_level(score): \u0026#34;\u0026#34;\u0026#34;根据分数返回等级\u0026#34;\u0026#34;\u0026#34; if 90 \u0026lt;= score \u0026lt;= 100: return \u0026#34;A\u0026#34; elif 80 \u0026lt;= score \u0026lt; 90: return \u0026#34;B\u0026#34; elif 70 \u0026lt;= score \u0026lt; 80: return \u0026#34;C\u0026#34; elif 60 \u0026lt;= score \u0026lt; 70: return \u0026#34;D\u0026#34; elif 0 \u0026lt;= score \u0026lt; 60: return \u0026#34;F\u0026#34; else: return \u0026#34;无效分数\u0026#34; scores = [95, 85, 75, 65, 55, 105, -5] for s in scores: print(f\u0026#34;分数 {s:\u0026gt;4} =\u0026gt; 等级 {get_score_level(s)}\u0026#34;) # 应用二：边界检查 def is_valid_coordinate(lat, lon): \u0026#34;\u0026#34;\u0026#34;检查坐标是否有效\u0026#34;\u0026#34;\u0026#34; return -90 \u0026lt;= lat \u0026lt;= 90 and -180 \u0026lt;= lon \u0026lt;= 180 coords = [ (0, 0), (45.5, 120.3), (91, 0), (0, 181), (35.3, 139.7) # 东京 ] print(\u0026#34;\\n坐标有效性检查：\u0026#34;) for lat, lon in coords: valid = is_valid_coordinate(lat, lon) print(f\u0026#34;({lat:\u0026gt;6}, {lon:\u0026gt;7}) =\u0026gt; {\u0026#39;有效\u0026#39; if valid else \u0026#39;无效\u0026#39;}\u0026#34;) 链式比较与运算符优先级 # 链式比较的优先级规则 # a \u0026lt; b == c 会被解析为 (a \u0026lt; b) and (b == c) # 而不是 a \u0026lt; (b == c) a, b, c = 1, 2, 2 print(f\u0026#34;a = {a}, b = {b}, c = {c}\u0026#34;) print(f\u0026#34;a \u0026lt; b == c : {a \u0026lt; b == c}\u0026#34;) # (1 \u0026lt; 2) and (2 == 2) = True print(f\u0026#34;等价于：(a \u0026lt; b) and (b == c) = {(a \u0026lt; b) and (b == c)}\u0026#34;) # 使用括号改变优先级 print(f\u0026#34;\\na \u0026lt; (b == c) : {a \u0026lt; (b == c)}\u0026#34;) and、or、not 的组合使用 优先级：not \u0026gt; and \u0026gt; or print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;逻辑运算符优先级\u0026#34;) print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;优先级：not \u0026gt; and \u0026gt; or\u0026#34;) print() # not 优先级最高 print(\u0026#34;示例 1：not True and False\u0026#34;) print(f\u0026#34;结果：{not True and False}\u0026#34;) # (not True) and False = False and False = False print(f\u0026#34;等价于：(not True) and False = {(not True) and False}\u0026#34;) print() # and 优先级高于 or print(\u0026#34;示例 2：True or False and False\u0026#34;) print(f\u0026#34;结果：{True or False and False}\u0026#34;) # True or (False and False) = True or False = True print(f\u0026#34;等价于：True or (False and False) = {True or (False and False)}\u0026#34;) print() # 使用括号改变优先级 print(\u0026#34;示例 3：(True or False) and False\u0026#34;) print(f\u0026#34;结果：{(True or False) and False}\u0026#34;) # True and False = False 复杂的逻辑表达式 # 组合使用 and、or、not age = 25 income = 50000 has_credit = False is_employed = True # 判断是否可以申请信用卡 can_apply = ( (age \u0026gt;= 18 and age \u0026lt;= 65) # 年龄在 18-65 岁之间 and (income \u0026gt; 30000 or has_credit) # 收入高于 30000 或者有其他信用卡 and is_employed # 当前在就业状态 ) print(f\u0026#34;年龄={age}, 收入={income}, 有信用卡={has_credit}, 在职={is_employed}\u0026#34;) print(f\u0026#34;可以申请信用卡：{can_apply}\u0026#34;) 德摩根定律的 Python 实现 德摩根定律（De Morgan\u0026rsquo;s Laws）是逻辑代数的基本定律：\n# 德摩根定律： # not (A and B) == (not A) or (not B) # not (A or B) == (not A) and (not B) print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;德摩根定律验证\u0026#34;) print(\u0026#34;=\u0026#34; * 50) A, B = True, False print(f\u0026#34;A = {A}, B = {B}\u0026#34;) print() print(f\u0026#34;not (A and B) = {not (A and B)}\u0026#34;) print(f\u0026#34;(not A) or (not B) = {(not A) or (not B)}\u0026#34;) print(f\u0026#34;相等：{not (A and B) == (not A) or (not B)}\u0026#34;) print() print(f\u0026#34;not (A or B) = {not (A or B)}\u0026#34;) print(f\u0026#34;(not A) and (not B) = {(not A) and (not B)}\u0026#34;) print(f\u0026#34;相等：{not (A or B) == (not A) and (not B)}\u0026#34;) 短路求值的高级应用 应用一：级联默认值赋值 # 使用 or 实现级联默认值 def get_connection_string(primary, secondary, fallback): \u0026#34;\u0026#34;\u0026#34;获取数据库连接字符串\u0026#34;\u0026#34;\u0026#34; return primary or secondary or fallback primary = \u0026#34;\u0026#34; # 主数据库不可用 secondary = \u0026#34;\u0026#34; # 备用数据库也不可用 fallback = \u0026#34;sqlite:///default.db\u0026#34; result = get_connection_string(primary, secondary, fallback) print(f\u0026#34;连接字符串：{result}\u0026#34;) 应用二：函数存在性检查 # 检查函数是否存在并调用 class Calculator: def add(self, a, b): return a + b def subtract(self, a, b): return a - b calc = Calculator() # 传统写法 if hasattr(calc, \u0026#34;multiply\u0026#34;): result = calc.multiply(5, 3) else: result = \u0026#34;方法不存在\u0026#34; # 使用 getattr 和短路求值（更 Pythonic） multiply_func = getattr(calc, \u0026#34;multiply\u0026#34;, None) result = multiply_func and multiply_func(5, 3) or \u0026#34;方法不存在\u0026#34; print(f\u0026#34;multiply 结果：{result}\u0026#34;) # 验证 add 方法存在 add_func = getattr(calc, \u0026#34;add\u0026#34;, None) result = add_func and add_func(5, 3) or \u0026#34;方法不存在\u0026#34; print(f\u0026#34;add 结果：{result}\u0026#34;) 应用三：防止 KeyError # 使用 and 链安全访问嵌套字典 data = { \u0026#34;user\u0026#34;: { \u0026#34;profile\u0026#34;: { \u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;settings\u0026#34;: { \u0026#34;theme\u0026#34;: \u0026#34;dark\u0026#34; } } } } # 不安全的方式（可能 KeyError） # theme = data[\u0026#34;user\u0026#34;][\u0026#34;profile\u0026#34;][\u0026#34;settings\u0026#34;][\u0026#34;theme\u0026#34;] # 使用短路求值的安全方式 theme = ( data and data.get(\u0026#34;user\u0026#34;) and data[\u0026#34;user\u0026#34;].get(\u0026#34;profile\u0026#34;) and data[\u0026#34;user\u0026#34;][\u0026#34;profile\u0026#34;].get(\u0026#34;settings\u0026#34;) and data[\u0026#34;user\u0026#34;][\u0026#34;profile\u0026#34;][\u0026#34;settings\u0026#34;].get(\u0026#34;theme\u0026#34;) ) print(f\u0026#34;主题：{theme}\u0026#34;) # 更简洁的替代方案（Python 3.10+） # 使用 | 运算符（需要注意，这只对字典有效） # theme = data.get(\u0026#34;user\u0026#34;, {}).get(\u0026#34;profile\u0026#34;, {}).get(\u0026#34;settings\u0026#34;, {}).get(\u0026#34;theme\u0026#34;) # 使用异常处理（最安全的方式） try: theme = data[\u0026#34;user\u0026#34;][\u0026#34;profile\u0026#34;][\u0026#34;settings\u0026#34;][\u0026#34;theme\u0026#34;] except (KeyError, TypeError): theme = None print(f\u0026#34;主题（try-except）：{theme}\u0026#34;) Python 3.11 中的改进 Python 3.11 对布尔运算和比较操作进行了一些优化：\n布尔运算的性能优化 # Python 3.11 中布尔运算的性能改进 # True 和 False 现在是 singletons（单例），比较操作更快 a = True b = False # is 比较 print(f\u0026#34;a is True : {a is True}\u0026#34;) # True print(f\u0026#34;b is False : {b is False}\u0026#34;) # True # 布尔类型的内部优化 import sys print(f\u0026#34;\\nbool 的缓存大小：{sys.maxsize}\u0026#34;) # 仅供参考 比较操作的优化 # Python 3.11 中链式比较的字节码优化 x = 5 print(f\u0026#34;0 \u0026lt; x \u0026lt; 10 = {0 \u0026lt; x \u0026lt; 10}\u0026#34;) # Python 3.11 中对 NaN 的比较处理 import math nan = float(\u0026#39;nan\u0026#39;) print(f\u0026#34;\\nnan 的比较：\u0026#34;) print(f\u0026#34;nan \u0026lt; 5 = {nan \u0026lt; 5}\u0026#34;) # False print(f\u0026#34;nan \u0026gt; 5 = {nan \u0026gt; 5}\u0026#34;) # False print(f\u0026#34;nan == nan = {nan == nan}\u0026#34;) # False（NaN 不等于自身！） print(f\u0026#34;\\nnan 与其他值的逻辑运算：\u0026#34;) print(f\u0026#34;nan and True = {nan and True}\u0026#34;) # True print(f\u0026#34;nan or False = {nan or False}\u0026#34;) # False 短路求值与 lambda/列表推导式 # 在列表推导式中使用短路求值 data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 只处理非零元素 result = [x * 2 for x in data if x != 0] print(f\u0026#34;非零元素的加倍：{result}\u0026#34;) # 使用 and 实现条件过滤 result = [x * 2 for x in data if x and x % 2 == 0] # x 非零且为偶数 print(f\u0026#34;非零偶数的加倍：{result}\u0026#34;) # 短路求值在列表推导式中的作用 values = [0, None, \u0026#34;\u0026#34;, 1, 2, None, 3] # 只保留真值 filtered = [v for v in values if v] print(f\u0026#34;真值过滤：{filtered}\u0026#34;) 综合练习题 练习一：布尔运算综合测试 \u0026#34;\u0026#34;\u0026#34; 布尔运算综合测试 测试短路求值、链式比较和逻辑组合 \u0026#34;\u0026#34;\u0026#34; def test_short_circuit(): \u0026#34;\u0026#34;\u0026#34;测试短路求值\u0026#34;\u0026#34;\u0026#34; print(\u0026#34;=\u0026#34; * 60) print(\u0026#34;测试 1：短路求值\u0026#34;) print(\u0026#34;=\u0026#34; * 60) call_count = {\u0026#34;a\u0026#34;: 0, \u0026#34;b\u0026#34;: 0} def make_func(name): def func(): call_count[name] += 1 print(f\u0026#34; [调用 {name}()]\u0026#34;) return True # 总是返回 True return func a = make_func(\u0026#34;a\u0026#34;) b = make_func(\u0026#34;b\u0026#34;) print(\u0026#34;a() and b()：\u0026#34;) call_count = {\u0026#34;a\u0026#34;: 0, \u0026#34;b\u0026#34;: 0} result = a() and b() print(f\u0026#34;结果：{result}，a 调用次数：{call_count[\u0026#39;a\u0026#39;]}，b 调用次数：{call_count[\u0026#39;b\u0026#39;]}\u0026#34;) print() def make_func_false(name): def func(): call_count[name] += 1 print(f\u0026#34; [调用 {name}()]\u0026#34;) return False return func a_false = make_func_false(\u0026#34;a\u0026#34;) b = make_func(\u0026#34;b\u0026#34;) print(\u0026#34;a_false() and b()：\u0026#34;) call_count = {\u0026#34;a\u0026#34;: 0, \u0026#34;b\u0026#34;: 0} result = a_false() and b() print(f\u0026#34;结果：{result}，a 调用次数：{call_count[\u0026#39;a\u0026#39;]}，b 调用次数：{call_count[\u0026#39;b\u0026#39;]}\u0026#34;) def test_or_short_circuit(): \u0026#34;\u0026#34;\u0026#34;测试 or 的短路求值\u0026#34;\u0026#34;\u0026#34; print() print(\u0026#34;=\u0026#34; * 60) print(\u0026#34;测试 2：or 的短路求值\u0026#34;) print(\u0026#34;=\u0026#34; * 60) call_count = {\u0026#34;a\u0026#34;: 0, \u0026#34;b\u0026#34;: 0} def make_func(name, return_value): def func(): call_count[name] += 1 print(f\u0026#34; [调用 {name}() -\u0026gt; {return_value}]\u0026#34;) return return_value return func a_true = make_func(\u0026#34;a\u0026#34;, True) b = make_func(\u0026#34;b\u0026#34;, False) print(\u0026#34;a_true() or b()：\u0026#34;) call_count = {\u0026#34;a\u0026#34;: 0, \u0026#34;b\u0026#34;: 0} result = a_true() or b() print(f\u0026#34;结果：{result}，a 调用次数：{call_count[\u0026#39;a\u0026#39;]}，b 调用次数：{call_count[\u0026#39;b\u0026#39;]}\u0026#34;) print() a_false = make_func(\u0026#34;a\u0026#34;, False) print(\u0026#34;a_false() or b()：\u0026#34;) call_count = {\u0026#34;a\u0026#34;: 0, \u0026#34;b\u0026#34;: 0} result = a_false() or b() print(f\u0026#34;结果：{result}，a 调用次数：{call_count[\u0026#39;a\u0026#39;]}，b 调用次数：{call_count[\u0026#39;b\u0026#39;]}\u0026#34;) def test_chained_comparison(): \u0026#34;\u0026#34;\u0026#34;测试链式比较\u0026#34;\u0026#34;\u0026#34; print() print(\u0026#34;=\u0026#34; * 60) print(\u0026#34;测试 3：链式比较\u0026#34;) print(\u0026#34;=\u0026#34; * 60) def trace_compare(x, name): print(f\u0026#34; [比较 x ({name}) = {x}]\u0026#34;) return x x = 5 print(f\u0026#34;0 \u0026lt; trace_compare(x, \u0026#39;left\u0026#39;) \u0026lt; 10：\u0026#34;) result = 0 \u0026lt; trace_compare(x, \u0026#34;left\u0026#34;) \u0026lt; 10 print(f\u0026#34;结果：{result}\u0026#34;) test_short_circuit() test_or_short_circuit() test_chained_comparison() 练习二：用户输入验证系统 \u0026#34;\u0026#34;\u0026#34; 用户输入验证系统 练习使用逻辑运算符构建复杂验证条件 \u0026#34;\u0026#34;\u0026#34; def validate_user_input(username, age, email, password): \u0026#34;\u0026#34;\u0026#34;验证用户输入\u0026#34;\u0026#34;\u0026#34; errors = [] # 用户名验证 if not username: # 用户名为空 errors.append(\u0026#34;用户名不能为空\u0026#34;) elif len(username) \u0026lt; 3: errors.append(\u0026#34;用户名长度不能少于 3 个字符\u0026#34;) elif len(username) \u0026gt; 20: errors.append(\u0026#34;用户名长度不能超过 20 个字符\u0026#34;) elif not username[0].isalpha(): errors.append(\u0026#34;用户名必须以字母开头\u0026#34;) # 年龄验证 if not isinstance(age, int): errors.append(\u0026#34;年龄必须是整数\u0026#34;) elif age \u0026lt; 0: errors.append(\u0026#34;年龄不能为负数\u0026#34;) elif age \u0026lt; 18: errors.append(\u0026#34;必须年满 18 岁\u0026#34;) elif age \u0026gt; 150: errors.append(\u0026#34;请输入真实的年龄\u0026#34;) # 邮箱验证 if not email: errors.append(\u0026#34;邮箱不能为空\u0026#34;) elif \u0026#34;@\u0026#34; not in email: errors.append(\u0026#34;邮箱格式不正确\u0026#34;) elif email.count(\u0026#34;@\u0026#34;) \u0026gt; 1: errors.append(\u0026#34;邮箱格式不正确\u0026#34;) elif \u0026#34;.\u0026#34; not in email.split(\u0026#34;@\u0026#34;)[-1]: errors.append(\u0026#34;邮箱域名格式不正确\u0026#34;) # 密码验证 if not password: errors.append(\u0026#34;密码不能为空\u0026#34;) elif len(password) \u0026lt; 8: errors.append(\u0026#34;密码长度不能少于 8 个字符\u0026#34;) elif len(password) \u0026gt; 128: errors.append(\u0026#34;密码长度不能超过 128 个字符\u0026#34;) elif not any(c.isupper() for c in password): errors.append(\u0026#34;密码必须包含至少一个大写字母\u0026#34;) elif not any(c.islower() for c in password): errors.append(\u0026#34;密码必须包含至少一个小写字母\u0026#34;) elif not any(c.isdigit() for c in password): errors.append(\u0026#34;密码必须包含至少一个数字\u0026#34;) # 综合验证结果 is_valid = len(errors) == 0 return is_valid, errors # 测试用例 test_cases = [ # (username, age, email, password) (\u0026#34;john\u0026#34;, 25, \u0026#34;john@example.com\u0026#34;, \u0026#34;Pass1234\u0026#34;), (\u0026#34;jo\u0026#34;, 25, \u0026#34;john@example.com\u0026#34;, \u0026#34;Pass1234\u0026#34;), # 用户名太短 (\u0026#34;john\u0026#34;, 15, \u0026#34;john@example.com\u0026#34;, \u0026#34;Pass1234\u0026#34;), # 年龄太小 (\u0026#34;john\u0026#34;, 25, \u0026#34;johnexample.com\u0026#34;, \u0026#34;Pass1234\u0026#34;), # 邮箱格式错误 (\u0026#34;john\u0026#34;, 25, \u0026#34;john@example.com\u0026#34;, \u0026#34;pass1234\u0026#34;), # 密码缺少大写字母 ] print(\u0026#34;=\u0026#34; * 70) print(\u0026#34;用户输入验证系统测试\u0026#34;) print(\u0026#34;=\u0026#34; * 70) for username, age, email, password in test_cases: is_valid, errors = validate_user_input(username, age, email, password) print(f\u0026#34;\\n输入：({username!r}, {age}, {email!r}, {password!r})\u0026#34;) if is_valid: print(\u0026#34;结果：✓ 验证通过\u0026#34;) else: print(\u0026#34;结果：✗ 验证失败\u0026#34;) for error in errors: print(f\u0026#34; - {error}\u0026#34;) 练习三：智能配置解析器 \u0026#34;\u0026#34;\u0026#34; 智能配置解析器 练习使用短路求值和安全地访问嵌套配置 \u0026#34;\u0026#34;\u0026#34; def get_config_value(config, *keys, default=None): \u0026#34;\u0026#34;\u0026#34;安全地获取嵌套配置值\u0026#34;\u0026#34;\u0026#34; result = config for key in keys: # 使用短路求值安全地遍历嵌套字典 result = result and isinstance(result, dict) and result.get(key) if result is None: return default return result if result is not None else default def parse_config(config): \u0026#34;\u0026#34;\u0026#34;解析配置并返回描述\u0026#34;\u0026#34;\u0026#34; results = [] # 基本设置 app_name = get_config_value(config, \u0026#34;app\u0026#34;, \u0026#34;name\u0026#34;, default=\u0026#34;未命名应用\u0026#34;) version = get_config_value(config, \u0026#34;app\u0026#34;, \u0026#34;version\u0026#34;, default=\u0026#34;0.0.0\u0026#34;) results.append(f\u0026#34;应用：{app_name} v{version}\u0026#34;) # 数据库配置 db_host = get_config_value(config, \u0026#34;database\u0026#34;, \u0026#34;host\u0026#34;, default=\u0026#34;localhost\u0026#34;) db_port = get_config_value(config, \u0026#34;database\u0026#34;, \u0026#34;port\u0026#34;, default=5432) db_name = get_config_value(config, \u0026#34;database\u0026#34;, \u0026#34;name\u0026#34;, default=\u0026#34;mydb\u0026#34;) results.append(f\u0026#34;数据库：{db_host}:{db_port}/{db_name}\u0026#34;) # 安全设置 ssl_enabled = get_config_value(config, \u0026#34;security\u0026#34;, \u0026#34;ssl\u0026#34;, default=False) ssl_str = \u0026#34;启用\u0026#34; if ssl_enabled else \u0026#34;禁用\u0026#34; results.append(f\u0026#34;SSL：{ssl_str}\u0026#34;) # 调试模式 debug = get_config_value(config, \u0026#34;app\u0026#34;, \u0026#34;debug\u0026#34;, default=False) debug_str = \u0026#34;开启\u0026#34; if debug else \u0026#34;关闭\u0026#34; results.append(f\u0026#34;调试模式：{debug_str}\u0026#34;) return results # 测试配置 configs = [ # 完整配置 { \u0026#34;app\u0026#34;: {\u0026#34;name\u0026#34;: \u0026#34;MyApp\u0026#34;, \u0026#34;version\u0026#34;: \u0026#34;1.2.3\u0026#34;, \u0026#34;debug\u0026#34;: True}, \u0026#34;database\u0026#34;: {\u0026#34;host\u0026#34;: \u0026#34;db.example.com\u0026#34;, \u0026#34;port\u0026#34;: 5432, \u0026#34;name\u0026#34;: \u0026#34;production\u0026#34;}, \u0026#34;security\u0026#34;: {\u0026#34;ssl\u0026#34;: True} }, # 部分配置 { \u0026#34;app\u0026#34;: {\u0026#34;name\u0026#34;: \u0026#34;PartialApp\u0026#34;}, \u0026#34;database\u0026#34;: {\u0026#34;host\u0026#34;: \u0026#34;localhost\u0026#34;} }, # 空配置 {}, ] for i, config in enumerate(configs, 1): print(f\u0026#34;=\u0026#34; * 60) print(f\u0026#34;配置 {i}\u0026#34;) print(\u0026#34;=\u0026#34; * 60) for line in parse_config(config): print(f\u0026#34; {line}\u0026#34;) print() 常见错误与调试 错误一：混淆 and 与 \u0026amp; # 错误：使用 and 进行位运算 result = True and False # 逻辑与，结果是 False # 正确：使用 \u0026amp; 进行位运算 result = True \u0026amp; False # 位与，结果是 False # 对于整数 a, b = 10, 5 result_and = a and b # 返回 b（5），因为 a 为真 result_bit = a \u0026amp; b # 位与，10 \u0026amp; 5 = 0b1010 \u0026amp; 0b0101 = 0 print(f\u0026#34;a and b = {result_and}\u0026#34;) print(f\u0026#34;a \u0026amp; b = {result_bit}\u0026#34;) 错误二：混淆 or 与 | # 错误：使用 or 进行位运算 result = True or False # 逻辑或，结果是 True # 正确：使用 | 进行位运算 result = True | False # 位或，结果是 True # 对于整数 a, b = 10, 5 result_or = a or b # 返回 a（10），因为 a 为真 result_bit = a | b # 位或，10 | 5 = 0b1010 | 0b0101 = 15 print(f\u0026#34;a or b = {result_or}\u0026#34;) print(f\u0026#34;a | b = {result_bit}\u0026#34;) 错误三：在布尔上下文中误用字符串 # 错误：使用字符串 \u0026#34;False\u0026#34; 作为布尔值 flag = \u0026#34;False\u0026#34; # 这是一个非空字符串，在布尔上下文中为 True！ if flag: print(\u0026#34;执行了！\u0026#34;) # 这会执行，因为 \u0026#34;False\u0026#34; 是真值 # 正确：使用布尔值 False flag = False if flag: print(\u0026#34;不会执行\u0026#34;) else: print(\u0026#34;正确：flag 是 False\u0026#34;) 错误四：短路求值导致的变量未定义 # 错误：依赖短路求值，但变量在两个分支中都需要 # x = 10 # if x \u0026gt; 0 and y \u0026gt; 0: # NameError: name \u0026#39;y\u0026#39; is not defined # pass # 正确：确保所有变量在使用前已定义 x, y = 10, 5 if x \u0026gt; 0 and y \u0026gt; 0: print(f\u0026#34;x * y = {x * y}\u0026#34;) 错误五：链式比较的误解 # 错误理解：0 \u0026lt; x \u0026lt; 10 表示 x 在 0 到 10 之间 # 但对于非数值类型可能不符合预期 x = \u0026#34;5\u0026#34; print(f\u0026#34;x = {x!r}\u0026#34;) print(f\u0026#34;0 \u0026lt; x \u0026lt; 10 = {0 \u0026lt; x \u0026lt; 10}\u0026#34;) # 对于字符串，\u0026#34;5\u0026#34; 会和数字比较吗？ # 实际上在 Python 3 中这会引发 TypeError # print(0 \u0026lt; \u0026#34;5\u0026#34; \u0026lt; 10) # TypeError # 正确：确保链式比较中的变量类型一致 x = 5 print(f\u0026#34;x = {x}, 0 \u0026lt; x \u0026lt; 10 = {0 \u0026lt; x \u0026lt; 10}\u0026#34;) Python 3.11 的特殊行为 None、True、False 的比较 # Python 3.11 中对 None、True、False 的比较优化 # 建议使用 is 进行身份比较，而不是 == print(\u0026#34;is vs == 对于 None：\u0026#34;) x = None print(f\u0026#34;x is None = {x is None}\u0026#34;) # 推荐 print(f\u0026#34;x == None = {x == None}\u0026#34;) # 不推荐 # True 和 False print(f\u0026#34;True is True = {True is True}\u0026#34;) print(f\u0026#34;False is False = {False is False}\u0026#34;) # 注意：True 和 False 是单例对象 print(f\u0026#34;True is not 1 = {True is not 1}\u0026#34;) # True（不同类型） print(f\u0026#34;True == 1 = {True == 1}\u0026#34;) # True（值相等） 本章小结 今天我们学习了以下核心内容：\n逻辑运算符基础：and、or、not 的基本用法和返回值特性。 短路求值机制： and 的短路：当第一个值为假时立即返回 or 的短路：当第一个值为真时立即返回 短路求值在安全默认值、避免错误等方面的应用 真值测试：Python 中所有对象的布尔值规则，假值和真值列表。 链式比较： 0 \u0026lt; x \u0026lt; 10 等价于 (0 \u0026lt; x) and (x \u0026lt; 10) Python 只对 x 求值一次 链式比较的实际应用场景 逻辑运算符的优先级：not \u0026gt; and \u0026gt; or 高级应用： 级联默认值赋值 函数存在性检查 嵌套字典安全访问 Python 3.11 改进：布尔运算和比较操作的优化 延伸阅读 Python Official Documentation - Boolean Operations Python Official Documentation - Comparisons Python Official Documentation - Truth Value Testing Real Python - Python\u0026rsquo;s not boolean \u0026ldquo;and\u0026rdquo; and \u0026ldquo;or\u0026rdquo; Python 3.11 Performance Improvements ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-05-logical-short-circuit/","summary":"\u003ch1 id=\"python-第五课逻辑运算符短路求值与链式比较\"\u003ePython 第五课：逻辑运算符、短路求值与链式比较\u003c/h1\u003e\n\u003ch2 id=\"课程概述\"\u003e课程概述\u003c/h2\u003e\n\u003cp\u003e本节课我们将深入探讨 Python 中三个最重要的逻辑运算符——\u003ccode\u003eand\u003c/code\u003e、\u003ccode\u003eor\u003c/code\u003e 和 \u003ccode\u003enot\u003c/code\u003e的工作原理，以及与它们密切相关的短路求值（Short-circuit Evaluation，也称为最小化求值）机制。我们还将详细学习 Python 特有的链式比较（Chained Comparisons）语法，这是 Python 语言中最优雅的特性之一。此外，本课还将涵盖 Python 中所有对象的布尔值规则、真值测试（Truth Value Testing），以及如何利用逻辑运算符的特性编写更加简洁、高效和安全的代码。本课程所有内容基于 \u003cstrong\u003ePython 3.11\u003c/strong\u003e 编写，涵盖了 Python 3.11 中关于布尔运算和比较操作的最新实现细节和优化。\u003c/p\u003e\n\u003cp\u003e逻辑运算符是所有编程语言的基石之一，它们构成了条件判断、循环控制和程序逻辑的核心。Python 的逻辑运算符相比其他语言有一些独特的设计：Python 使用英语单词 \u003ccode\u003eand\u003c/code\u003e、\u003ccode\u003eor\u003c/code\u003e、\u003ccode\u003enot\u003c/code\u003e 而不是 \u003ccode\u003e\u0026amp;\u0026amp;\u003c/code\u003e、\u003ccode\u003e||\u003c/code\u003e、\u003ccode\u003e!\u003c/code\u003e 这样的符号，这使得代码更接近自然语言，可读性更强。更重要的是，Python 的逻辑运算符遵循短路求值原则，这不仅提高了代码效率，还为编写安全的代码提供了独特的手段。\u003c/p\u003e\n\u003ch2 id=\"逻辑运算符基础\"\u003e逻辑运算符基础\u003c/h2\u003e\n\u003ch3 id=\"and逻辑与\"\u003eand（逻辑与）\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003eand\u003c/code\u003e 运算符当且仅当两个操作数都为 \u003ccode\u003eTrue\u003c/code\u003e 时结果才为 \u003ccode\u003eTrue\u003c/code\u003e。在任何其他情况下，结果都是 \u003ccode\u003eFalse\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# and 运算符的真值表\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;=\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;and 运算符真值表\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;=\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;True  and True  = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;True  and False = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;False and True  = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;False and False = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# and 运算符返回的是最后一个求值的表达式，而不是单纯的 True/False\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;and 返回的值：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;1 and 2  = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)     \u003cspan style=\"color:#75715e\"\u003e# 返回 2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;1 and 0  = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)     \u003cspan style=\"color:#75715e\"\u003e# 返回 0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;0 and 1  = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)     \u003cspan style=\"color:#75715e\"\u003e# 返回 0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#39;a\u0026#39; and \u0026#39;b\u0026#39; = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;a\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;b\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 返回 \u0026#39;b\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#39;\u0026#39; and \u0026#39;b\u0026#39; = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;b\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)    \u003cspan style=\"color:#75715e\"\u003e# 返回 \u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"or逻辑或\"\u003eor（逻辑或）\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003eor\u003c/code\u003e 运算符当任意一个操作数为 \u003ccode\u003eTrue\u003c/code\u003e 时结果就为 \u003ccode\u003eTrue\u003c/code\u003e。只有两个操作数都为 \u003ccode\u003eFalse\u003c/code\u003e 时结果才为 \u003ccode\u003eFalse\u003c/code\u003e。\u003c/p\u003e","tags":"Python, 编程","title":"Python 第五课：逻辑运算符、短路求值与链式比较"},{"columns":"acp-course","content":"Day 5：VPC专有网络与NAT网关 本文基于阿里云ACP云计算工程师认证课程内容整理，涵盖VPC专有网络核心架构、NAT网关原理与实践，以及企业级网络规划最佳实践。\n一、VPC专有网络核心概念与逻辑架构 专有网络VPC（Virtual Private Cloud） 是阿里云基于飞天云平台构建的逻辑隔离私有网络，为用户提供完全可控的云上私有网络环境。与传统经典网络相比，VPC允许用户自主规划IP地址范围、配置路由表、部署网关设备，实现与传统数据中心一致的 网络体验，同时兼具云端的弹性与高可用优势。\nVPC的三大核心组件 组件 作用 说明 私网网段 定义VPC地址空间 支持10.0.0.0/8、172.16.0.0/12、192.168.0.0/16及其子网 路由器（vRouter） VPC网络枢纽 连接各交换机，同时作为VPC与外部网络的网关 交换机（vSwitch） 基础连接设备 部署在特定可用区内，连接云资源实例 VPC的逻辑架构 VPC采用数据通路与配置通路分离的设计：\n数据通路：交换机（分布式节点）+ 网关组成，所有链路冗余容灾 配置通路：控制器下发转发表到网关和交换机，基于自研协议实现 这种架构确保了控制面与数据面的解耦，使VPC具备电信级的高可用保障。系统路由自动创建，用户可创建自定义路由表与交换机绑定，实现精细化的流量管理。\nVPC的显著特点 完全掌控：用户自主选择IP地址范围、配置路由表和网关 灵活互联：通过高速通道、VPN网关、云企业网CEN连接其他VPC或本地IDC 高可用：支持跨可用区部署，单可用区故障不影响整体网络 安全隔离：网络ACL、安全组多层次访问控制 考试要点：VPC是地域级别资源，不支持跨地域部署。一个VPC最多包含10张路由表（含系统路由表），一个交换机只能绑定一张路由表。\n二、VPC路由器、交换机与路由表深度解析 交换机（vSwitch） 交换机是组成VPC的基础网络设备，用于连接不同的云资源实例。其关键特性：\n可用区绑定：交换机属于特定可用区，不可跨可用区部署 网段约束：交换机网段必须是所属VPC网段的子集，掩码范围16~29位 容灾建议：生产环境至少创建2个跨可用区的交换机 路由表类型 系统路由表 - 创建VPC后自动生成 - 不可删除、不可手动创建 - 可添加自定义路由条目 自定义路由表 - 用户自行创建 - 与交换机绑定（一个交换机只能绑定一张） - 多个交换机可绑定同一张自定义路由表 网关路由表 - 与IPv4网关绑定，控制公网流量路由路由条目类型 类型 说明 可修改性 系统路由 VPC内默认路由，管理基础流量 不可修改 自定义路由 用户添加的路由规则 可添加、删除 动态路由 通过CEN/VPN/BGP学习到的路由 自动更新 路由匹配采用最长前缀匹配原则（Longest Prefix Match），这与Internet路由协议标准一致。\nVPC安全配置 VPC提供多层次的安全防护体系：\n网络ACL：绑定交换机，控制子网级别入站/出站流量 安全组：虚拟防火墙，具备状态检测能力，控制ECS实例级别流量 RDS白名单：仅允许指定IP访问数据库实例 SLB白名单：限制允许转发请求的客户端IP 三、NAT网关原理、类型与配置实践 NAT网关概述 NAT网关（NAT Gateway） 是阿里云提供的网络地址转换服务，提供SNAT（源地址转换）和DNAT（目标地址转换）能力。阿里云NAT网关分为两种类型：\n公网NAT网关 vs VPC NAT网关 特性 公网NAT网关 VPC NAT网关 转换类型 公网地址转换 私网地址转换 场景 VPC内ECS访问公网；公网访问VPC内服务 VPC间私网互通；VPC访问本地IDC 绑定 需要绑定EIP 使用中转私网地址（NAT IP） 公网NAT网关核心能力 100 Gbps 转发能力，跨可用区高可用部署 SNAT功能：让VPC内无公网IP的ECS实例通过NAT网关访问公网，隐藏内部网络结构 DNAT功能：通过端口映射或IP映射，将NAT网关的公网IP映射到VPC内特定ECS，提供公网服务 按量计费（CU容量，按小时计费），无需预估性能峰值 SNAT条目配置粒度 公网NAT网关的SNAT支持多种配置粒度：\nVPC粒度：整个VPC下的所有ECS共享同一个公网出口 交换机粒度：指定子网内的ECS通过配置的公网IP访问互联网 ECS粒度：单个指定ECS实例访问公网 自定义网段粒度：任意网段下的ECS通过SNAT规则访问 NAT网关配置流程 创建NAT网关 → 绑定EIP（可选）→ 创建SNAT/DNAT条目 → 连通性测试VPC NAT网关典型应用 VPC互访地址冲突解决：两个需要互通的VPC网段冲突时，各配置一个VPC NAT网关，使用不冲突的中转私网地址 混合云指定地址互访：使用固定私网地址访问其他网络 考试要点：公网NAT网关的SNAT功能可屏蔽VPC内ECS对外的端口，保护内部网络免受外部入侵攻击。VPC NAT网关支持SNAT和DNAT双向转换能力。\n四、VPC与NAT网关最佳实践及认证关键点 VPC网络规划最佳实践 单VPC vs 多VPC策略 场景 推荐方案 无多地域部署需求，各系统无需严格隔离 单VPC 多地域部署系统 多VPC + 云企业网CEN 需严格隔离生产/测试环境 多VPC + VPC对等连接 网段规划原则 唯一VPC：可使用10.0.0.0/8、172.16.0.0/12、192.168.0.0/16或其子网 多VPC或混合云：使用标准网段子网，掩码不超过16位，彼此不冲突 交换机规划：建议至少2个跨可用区交换机，掩码16~29位 公网类产品选型对比 产品 适用场景 ECS固定公网IP 需要固定公网地址，不可动态解绑 弹性公网IP（EIP） 需要动态绑定/解绑，支持SNAT和DNAT NAT网关 多ECS共享访问公网，或提供公网服务 负载均衡SLB 四层/七层负载均衡，公网访问入口 NAT网关应用实践 场景一：搭建SNAT网关（VPC内ECS主动访问公网） VPC私网ECS → NAT网关 → 公网配置要点：创建公网NAT网关 → 绑定EIP → 创建SNAT条目（VPC粒度或交换机粒度）\n场景二：搭建DNAT网关（公网访问VPC内服务） 公网用户 → NAT网关（公网IP:端口）→ VPC内ECS（私网IP:端口）配置要点：创建公网NAT网关 → 绑定EIP → 创建DNAT条目（端口映射或IP映射）\nACP认证核心知识点速查 VPC组成：私网网段 + 路由器 + 交换机 路由器作用：连接交换机与外部网络，根据路由表转发流量 NAT网关：提供SNAT（源地址转换）和DNAT（目标地址转换） VPC安全：网络ACL（子网级）+ 安全组（实例级）+ 白名单 多VPC互通：云企业网CEN、对等连接、VPN网关 公网访问：EIP（独立绑定）+ NAT网关（共享访问） 路由匹配原则：最长前缀匹配（Longest Prefix Match） 交换机规划：至少2个跨可用区，网段为VPC子集，掩码16~29位 典型实验流程（沙箱环境） 创建VPC → 创建交换机 → 创建自定义路由表 → 添加路由条目 → 绑定交换机与路由表 → 创建NAT网关 → 绑定EIP → 配置SNAT/DNAT → 连通性测试 相关推荐：\nDay 4：负载均衡SLB原理与实践 Day 6：对象存储OSS处理图片 阿里云NAT网关官方文档 ","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-05-acp-day-5-vpc-nat/","summary":"\u003ch1 id=\"day-5vpc专有网络与nat网关\"\u003eDay 5：VPC专有网络与NAT网关\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e本文基于阿里云ACP云计算工程师认证课程内容整理，涵盖VPC专有网络核心架构、NAT网关原理与实践，以及企业级网络规划最佳实践。\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一vpc专有网络核心概念与逻辑架构\"\u003e一、VPC专有网络核心概念与逻辑架构\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e专有网络VPC（Virtual Private Cloud）\u003c/strong\u003e 是阿里云基于飞天云平台构建的逻辑隔离私有网络，为用户提供完全可控的云上私有网络环境。与传统经典网络相比，VPC允许用户自主规划IP地址范围、配置路由表、部署网关设备，实现与传统数据中心一致的 网络体验，同时兼具云端的弹性与高可用优势。\u003c/p\u003e\n\u003ch3 id=\"vpc的三大核心组件\"\u003eVPC的三大核心组件\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e组件\u003c/th\u003e\n          \u003cth\u003e作用\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e私网网段\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e定义VPC地址空间\u003c/td\u003e\n          \u003ctd\u003e支持10.0.0.0/8、172.16.0.0/12、192.168.0.0/16及其子网\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e路由器（vRouter）\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eVPC网络枢纽\u003c/td\u003e\n          \u003ctd\u003e连接各交换机，同时作为VPC与外部网络的网关\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e交换机（vSwitch）\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e基础连接设备\u003c/td\u003e\n          \u003ctd\u003e部署在特定可用区内，连接云资源实例\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"vpc的逻辑架构\"\u003eVPC的逻辑架构\u003c/h3\u003e\n\u003cp\u003eVPC采用\u003cstrong\u003e数据通路与配置通路分离\u003c/strong\u003e的设计：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e数据通路\u003c/strong\u003e：交换机（分布式节点）+ 网关组成，所有链路冗余容灾\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e配置通路\u003c/strong\u003e：控制器下发转发表到网关和交换机，基于自研协议实现\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这种架构确保了控制面与数据面的解耦，使VPC具备电信级的高可用保障。系统路由自动创建，用户可创建自定义路由表与交换机绑定，实现精细化的流量管理。\u003c/p\u003e\n\u003ch3 id=\"vpc的显著特点\"\u003eVPC的显著特点\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e完全掌控\u003c/strong\u003e：用户自主选择IP地址范围、配置路由表和网关\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e灵活互联\u003c/strong\u003e：通过高速通道、VPN网关、云企业网CEN连接其他VPC或本地IDC\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e高可用\u003c/strong\u003e：支持跨可用区部署，单可用区故障不影响整体网络\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e安全隔离\u003c/strong\u003e：网络ACL、安全组多层次访问控制\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e考试要点\u003c/strong\u003e：VPC是地域级别资源，不支持跨地域部署。一个VPC最多包含10张路由表（含系统路由表），一个交换机只能绑定一张路由表。\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"二vpc路由器交换机与路由表深度解析\"\u003e二、VPC路由器、交换机与路由表深度解析\u003c/h2\u003e\n\u003ch3 id=\"交换机vswitch\"\u003e交换机（vSwitch）\u003c/h3\u003e\n\u003cp\u003e交换机是组成VPC的基础网络设备，用于连接不同的云资源实例。其关键特性：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e可用区绑定\u003c/strong\u003e：交换机属于特定可用区，不可跨可用区部署\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e网段约束\u003c/strong\u003e：交换机网段必须是所属VPC网段的子集，掩码范围16~29位\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e容灾建议\u003c/strong\u003e：生产环境至少创建2个跨可用区的交换机\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"路由表类型\"\u003e路由表类型\u003c/h3\u003e\n系统路由表\n  - 创建VPC后自动生成\n  - 不可删除、不可手动创建\n  - 可添加自定义路由条目\n\n自定义路由表\n  - 用户自行创建\n  - 与交换机绑定（一个交换机只能绑定一张）\n  - 多个交换机可绑定同一张自定义路由表\n\n网关路由表\n  - 与IPv4网关绑定，控制公网流量路由\u003ch3 id=\"路由条目类型\"\u003e路由条目类型\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e类型\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n          \u003cth\u003e可修改性\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e系统路由\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eVPC内默认路由，管理基础流量\u003c/td\u003e\n          \u003ctd\u003e不可修改\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e自定义路由\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e用户添加的路由规则\u003c/td\u003e\n          \u003ctd\u003e可添加、删除\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e动态路由\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e通过CEN/VPN/BGP学习到的路由\u003c/td\u003e\n          \u003ctd\u003e自动更新\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e路由匹配采用\u003cstrong\u003e最长前缀匹配原则（Longest Prefix Match）\u003c/strong\u003e，这与Internet路由协议标准一致。\u003c/p\u003e","tags":"Alibaba Cloud, VPC, NAT网关, ACP, 云计算","title":"Day 5: VPC专有网络与NAT网关 - ACP云计算工程师认证"},{"columns":"python-course","content":" 来源：03_循环 hm_01~hm_07 + Python官方文档 + 网络资料整理\n一、详细讲解 1.1 核心概念 while循环是Python编程中的重要知识点，在本课程的第6天我们将系统学习while循环、计数器控制、无限循环、以及while-else结构的完整知识体系。\nwhile循环是一种条件驱动的循环结构，它会在条件为True时反复执行代码块，直到条件变为False为止。这种循环特别适用于迭代次数不确定的场景，比如等待用户输入、读取文件直到结束、或者进行未知次数的搜索操作。\n与for循环不同，while循环需要程序员手动管理循环变量，确保循环最终能够终止，否则会产生无限循环。因此，使用while循环时需要格外注意循环条件的设置和计数器变量的更新。\n1.2 while循环语法详解 1.2.1 基本语法结构 # while循环的基本语法 while 条件表达式: # 循环体 - 当条件为True时执行 语句块 语法说明：\n条件表达式是一个布尔值或可以转换为布尔值的表达式 当条件为True时，执行循环体中的语句 执行完循环体后，会再次评估条件表达式 这个过程重复进行，直到条件变为False 1.2.2 计数循环的实现 # 计数器初始化 counter = 0 # 条件判断 while counter \u0026lt; 5: # 循环体 print(f\u0026#34;计数器当前值: {counter}\u0026#34;) # 计数器更新 - 这是防止无限循环的关键 counter += 1 print(\u0026#34;循环结束\u0026#34;) 运行结果：\n计数器当前值: 0 计数器当前值: 1 计数器当前值: 2 计数器当前值: 3 计数器当前值: 4 循环结束1.3 while循环的执行流程 ┌─────────────────┐ │ 初始化计数器 │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ 评估条件表达式 │◄──────────┐ └────────┬────────┘ │ │ │ 条件为True? │ │ │ ┌────┴────┐ │ │ │ │ Yes No │ │ │ │ ▼ ▼ │ ┌─────────┐ ┌─────────┐ │ │ 执行循环体│ │ 退出循环 │ │ │ 更新计数器│ └─────────┘ │ └────┬────┘ │ │ │ └────────────────────────┘1.4 实用示例 1.4.1 1~100累加求和 # 计算1到100的累加和 i = 1 # 初始化计数器，起始值为1 total = 0 # 初始化求和变量 while i \u0026lt;= 100: # 条件：i小于等于100 total += i # 累加当前i的值 i += 1 # 计数器递增 print(f\u0026#34;1+2+3+...+100 = {total}\u0026#34;) # 输出: 5050 算法分析：\n时间复杂度：O(n)，其中n=100 空间复杂度：O(1)，只使用了两个变量 1.4.2 用户登录验证模拟 # 模拟用户登录验证（最多尝试3次） max_attempts = 3 # 最大尝试次数 attempts = 0 # 当前尝试次数计数器 while attempts \u0026lt; max_attempts: attempts += 1 password = input(f\u0026#34;请输入密码（第{attempts}次尝试）: \u0026#34;) if password == \u0026#34;python123\u0026#34;: print(\u0026#34;登录成功！\u0026#34;) break else: remaining = max_attempts - attempts if remaining \u0026gt; 0: print(f\u0026#34;密码错误，你还有{remaining}次机会\u0026#34;) else: print(\u0026#34;密码错误，账户已被锁定\u0026#34;) 1.4.3 猜数字游戏 # 猜数字游戏 import random target = random.randint(1, 100) # 系统随机生成的目标数字 guess = 0 # 用户猜测的数字 max_guesses = 7 # 最大猜测次数 print(\u0026#34;我已经想好了一个1到100之间的数字\u0026#34;) print(f\u0026#34;你有{max_guesses}次猜测机会\u0026#34;) while guess != target and max_guesses \u0026gt; 0: guess = int(input(\u0026#34;请输入你的猜测: \u0026#34;)) if guess \u0026lt; target: print(\u0026#34;太小了，再试一次！\u0026#34;) elif guess \u0026gt; target: print(\u0026#34;太大了，再试一次！\u0026#34;) max_guesses -= 1 if max_guesses \u0026gt; 0 and guess != target: print(f\u0026#34;剩余猜测次数: {max_guesses}\u0026#34;) if guess == target: print(\u0026#34;恭喜你，猜对了！\u0026#34;) else: print(f\u0026#34;很遗憾，正确答案是{target}\u0026#34;) 1.5 while-else结构 Python的while循环支持可选的else子句，这是Python相比其他语言的一个独特特性。\n1.5.1 语法结构 while 条件表达式: # 循环体 语句块 else: # 当循环正常结束（不是因为break跳出）时执行 else语句块 1.5.2 执行时机说明 # else子句在以下情况会执行： # 1. 循环条件首次变为False时 # 2. 循环体执行完毕，条件仍为True，但继续判断时发现为False # else子句在以下情况不会执行： # 1. 循环被break语句提前终止 # 2. 循环中发生异常（exception） count = 0 while count \u0026lt; 3: print(f\u0026#34;第{count + 1}次循环\u0026#34;) count += 1 else: print(\u0026#34;循环正常结束，else子句被执行\u0026#34;) print(\u0026#34;---分隔线---\u0026#34;) count = 0 while count \u0026lt; 3: print(f\u0026#34;第{count + 1}次循环\u0026#34;) if count == 1: print(\u0026#34;遇到break，强制退出\u0026#34;) break count += 1 else: print(\u0026#34;这一行不会打印，因为循环被break中断\u0026#34;) 输出：\n第1次循环 第2次循环 第3次循环 循环正常结束，else子句被执行 ---分隔线--- 第1次循环 第2次循环 遇到break，强制退出1.5.3 while-else的实际应用 # 查找素数的例子 def find_primes_up_to(n): \u0026#34;\u0026#34;\u0026#34;查找小于等于n的所有素数\u0026#34;\u0026#34;\u0026#34; primes = [] i = 2 while i \u0026lt;= n: is_prime = True j = 2 while j * j \u0026lt;= i: if i % j == 0: is_prime = False break j += 1 else: # 如果内层循环正常结束（不是因为break） # 说明没有找到因子，当前i是素数 primes.append(i) i += 1 else: # 外层循环正常结束 print(f\u0026#34;查找完成，共找到{len(primes)}个素数\u0026#34;) return primes result = find_primes_up_to(30) print(f\u0026#34;30以下的素数: {result}\u0026#34;) 1.6 无限循环及其风险 1.6.1 什么是无限循环 当while循环的条件始终为True时，循环将永远不会自动停止，这就是无限循环。\n# 这是一个无限循环 - 不要轻易尝试！ # while True: # print(\u0026#34;我会一直运行下去...\u0026#34;) 1.6.2 无限循环的常见原因 # 错误示例1：忘记更新计数器 i = 0 while i \u0026lt; 10: print(i) # 忘记写 i += 1 # 这会导致无限循环 # 错误示例2：计数器更新位置错误 i = 0 while i \u0026lt; 10: i += 1 # 更新在打印之前 print(i) # 输出1~10 # 错误示例3：条件永远无法变为False count = 10 while count \u0026gt;= 0: print(count) count += 1 # 方向错了，永远不会小于0 1.6.3 如何安全使用无限循环 # 方法1：使用break条件退出 while True: user_input = input(\u0026#34;输入\u0026#39;quit\u0026#39;退出: \u0026#34;) if user_input == \u0026#39;quit\u0026#39;: break print(f\u0026#34;你输入了: {user_input}\u0026#34;) # 方法2：使用计数器限制 counter = 0 max_iterations = 1000 while True: # 业务逻辑 counter += 1 if counter \u0026gt;= max_iterations: print(\u0026#34;达到最大迭代次数，强制退出\u0026#34;) break # 方法3：结合异常处理 while True: try: number = int(input(\u0026#34;输入一个数字（输入0退出）: \u0026#34;)) if number == 0: print(\u0026#34;退出程序\u0026#34;) break print(f\u0026#34;你输入的数字是: {number}\u0026#34;) except ValueError: print(\u0026#34;输入无效，请输入一个整数\u0026#34;) continue # 继续下一次循环 1.7 计数器模式详解 1.7.1 正向计数 # 正向计数：从start到end start = 1 end = 10 while start \u0026lt;= end: print(start, end=\u0026#34; \u0026#34;) start += 1 # 输出: 1 2 3 4 5 6 7 8 9 10 1.7.2 反向计数 # 反向计数：从end到start start = 1 end = 10 while end \u0026gt;= start: print(end, end=\u0026#34; \u0026#34;) end -= 1 # 输出: 10 9 8 7 6 5 4 3 2 1 1.7.3 步长控制 # 步长为2的计数 i = 0 while i \u0026lt;= 10: print(i, end=\u0026#34; \u0026#34;) i += 2 # 输出: 0 2 4 6 8 10 print() # 自定义步长 start = 1 step = 3 end = 20 while start \u0026lt;= end: print(start, end=\u0026#34; \u0026#34;) start += step # 输出: 1 4 7 10 13 16 19 1.8 while循环的嵌套使用 # while循环的嵌套：打印九九乘法表（前3行） i = 1 while i \u0026lt;= 3: j = 1 line = \u0026#34;\u0026#34; while j \u0026lt;= i: product = i * j line += f\u0026#34;{i}×{j}={product} \u0026#34; j += 1 print(line) i += 1 # 输出: # 1×1=1 # 1×1=2 2×2=4 # 1×1=3 2×2=6 3×3=9 1.9 最佳实践与性能优化 1.9.1 避免在循环中重复计算条件 # 低效写法 while len(items) \u0026gt; 0: item = items.pop() process(item) # 高效写法 n = len(items) # 预先计算长度 while n \u0026gt; 0: item = items.pop() process(item) n -= 1 1.9.2 使用局部变量加速访问 # 对于大量迭代，可以使用局部变量 data = list(range(10000)) # 慢：每次都要查询len i = 0 while i \u0026lt; len(data): data[i] *= 2 i += 1 # 快：使用局部变量 data = list(range(10000)) n = len(data) i = 0 while i \u0026lt; n: data[i] *= 2 i += 1 1.9.3 循环不变式 保持循环不变式的正确性是编写正确while循环的关键：\n# 循环不变式：total始终等于已遍历元素的和 i = 0 total = 0 data = [1, 2, 3, 4, 5] # 循环不变式在循环开始前为真 while i \u0026lt; len(data): # 循环体执行前：total是data[0:i]的和 total += data[i] # 循环体执行后：total是data[0:i+1]的和 i += 1 # 循环结束后：total是data[0:n]的和，即所有元素的和 print(f\u0026#34;总和: {total}\u0026#34;) # 15 1.10 常见错误与调试技巧 # 错误1：缩进错误 i = 0 while i \u0026lt; 5: print(i) # IndentationError: expected an indented block i += 1 # 错误2：使用了比较运算符而非赋值 # i = 0 # while i \u0026lt; 5: # print(i) # i = 5 # 死循环！应该是 i += 1 # 调试技巧：添加日志 debug_mode = True i = 0 while i \u0026lt; 5: if debug_mode: print(f\u0026#34;[DEBUG] i={i}, condition={i\u0026lt;5}\u0026#34;) i += 1 二、背诵版 Day6 要点速记： 【while循环三要素】 1. 初始化计数器 2. 条件判断 3. 更新计数器 【while-else语法】 while 条件: 循环体 else: # 循环正常结束时执行 # break跳出时不执行 【常见错误】 - 忘记更新计数器 → 无限循环 - 计数器更新位置错误 → 逻辑错误 - 条件永远为True → 死循环 【使用场景】 - 迭代次数未知时 - 等待某个条件满足时 - 需要手动控制循环变量时 三、考前记忆 要素 内容 今日主题 while循环基础 关键词 while、计数循环、无限循环、while-else 重要考点 while循环条件控制、else子句执行时机 易错点 忘记更新计数器导致无限循环 语法结构 while 条件: → 循环体 → else: 四、测试题 1. 单选题： 以下哪个是while循环的正确语法？\n# 选项A while i \u0026lt; 10 print(i) i += 1 # 选项B while (i \u0026lt; 10): print(i) i += 1 # 选项C while i \u0026lt; 10 do: print(i) i += 1 # 选项D while i \u0026lt; 10 print(i) i += 1 2. 单选题： 以下代码的输出是什么？\ncount = 0 while count \u0026lt; 3: print(count) count += 1 else: print(\u0026#34;done\u0026#34;) A. 0 1 2 done B. 0 1 2 3 done C. 0 1 2 D. 死循环 3. 判断题： while-else结构中，如果循环被break语句提前终止，else子句会执行。\n4. 填空题： while循环中，用于控制循环次数的变量称为 _______。\n5. 填空题： 当while循环的条件永远为True时，会产生 _______ 循环。\n6. 简答题： 请描述while循环的执行流程，并说明while-else中else子句的执行时机。\n7. 代码题： 编写代码，使用while循环计算1+2+3+\u0026hellip;+50的结果。\n8. 代码题： 编写代码，使用while-else结构查找一个列表中的最大元素。\n9. 综合题： 设计一个简单的 ATM 取款模拟程序，要求：\n用户有1000元余额 每次取款后显示剩余余额 输入0或余额不足时退出 B - while循环需要冒号，选项A/C/D语法错误\nA - count从0开始，输出0,1,2，然后count变为3时条件为False，执行else\n✗ - break终止循环时，else子句不会执行\n计数器 - 用于控制循环次数的变量\n无限（死） - 无限循环会导致程序无法正常结束\nwhile循环执行流程：\n首先评估条件表达式 若为True，执行循环体，然后再次评估条件 若为False，跳过循环体，执行else子句（如果有） else在循环正常结束（条件首次为False）时执行，因break跳出时不执行 i = 1 total = 0 while i \u0026lt;= 50: total += i i += 1 print(f\u0026#34;1+2+3+...+50 = {total}\u0026#34;) # 1275 numbers = [3, 7, 2, 9, 4, 1] if numbers: max_val = numbers[0] index = 1 while index \u0026lt; len(numbers): if numbers[index] \u0026gt; max_val: max_val = numbers[index] index += 1 else: print(f\u0026#34;最大元素是: {max_val}\u0026#34;) balance = 1000 print(\u0026#34;=== ATM 取款模拟 ===\u0026#34;) print(f\u0026#34;您的余额: {balance}元\u0026#34;) while True: amount = int(input(\u0026#34;请输入取款金额（输入0退出）: \u0026#34;)) if amount == 0: print(\u0026#34;感谢使用，再见！\u0026#34;) break if amount \u0026gt; balance: print(f\u0026#34;余额不足！当前余额: {balance}元\u0026#34;) continue balance -= amount print(f\u0026#34;取款成功！剩余余额: {balance}元\u0026#34;) if balance == 0: print(\u0026#34;余额已用完，感谢使用！\u0026#34;) break 五、扩展阅读 5.1 while循环 vs for循环 特性 while循环 for循环 适用场景 迭代次数不确定 迭代次数已知/可迭代对象 循环控制 手动管理计数器 自动管理迭代器 代码复杂度 需要注意计数器更新 更简洁、更安全 灵活性 更高，可实现复杂逻辑 适合遍历操作 5.2 Python 3.10+ 新特性 Python 3.10引入了一些关于循环的改进，但while循环的基本语法保持不变。在现代Python中，推荐使用**海象运算符（:=）**来简化某些while循环：\n# Python 3.8+ # 传统写法 line = input(\u0026#34;Enter a line: \u0026#34;) while line != \u0026#34;quit\u0026#34;: print(f\u0026#34;You entered: {line}\u0026#34;) line = input(\u0026#34;Enter a line: \u0026#34;) # 使用海象运算符（更简洁） while (line := input(\u0026#34;Enter a line: \u0026#34;)) != \u0026#34;quit\u0026#34;: print(f\u0026#34;You entered: {line}\u0026#34;) 恭喜完成Day6学习！明天我们将学习break和continue语句，掌握更精细的循环控制技巧。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-06-while-loop-basics/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：03_循环 hm_01~hm_07 + Python官方文档 + 网络资料整理\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-核心概念\"\u003e1.1 核心概念\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003ewhile循环\u003c/strong\u003e是Python编程中的重要知识点，在本课程的第6天我们将系统学习while循环、计数器控制、无限循环、以及while-else结构的完整知识体系。\u003c/p\u003e\n\u003cp\u003ewhile循环是一种\u003cstrong\u003e条件驱动\u003c/strong\u003e的循环结构，它会在条件为True时反复执行代码块，直到条件变为False为止。这种循环特别适用于\u003cstrong\u003e迭代次数不确定\u003c/strong\u003e的场景，比如等待用户输入、读取文件直到结束、或者进行未知次数的搜索操作。\u003c/p\u003e\n\u003cp\u003e与for循环不同，while循环需要程序员\u003cstrong\u003e手动管理循环变量\u003c/strong\u003e，确保循环最终能够终止，否则会产生\u003cstrong\u003e无限循环\u003c/strong\u003e。因此，使用while循环时需要格外注意循环条件的设置和计数器变量的更新。\u003c/p\u003e\n\u003ch3 id=\"12-while循环语法详解\"\u003e1.2 while循环语法详解\u003c/h3\u003e\n\u003ch4 id=\"121-基本语法结构\"\u003e1.2.1 基本语法结构\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# while循环的基本语法\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewhile\u003c/span\u003e 条件表达式:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 循环体 - 当条件为True时执行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    语句块\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e语法说明：\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e条件表达式\u003c/code\u003e是一个布尔值或可以转换为布尔值的表达式\u003c/li\u003e\n\u003cli\u003e当条件为\u003ccode\u003eTrue\u003c/code\u003e时，执行循环体中的语句\u003c/li\u003e\n\u003cli\u003e执行完循环体后，会再次评估条件表达式\u003c/li\u003e\n\u003cli\u003e这个过程重复进行，直到条件变为\u003ccode\u003eFalse\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"122-计数循环的实现\"\u003e1.2.2 计数循环的实现\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 计数器初始化\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecounter \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 条件判断\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewhile\u003c/span\u003e counter \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 循环体\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;计数器当前值: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecounter\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 计数器更新 - 这是防止无限循环的关键\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    counter \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;循环结束\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e运行结果：\u003c/strong\u003e\u003c/p\u003e\n计数器当前值: 0\n计数器当前值: 1\n计数器当前值: 2\n计数器当前值: 3\n计数器当前值: 4\n循环结束\u003ch3 id=\"13-while循环的执行流程\"\u003e1.3 while循环的执行流程\u003c/h3\u003e\n┌─────────────────┐\n│  初始化计数器   │\n└────────┬────────┘\n         │\n         ▼\n┌─────────────────┐\n│  评估条件表达式  │◄──────────┐\n└────────┬────────┘           │\n         │                    │\n    条件为True?               │\n         │                    │\n    ┌────┴────┐               │\n    │         │               │\n   Yes        No              │\n    │         │               │\n    ▼         ▼               │\n┌─────────┐  ┌─────────┐       │\n│ 执行循环体│  │  退出循环 │       │\n│ 更新计数器│  └─────────┘       │\n└────┬────┘                   │\n     │                        │\n     └────────────────────────┘\u003ch3 id=\"14-实用示例\"\u003e1.4 实用示例\u003c/h3\u003e\n\u003ch4 id=\"141-1100累加求和\"\u003e1.4.1 1~100累加求和\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 计算1到100的累加和\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ei \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e        \u003cspan style=\"color:#75715e\"\u003e# 初始化计数器，起始值为1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etotal \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# 初始化求和变量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewhile\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e:      \u003cspan style=\"color:#75715e\"\u003e# 条件：i小于等于100\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    total \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e i       \u003cspan style=\"color:#75715e\"\u003e# 累加当前i的值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    i \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e            \u003cspan style=\"color:#75715e\"\u003e# 计数器递增\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;1+2+3+...+100 = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etotal\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 输出: 5050\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e算法分析：\u003c/strong\u003e\u003c/p\u003e","tags":"Python, 编程, while","title":"Day6 while循环基础"},{"columns":"acp-course","content":" 来源：Notion ACP学习笔记\nACP Day 6｜应用交付网络 + 全球化网络 今日主题 Day 6：应用交付网络 + 全球化网络\n对应资料：2-05-阿里云应用交付网络 (1).pdf、2-06-阿里云全球化网络.pdf\n重点整理 应用交付网络核心组件包括：负载均衡 SLB、全球加速 GA、弹性公网 IP（EIP）、共享带宽/共享流量包。\n负载均衡 SLB 的价值是把流量分发到多台后端服务器，提升吞吐、消除单点故障、提高系统高可用性。\nSLB 产品按场景可分为：ALB（7层 HTTP/HTTPS/QUIC，适合复杂七层路由与云原生 Ingress）、NLB（4层 TCP/UDP/TCPSSL，适合超高并发连接）、CLB（传统型，兼顾 4 层和 7 层场景）。\nALB 重点记忆：面向七层应用交付，支持 HTTP/HTTPS/HTTP2/WSS/QUIC/GRPC，单实例可达高规格 QPS。\nNLB 重点记忆：面向四层流量，支持 TCP、UDP、TCPSSL，单实例可支持超大规模并发连接。\nGA（全球加速）依托阿里云全球传输网络与 BGP 带宽，实现全球就近接入、跨地域部署，优化公网访问质量，减少时延、抖动和丢包。\nGA 关键组成包括：加速区域、接入点、加速 IP、CNAME、监听、终端节点组、终端节点、终端节点出公网 IP、基础带宽包。\nGA 分为标准型和基础型：标准型支持 4 层/7 层网络加速；基础型主要用于 3 层 IP 协议加速。\nEIP 是独立购买和持有的公网 IP 资源，可绑定到 VPC 类型 ECS、私网 SLB、辅助弹性网卡、NAT 网关和高可用虚拟 IP。\nEIP 相比 ECS 固定公网 IP，更灵活：可独立持有、可弹性绑定解绑、可灵活调整带宽，还可加入共享带宽以节省成本。\n共享带宽是地域级带宽共享与复用能力，支持同地域多个 EIP 共享带宽；共享流量包是公网流量套餐，支持多地域、多产品统一抵扣流量费用。\nCEN（云企业网）是阿里云私有全球网络上的企业级组网服务，用于实现跨地域 VPC 与 VPC、VPC 与本地 IDC 间的私网通信。\nCEN 的核心能力包括：全网互联、安全可靠、快速收敛、简明易用；典型使用流程是创建 CEN → 连接网络实例 → 购买带宽包 → 配置路由/策略 → 测试连通性。\nTR（转发路由器）是 CEN 的核心转发网元，负责同地域或跨地域流量转发，并提供路由表、路由学习、路由策略、关联转发等能力。\n企业版 TR 支持自定义路由表、关联转发与更灵活的管控；基础版 TR 只有默认路由表，路由能力相对简化。\nCEN/TR 典型场景：多地域多 VPC 互通、云上 VPC 与线下 IDC 互通、集团企业或全球化业务的统一私网互联。\n背诵版 SLB 三兄弟：ALB 管 7 层，NLB 管 4 层，CLB 传统通用。\nGA 解决的是全球公网访问质量问题：就近接入、跨地域加速、降时延降丢包。\nEIP 是独立公网 IP；固定公网 IP 跟着 ECS 走，EIP 可以灵活绑/解绑。\n共享带宽看“带宽复用”，共享流量包看“流量抵扣”。\nCEN 是全球私网互联骨干，TR 是 CEN 里的核心转发节点。\nCEN 适合：跨地域 VPC 互通、VPC 与 IDC 私网互通、混合云组网。\n企业版 TR：支持自定义路由表；基础版 TR：只有默认路由表。\n自测题 ALB、NLB、CLB 分别主要面向哪一层场景？ 全球加速 GA 主要解决的是哪类问题？ EIP 与 ECS 固定公网 IP 的最大区别是什么？ 共享带宽和共享流量包的关注重点分别是什么？ CEN 和 TR 在组网中的角色分别是什么？ ","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-06-acp-day-6-%E5%BA%94%E7%94%A8%E4%BA%A4%E4%BB%98%E7%BD%91%E7%BB%9C-%E5%85%A8%E7%90%83%E5%8C%96%E7%BD%91%E7%BB%9C/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：Notion ACP学习笔记\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"acp-day-6应用交付网络--全球化网络\"\u003eACP Day 6｜应用交付网络 + 全球化网络\u003c/h2\u003e\n\u003ch3 id=\"今日主题\"\u003e今日主题\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eDay 6：应用交付网络 + 全球化网络\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e对应资料：2-05-阿里云应用交付网络 (1).pdf、2-06-阿里云全球化网络.pdf\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"重点整理\"\u003e重点整理\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e应用交付网络核心组件包括：负载均衡 SLB、全球加速 GA、弹性公网 IP（EIP）、共享带宽/共享流量包。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e负载均衡 SLB 的价值是把流量分发到多台后端服务器，提升吞吐、消除单点故障、提高系统高可用性。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSLB 产品按场景可分为：ALB（7层 HTTP/HTTPS/QUIC，适合复杂七层路由与云原生 Ingress）、NLB（4层 TCP/UDP/TCPSSL，适合超高并发连接）、CLB（传统型，兼顾 4 层和 7 层场景）。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eALB 重点记忆：面向七层应用交付，支持 HTTP/HTTPS/HTTP2/WSS/QUIC/GRPC，单实例可达高规格 QPS。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eNLB 重点记忆：面向四层流量，支持 TCP、UDP、TCPSSL，单实例可支持超大规模并发连接。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eGA（全球加速）依托阿里云全球传输网络与 BGP 带宽，实现全球就近接入、跨地域部署，优化公网访问质量，减少时延、抖动和丢包。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eGA 关键组成包括：加速区域、接入点、加速 IP、CNAME、监听、终端节点组、终端节点、终端节点出公网 IP、基础带宽包。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eGA 分为标准型和基础型：标准型支持 4 层/7 层网络加速；基础型主要用于 3 层 IP 协议加速。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eEIP 是独立购买和持有的公网 IP 资源，可绑定到 VPC 类型 ECS、私网 SLB、辅助弹性网卡、NAT 网关和高可用虚拟 IP。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eEIP 相比 ECS 固定公网 IP，更灵活：可独立持有、可弹性绑定解绑、可灵活调整带宽，还可加入共享带宽以节省成本。\u003c/p\u003e","tags":"ACP, 阿里云","title":"ACP Day 6 应用交付网络 + 全球化网络"},{"columns":"python-course","content":" 来源：03_循环 hm_06~hm_07 + Python官方文档 + 网络资料整理\n一、详细讲解 1.1 核心概念 循环控制break与continue是Python编程中用于精确控制循环执行流程的两个重要关键字。在本课程的第7天，我们将深入学习break语句、continue语句、以及它们与循环else子句的配合使用。\n在实际的程序开发中，我们经常需要在循环执行过程中根据某些条件提前退出循环（break）或者跳过本次循环的剩余代码（continue）。这两个语句为我们提供了这种精细控制的能力，使得我们可以编写出更加灵活和高效的循环逻辑。\n理解break和continue的区别以及它们对循环else子句的影响，是掌握Python循环控制的关键。\n1.2 break语句详解 1.2.1 break的基本语法 break语句用于立即终止当前所在的最内层循环，并将控制流转移到循环体之外的下一条语句。\n# break语句的语法位置 for 变量 in 序列: if 条件: break # 跳出当前循环 循环体 # while循环中的break while 条件: if 条件: break # 跳出当前循环 循环体 1.2.2 break在for循环中的使用 # 示例1：查找第一个符合条件的元素 fruits = [\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;cherry\u0026#34;, \u0026#34;date\u0026#34;, \u0026#34;elderberry\u0026#34;] for fruit in fruits: if len(fruit) \u0026gt; 5: print(f\u0026#34;第一个长度大于5的水果: {fruit}\u0026#34;) break # 输出: 第一个长度大于5的水果: banana # 示例2：遍历列表，找到目标后立即停止 numbers = [1, 3, 5, 7, 9, 11, 13, 15] target = 11 for num in numbers: if num == target: print(f\u0026#34;找到目标: {target}\u0026#34;) break print(f\u0026#34;检查: {num}\u0026#34;) print(\u0026#34;搜索完成\u0026#34;) 运行结果：\n检查: 1 检查: 3 检查: 5 检查: 7 检查: 9 找到目标: 11 搜索完成1.2.3 break在while循环中的使用 # 示例：模拟用户登录流程 max_attempts = 5 attempts = 0 while attempts \u0026lt; max_attempts: attempts += 1 password = input(f\u0026#34;请输入密码（第{attempts}次尝试）: \u0026#34;) if password == \u0026#34;admin123\u0026#34;: print(\u0026#34;登录成功！\u0026#34;) break else: print(\u0026#34;密码错误\u0026#34;) print(f\u0026#34;最终尝试次数: {attempts}\u0026#34;) 1.2.4 break的嵌套循环使用 # break只会跳出直接包含它的那一层循环 for i in range(1, 4): for j in range(1, 4): print(f\u0026#34;i={i}, j={j}\u0026#34;) if j == 2: break # 只跳出内层循环，外层循环继续 print(\u0026#34;内层循环结束\u0026#34;) print(\u0026#34;\\n--- 外层循环继续 ---\u0026#34;) 输出：\ni=1, j=1 i=1, j=2 内层循环结束 i=2, j=1 i=2, j=2 内层循环结束 i=3, j=1 i=3, j=2 内层循环结束 --- 外层循环继续 ---1.3 continue语句详解 1.3.1 continue的基本语法 continue语句用于跳过本次循环剩余的代码，直接进入下一次循环的判断。\n# continue语句的语法位置 for 变量 in 序列: if 条件: continue # 跳过本次循环剩余代码 循环体（条件为False时执行） # while循环中的continue while 条件: if 条件: continue # 跳过本次循环剩余代码 循环体（条件为False时执行） 1.3.2 continue在for循环中的使用 # 示例1：跳过某些元素，只处理偶数 numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] for num in numbers: if num % 2 != 0: # 奇数跳过 continue print(f\u0026#34;偶数: {num}\u0026#34;) # 示例2：处理数据时跳过无效值 data = [10, 20, 0, 30, 0, 40, 50, 0] print(\u0026#34;处理数据...\u0026#34;) for value in data: if value == 0: print(\u0026#34; [跳过零值]\u0026#34;) continue result = value * 2 print(f\u0026#34; {value} × 2 = {result}\u0026#34;) 运行结果：\n偶数: 2 偶数: 4 偶数: 6 偶数: 8 偶数: 10 处理数据... 10 × 2 = 20 20 × 2 = 40 [跳过零值] 30 × 2 = 60 [跳过零值] 40 × 2 = 80 50 × 2 = 100 [跳过零值]1.3.3 continue在while循环中的使用 # 示例：计算正整数的和，跳过负数和零 values = [5, -3, 0, 8, -1, 12, 0, 7] i = 0 positive_sum = 0 while i \u0026lt; len(values): val = values[i] if val \u0026lt;= 0: i += 1 continue positive_sum += val i += 1 print(f\u0026#34;正整数之和: {positive_sum}\u0026#34;) # 5 + 8 + 12 + 7 = 32 1.3.4 continue使用注意事项 # 警告：continue在while循环中可能导致的陷阱 i = 0 while i \u0026lt; 5: if i == 2: continue # 跳过下面的 i += 1 print(i) i += 1 # 当continue执行时，这行被跳过，导致无限循环！ # 正确写法：确保计数器在continue之前或之后更新 i = 0 while i \u0026lt; 5: if i == 2: i += 1 # 在continue之前更新计数器 continue print(i) i += 1 1.4 break与continue对比 1.4.1 核心区别 特性 break continue 作用范围 终止整个循环 跳过本次循环剩余代码 执行后 跳出循环体，执行循环后的语句 回到循环条件判断 循环else 不执行else子句 会执行else子句 1.4.2 流程对比图 break流程: ┌─────────┐ │ 开始 │ └────┬────┘ ▼ ┌─────────┐ 否 │ 条件判断 ├────────► 执行循环体 └────┬────┘ │是 ▼ ┌─────────┐ │ break │──────────────────┐ └─────────┘ │ │ │ ▼ ▼ ┌─────────┐ ┌─────────┐ │ 循环结束 │ │ 后续代码│ └─────────┘ └─────────┘ continue流程: ┌─────────┐ │ 开始 │ └────┬────┘ ▼ ┌─────────┐ 否 │ 条件判断 ├────────► 执行循环体 └────┬────┘ │是 ▼ ┌─────────┐ │continue │──────────┐ └─────────┘ │ │ │ ▼ ▼ ┌─────────┐ ┌─────────┐ │ 下一次 │◄───┤ 条件判断│ │ 循环 │ └─────────┘ └─────────┘1.5 break/continue与循环else子句 1.5.1 break与else # break会阻止else子句执行 print(\u0026#34;=== break 与 else ===\u0026#34;) for i in range(1, 4): print(f\u0026#34;循环: {i}\u0026#34;) if i == 2: print(\u0026#34;执行break\u0026#34;) break else: print(\u0026#34;else子句: 循环正常结束\u0026#34;) print(\u0026#34;循环后的代码\u0026#34;) print(\u0026#34;\\n=== continue 与 else ===\u0026#34;) # continue不会阻止else子句执行 for i in range(1, 4): print(f\u0026#34;循环: {i}\u0026#34;) if i == 2: print(\u0026#34;执行continue\u0026#34;) continue print(f\u0026#34;处理 {i}\u0026#34;) else: print(\u0026#34;else子句: 循环正常结束\u0026#34;) print(\u0026#34;循环后的代码\u0026#34;) 输出：\n=== break 与 else === 循环: 1 循环: 2 执行break 循环后的代码 === continue 与 else === 循环: 1 处理 1 循环: 2 执行continue 循环: 3 处理 3 else子句: 循环正常结束 循环后的代码1.5.2 实际应用示例 # 示例：验证密码强度 def validate_password(password): \u0026#34;\u0026#34;\u0026#34; 验证密码是否满足所有要求 如果所有要求都满足，返回True 如果任何要求不满足，报告第一个失败的要求 \u0026#34;\u0026#34;\u0026#34; requirements = [ (\u0026#34;长度至少8位\u0026#34;, len(password) \u0026gt;= 8), (\u0026#34;包含数字\u0026#34;, any(c.isdigit() for c in password)), (\u0026#34;包含小写字母\u0026#34;, any(c.islower() for c in password)), (\u0026#34;包含大写字母\u0026#34;, any(c.isupper() for c in password)), ] for desc, passed in requirements: if not passed: print(f\u0026#34;验证失败: {desc}\u0026#34;) return False else: print(\u0026#34;所有验证通过！\u0026#34;) return True # 测试 print(\u0026#34;测试1:\u0026#34;) validate_password(\u0026#34;abc\u0026#34;) print(\u0026#34;\\n测试2:\u0026#34;) validate_password(\u0026#34;Password123\u0026#34;) 1.6 实用场景示例 1.6.1 搜索算法中的break # 在有序列表中进行二分搜索（使用break优化） def binary_search(arr, target): \u0026#34;\u0026#34;\u0026#34; 二分搜索函数 返回目标元素的索引，如果未找到返回-1 \u0026#34;\u0026#34;\u0026#34; left, right = 0, len(arr) - 1 while left \u0026lt;= right: mid = (left + right) // 2 if arr[mid] == target: print(f\u0026#34;找到目标在索引 {mid}\u0026#34;) return mid elif arr[mid] \u0026lt; target: left = mid + 1 else: right = mid - 1 print(\u0026#34;未找到目标\u0026#34;) return -1 # 测试 numbers = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] binary_search(numbers, 7) # 找到目标在索引 3 binary_search(numbers, 8) # 未找到目标 1.6.2 数据处理中的continue # 示例：处理日志文件，跳过空行和注释 log_lines = [ \u0026#34;# 系统日志\u0026#34;, \u0026#34;\u0026#34;, \u0026#34;2024-01-01 10:00:00 系统启动\u0026#34;, \u0026#34;# 调试信息\u0026#34;, \u0026#34;\u0026#34;, \u0026#34;2024-01-01 10:05:23 用户登录\u0026#34;, \u0026#34;2024-01-01 10:10:45 订单提交\u0026#34;, \u0026#34;\u0026#34;, \u0026#34;# 错误日志\u0026#34;, \u0026#34;2024-01-01 10:15:00 支付失败\u0026#34;, ] print(\u0026#34;处理日志...\u0026#34;) line_number = 0 valid_lines = [] for line in log_lines: line_number += 1 # 跳过空行 if not line.strip(): continue # 跳过注释行 if line.strip().startswith(\u0026#34;#\u0026#34;): continue # 处理有效日志行 valid_lines.append(line) print(f\u0026#34; [{line_number}] {line}\u0026#34;) print(f\u0026#34;\\n共处理 {len(valid_lines)} 条有效日志\u0026#34;) 1.6.3 菜单驱动的循环程序 # 菜单驱动的循环程序 def show_menu(): print(\u0026#34;=\u0026#34; * 30) print(\u0026#34; 简易记事本\u0026#34;) print(\u0026#34;=\u0026#34; * 30) print(\u0026#34;1. 添加笔记\u0026#34;) print(\u0026#34;2. 查看所有笔记\u0026#34;) print(\u0026#34;3. 删除笔记\u0026#34;) print(\u0026#34;4. 退出程序\u0026#34;) print(\u0026#34;=\u0026#34; * 30) notes = [] while True: show_menu() choice = input(\u0026#34;请选择操作 (1-4): \u0026#34;) if choice == \u0026#34;1\u0026#34;: note = input(\u0026#34;请输入笔记内容: \u0026#34;) notes.append(note) print(\u0026#34;笔记已添加！\u0026#34;) elif choice == \u0026#34;2\u0026#34;: if not notes: print(\u0026#34;暂无笔记\u0026#34;) else: print(\u0026#34;\\n--- 所有笔记 ---\u0026#34;) for i, note in enumerate(notes, 1): print(f\u0026#34;{i}. {note}\u0026#34;) print() elif choice == \u0026#34;3\u0026#34;: if not notes: print(\u0026#34;暂无笔记可删除\u0026#34;) else: idx = int(input(\u0026#34;请输入要删除的笔记编号: \u0026#34;)) if 1 \u0026lt;= idx \u0026lt;= len(notes): removed = notes.pop(idx - 1) print(f\u0026#34;已删除: {removed}\u0026#34;) else: print(\u0026#34;编号无效\u0026#34;) elif choice == \u0026#34;4\u0026#34;: print(\u0026#34;感谢使用，再见！\u0026#34;) break else: print(\u0026#34;无效选择，请重新输入\u0026#34;) 1.7 最佳实践 1.7.1 避免深层嵌套 # 不推荐：深层嵌套 for i in range(10): for j in range(10): for k in range(10): if condition: break if condition: break if condition: break # 推荐：使用标志变量或重构 found = False for i in range(10): for j in range(10): for k in range(10): if condition: found = True break if found: break if found: break 1.7.2 优先使用for循环和辅助函数 # 对于遍历并筛选的场景，考虑使用列表推导式或filter # 使用continue的场景 result = [] for item in data: if is_valid(item): result.append(process(item)) # 可以简化为列表推导式 result = [process(item) for item in data if is_valid(item)] # 或者使用filter result = list(map(process, filter(is_valid, data))) 1.8 常见错误与调试 1.8.1 break/continue作用域错误 # 错误：break只能跳出直接包含它的循环 for i in range(3): for j in range(3): if j == 1: break # 这只跳出内层循环 print(f\u0026#34;外层循环 i={i}\u0026#34;) # 仍然会执行3次 # 如果需要跳出外层循环，使用以下方法之一： # 方法1：使用标志变量 should_break = False for i in range(3): for j in range(3): if j == 1: should_break = True break if should_break: break print(f\u0026#34;外层循环 i={i}\u0026#34;) # 方法2：使用函数封装 def process Outer(): for i in range(3): for j in range(3): if j == 1: return # 直接返回，跳出所有循环 print(f\u0026#34;外层循环 i={i}\u0026#34;) 1.8.2 continue在while中的计数器陷阱 # 错误示例 counter = 0 while counter \u0026lt; 5: print(f\u0026#34;count: {counter}\u0026#34;) if counter == 2: continue # 跳过下面的 counter += 1！ counter += 1 # 永远执行不到，导致无限循环 1.9 高级应用 1.9.1 带计数的break（模拟switch-case） # 模拟多分支选择 def handle_command(cmd): count = 0 while True: count += 1 if cmd == \u0026#34;start\u0026#34; and count == 1: print(\u0026#34;Starting...\u0026#34;) break elif cmd == \u0026#34;stop\u0026#34; and count == 1: print(\u0026#34;Stopping...\u0026#34;) break elif cmd == \u0026#34;restart\u0026#34; and count == 1: print(\u0026#34;Restarting...\u0026#34;) break else: print(f\u0026#34;Unknown command: {cmd}\u0026#34;) break handle_command(\u0026#34;start\u0026#34;) handle_command(\u0026#34;unknown\u0026#34;) 1.9.2 break模拟do-while循环 # Python没有do-while，可以用break模拟 while True: user_input = input(\u0026#34;输入一个正数: \u0026#34;) number = int(user_input) if number \u0026gt; 0: print(f\u0026#34;你输入了: {number}\u0026#34;) break else: print(\u0026#34;无效输入，请重新输入\u0026#34;) 二、背诵版 Day7 要点速记： 【break语句】 - 作用：立即终止整个循环 - 跳出后：执行循环后的下一条语句 - 与else：break终止的循环不执行else子句 【continue语句】 - 作用：跳过本次循环剩余代码 - 跳转到：下一次循环的条件判断 - 与else：continue不阻止else子句执行 【使用场景】 - break：找到目标后提前退出、用户取消操作、错误发生 - continue：跳过无效数据、跳过特定条件、处理剩余数据 【注意事项】 - break只跳出直接包含它的循环（嵌套循环） - continue在while中要小心计数器更新问题 三、考前记忆 要素 内容 今日主题 循环控制break与continue 关键词 break、continue、循环else break作用 跳出整个循环 continue作用 跳过本次循环剩余代码 break与else break时不执行else continue与else continue时执行else 重要考点 break/continue区别与使用场景 四、测试题 1. 单选题： 以下代码的输出是什么？\nfor i in range(4): if i == 2: break print(i, end=\u0026#34; \u0026#34;) A. 0 1 2 B. 0 1 C. 0 1 2 3 D. 0 1 2 2. 单选题： 以下代码的输出是什么？\nfor i in range(4): if i == 2: continue print(i, end=\u0026#34; \u0026#34;) A. 0 1 2 B. 0 1 3 C. 0 1 2 3 D. 0 1 3. 单选题： 在while循环中使用continue时，需要特别注意什么？\nA. 条件判断的顺序 B. 计数器的更新位置 C. 循环的嵌套层数 D. 变量的命名 4. 判断题： break语句可以同时跳出多层嵌套循环。\n5. 判断题： continue语句会使循环完全终止，不再执行。\n6. 填空题： 当循环被break提前终止时，循环的else子句 _______（填\u0026quot;会\u0026quot;或\u0026quot;不会\u0026quot;）执行。\n7. 填空题： continue语句的作用是跳过本次循环的剩余代码，进入 _______ 次循环。\n8. 简答题： 请描述break和continue的区别，并说明它们对循环else子句的影响。\n9. 代码题： 编写代码，遍历1-100的数字，遇到能被3整除的数时跳过，遇到能被5整除的数时停止。\n10. 代码题： 编写一个简单的质数判断程序，使用continue跳过非质数。\n11. 综合题： 设计一个购物车程序，用户可以： - 添加商品 - 查看购物车 - 结账退出 使用break和continue实现菜单循环控制。\nB - break在i==2时终止循环，输出0 1\nB - continue在i==2时跳过print，继续执行i==3，输出0 1 3\nB - continue会跳过后续代码，如果计数器更新在continue之后，可能导致无限循环\n✗ - break只能跳出直接包含它的那一层循环，不能同时跳出多层\n✗ - continue只跳过本次循环的剩余代码，下一次循环会继续执行\n不会 - break提前终止循环时，else子句不会执行\n下一 - continue跳转到下一次循环的条件判断\nbreak与continue的区别： - break：立即终止整个循环，执行循环后的下一条语句 - continue：跳过本次循环剩余代码，回到循环条件判断 对else子句的影响： - break终止：else子句不执行 - continue跳过：else子句会执行（因为循环是正常结束条件判断的） for num in range(1, 101): if num % 3 == 0: continue # 跳过能被3整除的数 if num % 5 == 0: print(f\u0026#34;\\n遇到{num}，停止\u0026#34;) break # 停止循环 print(num, end=\u0026#34; \u0026#34;) def is_prime(n): if n \u0026lt; 2: return False for i in range(2, n): if n % i == 0: return False return True print(\u0026#34;1-100的质数:\u0026#34;) for num in range(1, 101): if num \u0026lt; 2: continue for divisor in range(2, num): if num % divisor == 0: break else: print(num, end=\u0026#34; \u0026#34;) cart = [] while True: print(\u0026#34;\\n=== 购物车程序 ===\u0026#34;) print(\u0026#34;1. 添加商品\u0026#34;) print(\u0026#34;2. 查看购物车\u0026#34;) print(\u0026#34;3. 结账退出\u0026#34;) choice = input(\u0026#34;请选择: \u0026#34;) if choice == \u0026#34;1\u0026#34;: item = input(\u0026#34;请输入商品名称: \u0026#34;) if not item.strip(): print(\u0026#34;商品名称不能为空\u0026#34;) continue cart.append(item) print(f\u0026#34;已添加: {item}\u0026#34;) elif choice == \u0026#34;2\u0026#34;: if not cart: print(\u0026#34;购物车是空的\u0026#34;) continue print(\u0026#34;\\n--- 购物车内容 ---\u0026#34;) for i, item in enumerate(cart, 1): print(f\u0026#34;{i}. {item}\u0026#34;) print(f\u0026#34;共 {len(cart)} 件商品\u0026#34;) elif choice == \u0026#34;3\u0026#34;: print(\u0026#34;\\n=== 结账 ===\u0026#34;) if cart: print(\u0026#34;您购买了:\u0026#34;) for item in cart: print(f\u0026#34; - {item}\u0026#34;) print(\u0026#34;感谢购物！\u0026#34;) else: print(\u0026#34;购物车是空的\u0026#34;) break else: print(\u0026#34;无效选择，请重新输入\u0026#34;) 五、扩展阅读 5.1 Python 3.10+ 结构化模式匹配 Python 3.10引入了match语句，可以作为复杂的条件判断的替代方案：\n# 传统的if-elif-else def handle_command(cmd): if cmd == \u0026#34;start\u0026#34;: return \u0026#34;Starting...\u0026#34; elif cmd == \u0026#34;stop\u0026#34;: return \u0026#34;Stopping...\u0026#34; elif cmd == \u0026#34;restart\u0026#34;: return \u0026#34;Restarting...\u0026#34; else: return \u0026#34;Unknown command\u0026#34; # 使用match（Python 3.10+） def handle_command(cmd): match cmd: case \u0026#34;start\u0026#34;: return \u0026#34;Starting...\u0026#34; case \u0026#34;stop\u0026#34;: return \u0026#34;Stopping...\u0026#34; case \u0026#34;restart\u0026#34;: return \u0026#34;Restarting...\u0026#34; case _: return \u0026#34;Unknown command\u0026#34; 5.2 itertools中的跳过函数 对于复杂的跳过逻辑，可以考虑使用itertools：\nimport itertools # 使用 itertools.dropwhile 跳过条件满足的元素 data = [1, 2, 3, -1, -2, 4, 5, -3] # 跳过前面的正数（直到遇到负数） result = list(itertools.dropwhile(lambda x: x \u0026gt; 0, data)) print(result) # [-1, -2, 4, 5, -3] # 使用 itertools.takewhile 取满足条件的元素 result = list(itertools.takewhile(lambda x: x \u0026gt; 0, data)) print(result) # [1, 2, 3] 恭喜完成Day7学习！明天我们将学习for循环与range，掌握Python中最常用的迭代方式。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-07-break-continue/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：03_循环 hm_06~hm_07 + Python官方文档 + 网络资料整理\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-核心概念\"\u003e1.1 核心概念\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e循环控制break与continue\u003c/strong\u003e是Python编程中用于精确控制循环执行流程的两个重要关键字。在本课程的第7天，我们将深入学习break语句、continue语句、以及它们与循环else子句的配合使用。\u003c/p\u003e\n\u003cp\u003e在实际的程序开发中，我们经常需要在循环执行过程中根据某些条件\u003cstrong\u003e提前退出循环\u003c/strong\u003e（break）或者\u003cstrong\u003e跳过本次循环的剩余代码\u003c/strong\u003e（continue）。这两个语句为我们提供了这种精细控制的能力，使得我们可以编写出更加灵活和高效的循环逻辑。\u003c/p\u003e\n\u003cp\u003e理解break和continue的区别以及它们对循环else子句的影响，是掌握Python循环控制的关键。\u003c/p\u003e\n\u003ch3 id=\"12-break语句详解\"\u003e1.2 break语句详解\u003c/h3\u003e\n\u003ch4 id=\"121-break的基本语法\"\u003e1.2.1 break的基本语法\u003c/h4\u003e\n\u003cp\u003e\u003ccode\u003ebreak\u003c/code\u003e语句用于\u003cstrong\u003e立即终止\u003c/strong\u003e当前所在的最内层循环，并将控制流转移到循环体之外的下一条语句。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# break语句的语法位置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e 变量 \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e 序列:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e 条件:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ebreak\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# 跳出当前循环\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    循环体\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# while循环中的break\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewhile\u003c/span\u003e 条件:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e 条件:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ebreak\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# 跳出当前循环\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    循环体\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"122-break在for循环中的使用\"\u003e1.2.2 break在for循环中的使用\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 示例1：查找第一个符合条件的元素\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003efruits \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;apple\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;banana\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;cherry\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;date\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;elderberry\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e fruit \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e fruits:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e len(fruit) \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;第一个长度大于5的水果: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003efruit\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ebreak\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 输出: 第一个长度大于5的水果: banana\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 示例2：遍历列表，找到目标后立即停止\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enumbers \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e9\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e11\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e13\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e15\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etarget \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e11\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e num \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e numbers:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e num \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e target:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;找到目标: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etarget\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ebreak\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;检查: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003enum\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;搜索完成\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e运行结果：\u003c/strong\u003e\u003c/p\u003e","tags":"Python, 编程, break, continue","title":"Day7 循环控制break与continue"},{"columns":"acp-course","content":" 来源：Notion ACP学习笔记\nACP Day 7｜操作数据库 RDS 的参数实验 今日主题 Day 7：操作数据库 RDS 的参数实验\n对应资料：07操作数据库RDS的参数实验.pdf\n重点整理 RDS（Relational Database Service）是阿里云关系型数据库服务，支持 MySQL、SQL Server、PostgreSQL、OceanBase 等引擎，提供开箱即用的数据库能力，无需自行运维底层基础设施。\nRDS 实例创建关键配置：实例规格（CPU/内存配比）、存储类型（ESSD PL0-PL3/普通云盘/高效云盘）、网络类型（专有网络 VPC 推荐）、连接地址（生产环境建议只用内网）。\n参数组（Parameter Group）用于批量管理数据库配置参数，确保实例间配置一致。常用参数包括：max_connections（最大连接数）、innodb_buffer_pool_size（InnoDB 缓冲池大小）、character_set_server（字符集，建议 utf8mb4）、wait_timeout（空闲连接超时时间）、long_query_time（慢查询阈值）。\n参数修改分为动态生效和需重启生效两类，修改时需注意影响范围。\nRDS 高可用架构：主备实例（一主一备，自动数据同步，故障自动切换）用于保障业务连续性；只读实例用于读写分离，分担主实例查询压力。主备建议跨可用区部署。\nRDS 备份与恢复：自动备份按策略执行（支持全量备份 + 日志备份），手动备份用于重大变更前。按时间点恢复可恢复到新实例或覆盖原实例。备份保留天数最长 730 天。\nRDS 安全配置：白名单控制 IP 访问（默认 0.0.0.0/0 禁止，生产环境应限制具体 IP）；SSL 加密数据传输；TDE 静态数据加密；审计日志记录 SQL 操作。\nRDS 监控指标：CPU 使用率、内存使用率、IOPS、连接数、QPS/TPS，配合性能洞察进行 SQL 分析与死锁检测。\n背诵版 RDS 核心价值：托管式关系数据库，自带高可用、备份、安全。\n参数组作用：批量管理配置，确保实例配置一致；常见参数：连接数、缓冲池、字符集、慢查询时间。\n高可用：主备自动切换保障连续性，只读实例分担查询压力。\n备份恢复：自动 + 手动两种，按时间点恢复。\n安全三剑客：白名单（访问控制）+ SSL（传输加密）+ TDE（静态加密）。\n自测题 RDS 参数组的主要作用是什么？哪些参数修改需要重启实例？ 主备实例和只读实例的区别是什么？ RDS 备份分为哪两种？恢复方式有哪些？ RDS 白名单的默认策略是什么？生产环境应该如何设置？ 什么场景下需要使用 RDS 只读实例？ ACP Day 7｜万物上云网络 + Week1复习（最终整理版） 今日主题 Day 7：万物上云网络 + Week1复习\n对应资料：/home/文档/学习资料/acp学习/2-07-阿里云万物上云网络 (1).pdf\n本讲核心：把 IDC、企业分支、门店、移动终端、IoT 设备安全、稳定、可靠地接入阿里云\n重点整理 万物上云网络的本质，是解决“云下到云上”的接入问题，覆盖企业分支上云、办公网接云、终端接云、物联设备上云、IDC 混合云互通等场景。\n这部分课件重点是 4 个产品：智能接入网关 SAG、云连接器 CC、VPN 网关、高速通道 Express Connect。\n智能接入网关 SAG（Smart Access Gateway）是阿里云提供的一站式快速上云 SD-WAN 接入服务，强调 Internet 就近接入、加密传输、集中管理、快速收敛。\nSAG 的 3 种产品形态要记住：硬件 CPE、镜像 vCPE、SAG App。分别对应站点接入、虚拟化部署接入、终端接入。\nSAG 的核心能力包括：多链路上云、静态路由 / BGP / OSPF、QoS、访问控制、流日志、健康检查、NAT、安全加密。\nSAG 支持直挂和旁挂两种部署模式：直挂模式下本地流量都经过 SAG；旁挂模式下私网流量可走 SAG，而公网流量仍可走原有出口。\nSAG 的典型场景是：多分支机构上云、多地域业务就近接入、门店网络快速接云、混合云安全互联。\n云连接器 CC（Cloud Connector）面向海量物联网终端，提供基于专用 APN 的一站式定向上云连接服务。\n云连接器的关键词是：物联专网、私网连接云服务、海量连接、超大带宽、超高并发、全链路监控、精细化流量管理。\n云连接器支持访问公网 IP / 域名、VPC 私网地址以及阿里云服务（如 OSS、RDS、ECS），还支持到云上应用或本地 IDC 的定向连接。\n云连接器的基本组成包括：云连接器实例、授权规则、连接地址池；创建时通常需要指定专用 APN、VPC 和交换机。\n云连接器的典型场景是 5G / 物联网终端高速上云，适合车联网、设备联网、海量终端接云。\nVPN 网关（VPN Gateway）是基于 Internet 的加密通道服务，用来把企业数据中心、办公网或互联网客户端与 VPC 安全可靠地连接起来。\nVPN 网关的价值要记住 4 个词：安全、稳定、简单、低成本。安全依赖 IKE / IPsec 加密，稳定依赖双机热备，成本低于物理专线。\nVPN 网关有 2 种网络连接方式：IPsec-VPN 和 SSL-VPN。\nIPsec-VPN 适合本地 IDC / 办公网与 VPC 之间建网，也支持不同 VPC 之间互联；SSL-VPN 适合互联网客户端与 VPC 之间建网，典型场景是远程办公。\nVPN 网关类型上要区分普通型 VPN 网关和国密型 VPN 网关；同时还要理解公网加密隧道与私网加密隧道的差异。\nVPN 网关常见配置流程：创建 VPN 网关 → 创建用户网关 → 创建 IPsec 连接 → 配置路由 → 测试连通性。\n高速通道 Express Connect 是企业数据中心与阿里云之间建立高速、稳定、安全私网通信通道的服务。\n高速通道的本质是“物理专线 + VBR 边界路由器”，通过专线把本地 IDC 接入阿里云，再通过 CEN 打通 VPC。\nVBR（Virtual Border Router）是本地 CPE 和云上 VPC 之间的转发桥梁，支持 BGP，是高速通道架构中的关键组件。\n高速通道的核心优势是：不走公网、低时延、高带宽、安全性强、拓扑灵活，适合金融、政企、大型企业等对网络质量要求高的场景。\n与 VPN 相比，高速通道在网络质量、安全性、传输带宽上更强；VPN 的优势则是成本低、开通快、部署简单。\n高速通道常见流程：申请物理专线端口并完成接入 → 创建 VBR 并配置路由 → 加入云企业网 CEN → 配置阿里云侧和本地 IDC 侧健康检查 / 路由 → 测试连通性。\n高频选型题要这样记：分支 / 门店快速上云优先 SAG；海量物联网终端定向上云优先云连接器；通过公网加密接入云上优先 VPN 网关；对质量、安全和带宽要求最高时优先高速通道。\nWeek1复习 Day1 云计算概述：理解云计算为什么出现，重点是解决传统 IT 资源利用率低、上线慢、运维重的问题，并掌握云计算的弹性与按需特征。\nDay2 计算虚拟化 + CPU / 内存虚拟化：理解虚拟化是 IaaS 的基础，要知道虚拟机如何把计算资源抽象出来并提高资源利用率。\nDay3 阿里云综述：重点记阿里云定位、发展时间线、全球化布局，以及“三条生命线”。\nDay4 网络架构 + IP 编址：重点记 OSI / TCP-IP 分层、私网地址、子网划分、网络层与传输层职责。\nDay5 VPC + NAT：重点记 VPC 的定位与组件，SNAT / DNAT 的区别，以及 NAT 网关的场景。\nDay6 应用交付网络 + 全球化网络：重点记 SLB、GA、EIP、共享带宽 / 共享流量包、CEN、TR 的作用与区别。\nDay7 万物上云网络：重点记 4 个接云产品的定位与场景——SAG、云连接器、VPN 网关、高速通道。\n整个 Week1 的主线可以串成一句话：云计算基础 → 虚拟化 → 阿里云认知 → 网络基础 → 云上网络底座 → 应用交付 / 全球互联 → 云下到云上的接入体系。\n背诵版 分支 / 门店上云：SAG。\n海量 IoT 终端上云：云连接器 CC。\n通过公网加密打通 IDC / 办公网 / 客户端 与 VPC：VPN 网关。\n通过高质量私网专线打通 IDC 与云：高速通道 Express Connect。\nSAG 三形态：硬件 CPE、vCPE、App。\nVPN 两连接方式：IPsec-VPN、SSL-VPN。\n高速通道核心组件：物理专线 + VBR + CEN。\n高频对比：VPN 更便宜更快，高速通道质量更高更安全。\nWeek1 主线：云计算基础 → 虚拟化 → 阿里云综述 → 网络基础 → VPC/NAT → 应交网络 / 全球化网络 → 万物上云网络。\n自测题 智能接入网关 SAG 和 VPN 网关的核心定位有什么不同？ 为什么说云连接器更适合海量物联网终端上云？ IPsec-VPN 和 SSL-VPN 分别适合什么场景？ 高速通道相比 VPN，优势主要体现在哪几个方面？ VBR 在高速通道架构中扮演什么角色？ 如果企业有很多分支门店，需要快速、安全接入云上多地域业务，优先考虑哪种产品？ 如果业务需要通过 5G / 专用 APN 把终端直接接入云上服务，应该想到哪个产品？ 请用一句话串起 Week1 的学习主线。 考点提醒 易考的是“产品定位 + 场景选型 + 组件名称 + 配置流程”。\n最容易混淆的是 SAG、VPN 网关、高速通道三者：一个偏分支 SD-WAN 接入，一个偏公网加密隧道，一个偏物理专线私网互通。\n只要抓住“分支上云 / 物联上云 / 公网加密 / 物理专线”这 4 个关键词，题目基本不容易选错。\n同步状态 本地笔记文件：/root/.openclaw/workspace/memory/2026-03-27-acp-day7.md\n目标计划条目：ACP 21天学习计划 → Day7《万物上云网络 + Week1复习》\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-07-acp-day-7-%E4%B8%87%E7%89%A9%E4%B8%8A%E4%BA%91%E7%BD%91%E7%BB%9C-week1%E5%A4%8D%E4%B9%A0/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：Notion ACP学习笔记\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"acp-day-7操作数据库-rds-的参数实验\"\u003eACP Day 7｜操作数据库 RDS 的参数实验\u003c/h2\u003e\n\u003ch3 id=\"今日主题\"\u003e今日主题\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eDay 7：操作数据库 RDS 的参数实验\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e对应资料：07操作数据库RDS的参数实验.pdf\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"重点整理\"\u003e重点整理\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eRDS（Relational Database Service）是阿里云关系型数据库服务，支持 MySQL、SQL Server、PostgreSQL、OceanBase 等引擎，提供开箱即用的数据库能力，无需自行运维底层基础设施。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRDS 实例创建关键配置：实例规格（CPU/内存配比）、存储类型（ESSD PL0-PL3/普通云盘/高效云盘）、网络类型（专有网络 VPC 推荐）、连接地址（生产环境建议只用内网）。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e参数组（Parameter Group）用于批量管理数据库配置参数，确保实例间配置一致。常用参数包括：max_connections（最大连接数）、innodb_buffer_pool_size（InnoDB 缓冲池大小）、character_set_server（字符集，建议 utf8mb4）、wait_timeout（空闲连接超时时间）、long_query_time（慢查询阈值）。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e参数修改分为动态生效和需重启生效两类，修改时需注意影响范围。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRDS 高可用架构：主备实例（一主一备，自动数据同步，故障自动切换）用于保障业务连续性；只读实例用于读写分离，分担主实例查询压力。主备建议跨可用区部署。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRDS 备份与恢复：自动备份按策略执行（支持全量备份 + 日志备份），手动备份用于重大变更前。按时间点恢复可恢复到新实例或覆盖原实例。备份保留天数最长 730 天。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRDS 安全配置：白名单控制 IP 访问（默认 0.0.0.0/0 禁止，生产环境应限制具体 IP）；SSL 加密数据传输；TDE 静态数据加密；审计日志记录 SQL 操作。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRDS 监控指标：CPU 使用率、内存使用率、IOPS、连接数、QPS/TPS，配合性能洞察进行 SQL 分析与死锁检测。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"背诵版\"\u003e背诵版\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eRDS 核心价值：托管式关系数据库，自带高可用、备份、安全。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e参数组作用：批量管理配置，确保实例配置一致；常见参数：连接数、缓冲池、字符集、慢查询时间。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e高可用：主备自动切换保障连续性，只读实例分担查询压力。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e备份恢复：自动 + 手动两种，按时间点恢复。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e安全三剑客：白名单（访问控制）+ SSL（传输加密）+ TDE（静态加密）。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"自测题\"\u003e自测题\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003col\u003e\n\u003cli\u003eRDS 参数组的主要作用是什么？哪些参数修改需要重启实例？\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e主备实例和只读实例的区别是什么？\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003col start=\"3\"\u003e\n\u003cli\u003eRDS 备份分为哪两种？恢复方式有哪些？\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003col start=\"4\"\u003e\n\u003cli\u003eRDS 白名单的默认策略是什么？生产环境应该如何设置？\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003col start=\"5\"\u003e\n\u003cli\u003e什么场景下需要使用 RDS 只读实例？\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"acp-day-7万物上云网络--week1复习最终整理版\"\u003eACP Day 7｜万物上云网络 + Week1复习（最终整理版）\u003c/h2\u003e\n\u003ch3 id=\"今日主题-1\"\u003e今日主题\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eDay 7：万物上云网络 + Week1复习\u003c/p\u003e","tags":"ACP, 阿里云","title":"ACP Day 7 万物上云网络 + Week1复习"},{"columns":"python-course","content":" 来源：03_循环 hm_01~hm_05 + Python官方文档 + 网络资料整理\n一、详细讲解 1.1 核心概念 for循环与range是Python编程中最常用和重要的迭代结构。在本课程的第8天，我们将系统学习for循环的基本语法、range函数的使用、enumerate和zip等内置函数的配合使用，以及序列解包在for循环中的应用。\nfor循环是一种基于迭代器的循环结构，它依次从可迭代对象中取出每个元素进行处理。与while循环不同，for循环不需要手动管理计数器，Python解释器会自动处理迭代的细节。这使得for循环更加简洁、安全，是处理已知序列或需要遍历元素场景的首选。\n1.2 for循环语法详解 1.2.1 基本语法结构 # for循环的基本语法 for 变量 in 可迭代对象: # 循环体 语句块 1.2.2 遍历各种序列类型 # 遍历字符串 print(\u0026#34;=== 遍历字符串 ===\u0026#34;) for char in \u0026#34;Python\u0026#34;: print(char) # 遍历列表 print(\u0026#34;\\n=== 遍历列表 ===\u0026#34;) fruits = [\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;cherry\u0026#34;] for fruit in fruits: print(fruit) # 遍历元组 print(\u0026#34;\\n=== 遍历元组 ===\u0026#34;) coordinates = (10, 20, 30) for coord in coordinates: print(f\u0026#34;坐标: {coord}\u0026#34;) # 遍历字典（默认遍历键） print(\u0026#34;\\n=== 遍历字典 ===\u0026#34;) person = {\u0026#34;name\u0026#34;: \u0026#34;Alice\u0026#34;, \u0026#34;age\u0026#34;: 30, \u0026#34;city\u0026#34;: \u0026#34;Beijing\u0026#34;} for key in person: print(f\u0026#34;{key}: {person[key]}\u0026#34;) 运行结果：\n=== 遍历字符串 === P y t h o n === 遍历列表 === apple banana cherry === 遍历元组 === 坐标: 10 坐标: 20 坐标: 30 === 遍历字典 === name: Alice age: 30 city: Beijing1.3 range函数详解 1.3.1 range函数语法 range(stop) # 0 到 stop-1 range(start, stop) # start 到 stop-1 range(start, stop, step) # start 到 stop-1，步长为step 1.3.2 range的基本使用 # range(stop) - 从0开始 print(\u0026#34;range(5):\u0026#34;, list(range(5))) # 输出: [0, 1, 2, 3, 4] # range(start, stop) - 指定起始和结束 print(\u0026#34;range(1, 6):\u0026#34;, list(range(1, 6))) # 输出: [1, 2, 3, 4, 5] # range(start, stop, step) - 指定步长 print(\u0026#34;range(0, 10, 2):\u0026#34;, list(range(0, 10, 2))) # 输出: [0, 2, 4, 6, 8] # 负数步长 - 倒序 print(\u0026#34;range(10, 0, -1):\u0026#34;, list(range(10, 0, -1))) # 输出: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 负数步长 - 不包含结束值 print(\u0026#34;range(10, 0, -2):\u0026#34;, list(range(10, 0, -2))) # 输出: [10, 8, 6, 4, 2] 1.3.3 range的常见用法 # 1~100累加求和 total = sum(range(1, 101)) print(f\u0026#34;1+2+...+100 = {total}\u0026#34;) # 5050 # 生成指定长度的序列 print(\u0026#34;range(10):\u0026#34;, list(range(10))) # 倒序遍历 for i in range(5, 0, -1): print(f\u0026#34;倒计时: {i}\u0026#34;) print(\u0026#34;发射！\u0026#34;) # 遍历列表的索引 colors = [\u0026#34;红\u0026#34;, \u0026#34;绿\u0026#34;, \u0026#34;蓝\u0026#34;] for i in range(len(colors)): print(f\u0026#34;第{i+1}个颜色: {colors[i]}\u0026#34;) 1.4 enumerate函数详解 1.4.1 enumerate的基本语法 enumerate()函数用于在遍历序列时同时获取元素的索引和值。\nenumerate(iterable, start=0) # 返回: (索引, 值) 的元组 1.4.2 enumerate的使用示例 # 基本用法 fruits = [\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;cherry\u0026#34;] for index, fruit in enumerate(fruits): print(f\u0026#34;{index}: {fruit}\u0026#34;) # 输出: # 0: apple # 1: banana # 2: cherry # 指定起始索引 print(\u0026#34;\\n从1开始编号:\u0026#34;) for index, fruit in enumerate(fruits, start=1): print(f\u0026#34;{index}: {fruit}\u0026#34;) # 输出: # 1: apple # 2: banana # 3: cherry 1.4.3 enumerate的实际应用 # 应用1：同时遍历索引和值 scores = [85, 92, 78, 95, 88] print(\u0026#34;=== 成绩单 ===\u0026#34;) for i, score in enumerate(scores, 1): status = \u0026#34;及格\u0026#34; if score \u0026gt;= 60 else \u0026#34;不及格\u0026#34; print(f\u0026#34;第{i}名学生: {score}分 ({status})\u0026#34;) # 应用2：构建字典 names = [\u0026#34;Alice\u0026#34;, \u0026#34;Bob\u0026#34;, \u0026#34;Charlie\u0026#34;] # 传统方式 name_dict = {} for i, name in enumerate(names): name_dict[i] = name print(f\u0026#34;\\n构建的字典: {name_dict}\u0026#34;) # 应用3：enumerate与条件判断 data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] print(\u0026#34;\\n=== 查找偶数 ===\u0026#34;) for i, num in enumerate(data): if num % 2 == 0: print(f\u0026#34;索引{i}: {num}是偶数\u0026#34;) 1.5 zip函数详解 1.5.1 zip的基本语法 zip()函数用于将多个可迭代对象的对应元素打包成元组。\nzip(iterable1, iterable2, ...) # 返回: 迭代器，产生 (元素1, 元素2, ...) 的元组 1.5.2 zip的使用示例 # 基本用法 - 合并两个列表 names = [\u0026#34;Alice\u0026#34;, \u0026#34;Bob\u0026#34;, \u0026#34;Charlie\u0026#34;] ages = [25, 30, 35] print(\u0026#34;=== 人员信息 ===\u0026#34;) for name, age in zip(names, ages): print(f\u0026#34;{name}: {age}岁\u0026#34;) # 输出: # Alice: 25岁 # Bob: 30岁 # Charlie: 35岁 # 合并多个列表 students = [\u0026#34;张三\u0026#34;, \u0026#34;李四\u0026#34;, \u0026#34;王五\u0026#34;] math_scores = [85, 92, 78] english_scores = [90, 88, 95] print(\u0026#34;\\n=== 学生成绩表 ===\u0026#34;) print(f\u0026#34;{\u0026#39;姓名\u0026#39;:\u0026lt;6} {\u0026#39;数学\u0026#39;:\u0026lt;6} {\u0026#39;英语\u0026#39;:\u0026lt;6}\u0026#34;) print(\u0026#34;-\u0026#34; * 20) for name, math, english in zip(students, math_scores, english_scores): print(f\u0026#34;{name:\u0026lt;6} {math:\u0026lt;6} {english:\u0026lt;6}\u0026#34;) # 创建字典 keys = [\u0026#34;name\u0026#34;, \u0026#34;age\u0026#34;, \u0026#34;city\u0026#34;] values = [\u0026#34;Alice\u0026#34;, 30, \u0026#34;Beijing\u0026#34;] person_dict = dict(zip(keys, values)) print(f\u0026#34;\\n合并为字典: {person_dict}\u0026#34;) 1.5.3 zip的注意事项 # zip会按照最短序列截断 list1 = [1, 2, 3, 4, 5] list2 = [\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;] result = list(zip(list1, list2)) print(f\u0026#34;不等长列表zip: {result}\u0026#34;) # 输出: [(1, \u0026#39;a\u0026#39;), (2, \u0026#39;b\u0026#39;), (3, \u0026#39;c\u0026#39;)] # 使用zip_longest处理不等长序列（需要itertools） from itertools import zip_longest list1 = [1, 2, 3, 4, 5] list2 = [\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;] result = list(zip_longest(list1, list2, fillvalue=None)) print(f\u0026#34;zip_longest结果: {result}\u0026#34;) # 输出: [(1, \u0026#39;a\u0026#39;), (2, \u0026#39;b\u0026#39;), (3, \u0026#39;c\u0026#39;), (4, None), (5, None)] 1.6 序列解包在for循环中的应用 1.6.1 基本解包 # 使用enumerate进行解包 pairs = [(1, \u0026#34;one\u0026#34;), (2, \u0026#34;two\u0026#34;), (3, \u0026#34;three\u0026#34;)] for number, word in pairs: print(f\u0026#34;{number} -\u0026gt; {word}\u0026#34;) # 使用zip进行解包 keys = [\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;] values = [1, 2, 3] for k, v in zip(keys, values): print(f\u0026#34;{k} = {v}\u0026#34;) 1.6.2 使用*进行解包 # 使用 * 解包剩余元素 first, *middle, last = [1, 2, 3, 4, 5] print(f\u0026#34;first={first}, middle={middle}, last={last}\u0026#34;) # first=1, middle=[2, 3, 4], last=5 # 在for循环中解包嵌套结构 students = [ (\u0026#34;张三\u0026#34;, [85, 90, 78]), (\u0026#34;李四\u0026#34;, [92, 88, 95]), (\u0026#34;王五\u0026#34;, [77, 82, 89]) ] print(\u0026#34;\\n=== 学生成绩 ===\u0026#34;) for name, scores in students: avg = sum(scores) / len(scores) print(f\u0026#34;{name}: 平均分 {avg:.1f}\u0026#34;) # 使用 enumerate 和解包 data = [10, 20, 30] for i, (first, second) in enumerate(zip(data, data[1:])): print(f\u0026#34;第{i}组: {first} + {second} = {first + second}\u0026#34;) 1.7 for-else结构 与while循环一样，for循环也支持else子句。\n# for-else语法 for 变量 in 可迭代对象: 循环体 else: # 循环正常结束后执行 else语句块 # 示例：查找质数 def find_primes(n): primes = [] for num in range(2, n + 1): for i in range(2, int(num ** 0.5) + 1): if num % i == 0: break else: primes.append(num) return primes print(f\u0026#34;2-30之间的质数: {find_primes(30)}\u0026#34;) 1.8 for循环的嵌套 # for循环嵌套：打印九九乘法表 print(\u0026#34;=== 九九乘法表 ===\u0026#34;) for i in range(1, 10): for j in range(1, i + 1): print(f\u0026#34;{j}×{i}={i*j}\u0026#34;, end=\u0026#34;\\t\u0026#34;) print() # 换行 输出：\n=== 九九乘法表 === 1×1=1\t2×1=2\t2×2=4\t3×1=3\t2×3=6\t3×3=9\t4×1=4\t2×4=8\t3×4=12\t4×4=16\t5×1=5\t2×5=10\t3×5=15\t4×5=20\t5×5=25\t6×1=6\t2×6=12\t3×6=18\t4×6=24\t5×6=30\t6×6=36\t7×1=7\t2×7=14\t3×7=21\t4×7=28\t5×7=35\t6×7=42\t7×7=49\t8×1=8\t2×8=16\t3×8=24\t4×8=32\t5×8=40\t6×8=48\t7×8=56\t8×8=64\t9×1=9\t2×9=18\t3×9=27\t4×9=36\t5×9=45\t6×9=54\t7×9=63\t8×9=72\t9×9=81\t1.9 实用示例 1.9.1 列表操作 # 列表去重（保持顺序） def remove_duplicates(lst): seen = set() result = [] for item in lst: if item not in seen: seen.add(item) result.append(item) return result numbers = [1, 2, 2, 3, 1, 4, 3, 5] print(f\u0026#34;去重后: {remove_duplicates(numbers)}\u0026#34;) # 输出: [1, 2, 3, 4, 5] # 列表过滤 def filter_even(numbers): return [n for n in numbers if n % 2 == 0] nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] print(f\u0026#34;偶数: {filter_even(nums)}\u0026#34;) # 输出: [2, 4, 6, 8, 10] 1.9.2 字符串处理 # 统计字符出现频率 text = \u0026#34;hello world\u0026#34; char_count = {} for char in text: if char != \u0026#34; \u0026#34;: # 跳过空格 char_count[char] = char_count.get(char, 0) + 1 print(\u0026#34;字符统计:\u0026#34;) for char, count in sorted(char_count.items()): print(f\u0026#34;\u0026#39;{char}\u0026#39;: {count}次\u0026#34;) # 反转字符串 original = \u0026#34;Python\u0026#34; reversed_str = \u0026#34;\u0026#34;.join(list(reversed(original))) print(f\u0026#34;\\n反转: {original} -\u0026gt; {reversed_str}\u0026#34;) 1.9.3 数据聚合 # 按条件分组 students = [ {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;score\u0026#34;: 85}, {\u0026#34;name\u0026#34;: \u0026#34;李四\u0026#34;, \u0026#34;score\u0026#34;: 92}, {\u0026#34;name\u0026#34;: \u0026#34;王五\u0026#34;, \u0026#34;score\u0026#34;: 78}, {\u0026#34;name\u0026#34;: \u0026#34;赵六\u0026#34;, \u0026#34;score\u0026#34;: 88}, {\u0026#34;name\u0026#34;: \u0026#34;钱七\u0026#34;, \u0026#34;score\u0026#34;: 95} ] # 分组 excellent = [] good = [] passing = [] for student in students: score = student[\u0026#34;score\u0026#34;] if score \u0026gt;= 90: excellent.append(student[\u0026#34;name\u0026#34;]) elif score \u0026gt;= 80: good.append(student[\u0026#34;name\u0026#34;]) else: passing.append(student[\u0026#34;name\u0026#34;]) print(f\u0026#34;优秀(\u0026gt;=90): {excellent}\u0026#34;) print(f\u0026#34;良好(80-89): {good}\u0026#34;) print(f\u0026#34;及格(60-79): {passing}\u0026#34;) 1.10 最佳实践 1.10.1 优先使用内置函数 # 计算总和 - 使用sum而不是手动累加 numbers = [1, 2, 3, 4, 5] total = sum(numbers) # 推荐 # total = 0 # for n in numbers: # total += n # 不推荐 # 查找最大最小值 print(f\u0026#34;最大值: {max(numbers)}\u0026#34;) print(f\u0026#34;最小值: {min(numbers)}\u0026#34;) # 计数 print(f\u0026#34;元素个数: {len(numbers)}\u0026#34;) print(f\u0026#34;元素和: {sum(numbers)}\u0026#34;) print(f\u0026#34;平均值: {sum(numbers) / len(numbers)}\u0026#34;) 1.10.2 使用列表推导式替代简单循环 # 生成平方数列表 n = 10 # 传统循环 squares = [] for i in range(1, n + 1): squares.append(i ** 2) print(f\u0026#34;平方数: {squares}\u0026#34;) # 列表推导式（更简洁） squares = [i ** 2 for i in range(1, n + 1)] print(f\u0026#34;平方数: {squares}\u0026#34;) 1.10.3 合理使用生成器 # 对于大量数据，使用生成器节省内存 def square_numbers(n): for i in range(n): yield i ** 2 # 使用生成器 gen = square_numbers(1000000) print(f\u0026#34;生成器对象: {gen}\u0026#34;) # 惰性求值 - 只在需要时计算 for i, sq in enumerate(square_numbers(10)): print(f\u0026#34;{i}: {sq}\u0026#34;) if i \u0026gt;= 4: break 1.11 常见错误与调试 # 错误1：修改正在遍历的列表 # numbers = [1, 2, 3, 4, 5] # for n in numbers: # if n == 3: # numbers.remove(n) # 危险！可能导致跳过元素 # 正确做法：遍历副本 numbers = [1, 2, 3, 4, 5] for n in numbers[:]: # 遍历副本 if n == 3: numbers.remove(n) print(f\u0026#34;删除后的列表: {numbers}\u0026#34;) # 错误2：忘记zip的不等长截断问题 # list1 = [1, 2, 3] # list2 = [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;, \u0026#39;d\u0026#39;, \u0026#39;e\u0026#39;] # for a, b in zip(list1, list2): # 只遍历到最短长度 # print(a, b) # 正确做法：确保长度一致或使用zip_longest 二、背诵版 Day8 要点速记： 【for循环】 for 变量 in 可迭代对象: 循环体 # 自动从对象中取元素，不需要手动管理计数器 【range函数】 range(stop) # 0 ~ stop-1 range(start, stop) # start ~ stop-1 range(start, stop, step) # 按步长取值 【enumerate】 - 同时获取索引和值 for index, value in enumerate(序列, start=0): 处理 【zip】 - 并行遍历多个序列 for item1, item2 in zip(序列1, 序列2): 处理 【序列解包】 a, b, c = [1, 2, 3] first, *rest, last = [1, 2, 3, 4, 5] 【for-else】 for x in iterable: ... else: # 循环正常结束后执行 ... 三、考前记忆 要素 内容 今日主题 for循环与range 关键词 for、range、enumerate、zip、解包 range参数 range(起点,终点,步长) enumerate返回值 (索引, 值) 元组 zip返回值 (元素1, 元素2, \u0026hellip;) 元组 重要考点 range边界、enumerate解包、zip并行遍历 四、测试题 1. 单选题： 以下哪个range会生成序列 0, 2, 4, 6, 8？\nA. range(0, 9, 2) B. range(0, 10, 2) C. range(0, 8, 2) D. range(2, 10, 2) 2. 单选题： 以下代码的输出是什么？\nfor i, c in enumerate(\u0026#34;ABC\u0026#34;, start=1): print(f\u0026#34;{i}: {c}\u0026#34;) A. 0: A 1: B 2: C B. 1: A 2: B 3: C C. A:1 B:2 C:3 D. 1:A 2:B 3:C 3. 单选题： zip函数在处理不等长序列时会怎么做？\nA. 报错 B. 用None填充 C. 截断到最短序列 D. 无限延长 4. 填空题： 要遍历列表[1,2,3,4,5]的索引，应该使用 _______。\n5. 填空题： range(10, 0, -2) 生成的序列是 _______。\n6. 简答题： 请说明enumerate和zip的区别，以及它们的典型使用场景。\n7. 代码题： 使用for循环和range计算1到100之间所有偶数的和。\n8. 代码题： 使用zip合并两个列表，并创建一个字典： names = [\u0026ldquo;a\u0026rdquo;, \u0026ldquo;b\u0026rdquo;, \u0026ldquo;c\u0026rdquo;] values = [1, 2, 3]\n9. 代码题： 使用enumerate找出列表中第一个负数的位置： data = [5, 3, 7, -2, 8, -1]\n10. 综合题： 设计一个程序，模拟考试成绩统计： - 3个学生，4门课程的成绩 - 计算每个学生的平均分 - 找出每门课程的最高分\nB - range(0, 10, 2) 生成 0, 2, 4, 6, 8（不包含10）\nB - enumerate从start=1开始编号，输出 1: A 2: B 3: C\nC - zip会截断到最短序列的长度\nrange(len(列表)) - for i in range(len(data))可以遍历索引\n10, 8, 6, 4, 2 - 从10开始，步长-2，不包含0\nenumerate：同时获取索引和值 - 适用于需要知道当前位置的场景 - 例如：打印带行号的内容、查找特定位置的元素 zip：并行遍历多个序列 - 适用于需要同时处理多个序列对应元素的场景 - 例如：合并两个列表、构建字典、并行迭代 # 方法1：使用range的步长 total = sum(range(2, 101, 2)) print(f\u0026#34;偶数和: {total}\u0026#34;) # 方法2：使用条件判断 total = 0 for i in range(1, 101): if i % 2 == 0: total += i print(f\u0026#34;偶数和: {total}\u0026#34;) names = [\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;] values = [1, 2, 3] # 使用zip创建字典 result_dict = dict(zip(names, values)) print(f\u0026#34;合并的字典: {result_dict}\u0026#34;) # 或者遍历方式 result_dict = {} for name, value in zip(names, values): result_dict[name] = value print(f\u0026#34;合并的字典: {result_dict}\u0026#34;) data = [5, 3, 7, -2, 8, -1] for index, value in enumerate(data): if value \u0026lt; 0: print(f\u0026#34;第一个负数在索引 {index}\u0026#34;) break students = [\u0026#34;张三\u0026#34;, \u0026#34;李四\u0026#34;, \u0026#34;王五\u0026#34;] scores = [ [85, 92, 78, 88], # 张三 [90, 85, 95, 82], # 李四 [78, 88, 80, 90] # 王五 ] courses = [\u0026#34;语文\u0026#34;, \u0026#34;数学\u0026#34;, \u0026#34;英语\u0026#34;, \u0026#34;物理\u0026#34;] # 计算每个学生的平均分 print(\u0026#34;=== 学生平均分 ===\u0026#34;) for i, student in enumerate(students): avg = sum(scores[i]) / len(scores[i]) print(f\u0026#34;{student}: {avg:.1f}分\u0026#34;) # 找出每门课程的最高分 print(\u0026#34;\\n=== 各科最高分 ===\u0026#34;) for j, course in enumerate(courses): max_score = max(score[j] for score in scores) top_student = students[scores[j].index(max_score)] print(f\u0026#34;{course}: {max_score}分 ({top_student})\u0026#34;) 五、扩展阅读 5.1 map和filter函数 # map：对每个元素应用函数 numbers = [1, 2, 3, 4, 5] squares = list(map(lambda x: x ** 2, numbers)) print(f\u0026#34;平方: {squares}\u0026#34;) # filter：过滤满足条件的元素 evens = list(filter(lambda x: x % 2 == 0, numbers)) print(f\u0026#34;偶数: {evens}\u0026#34;) # 组合使用 result = list(map(lambda x: x * 2, filter(lambda x: x \u0026gt; 2, numbers))) print(f\u0026#34;大于2的数翻倍: {result}\u0026#34;) 5.2 itertools模块 import itertools # count: 无限计数器 # cycle: 无限循环迭代 # chain: 连接多个迭代器 # islice: 切片迭代器 # 使用islice模拟range的行为 result = list(itertools.islice(range(10), 0, 10, 2)) print(f\u0026#34;islice结果: {result}\u0026#34;) # [0, 2, 4, 6, 8] 5.3 enumerate的高级用法 # 标记索引进行分组 data = [\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;\u0026#34;, \u0026#34;c\u0026#34;, \u0026#34;\u0026#34;, \u0026#34;d\u0026#34;, \u0026#34;e\u0026#34;] groups = [] current_group = [] for i, item in enumerate(data): if item: current_group.append((i, item)) else: if current_group: groups.append(current_group) current_group = [] if current_group: groups.append(current_group) print(f\u0026#34;分组结果: {groups}\u0026#34;) # 查找连续出现的模式 text = \u0026#34;aaabbbcccdddeee\u0026#34; consecutive = [] current_char = text[0] count = 1 for i in range(1, len(text)): if text[i] == current_char: count += 1 else: consecutive.append((current_char, count)) current_char = text[i] count = 1 consecutive.append((current_char, count)) print(f\u0026#34;连续字符: {consecutive}\u0026#34;) 恭喜完成Day8学习！明天我们将学习嵌套循环与图案打印，掌握复杂循环结构的运用。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-08-for-loop-range/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：03_循环 hm_01~hm_05 + Python官方文档 + 网络资料整理\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-核心概念\"\u003e1.1 核心概念\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003efor循环与range\u003c/strong\u003e是Python编程中最常用和重要的迭代结构。在本课程的第8天，我们将系统学习for循环的基本语法、range函数的使用、enumerate和zip等内置函数的配合使用，以及序列解包在for循环中的应用。\u003c/p\u003e\n\u003cp\u003efor循环是一种\u003cstrong\u003e基于迭代器\u003c/strong\u003e的循环结构，它依次从可迭代对象中取出每个元素进行处理。与while循环不同，for循环不需要手动管理计数器，Python解释器会自动处理迭代的细节。这使得for循环更加简洁、安全，是处理已知序列或需要遍历元素场景的首选。\u003c/p\u003e\n\u003ch3 id=\"12-for循环语法详解\"\u003e1.2 for循环语法详解\u003c/h3\u003e\n\u003ch4 id=\"121-基本语法结构\"\u003e1.2.1 基本语法结构\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# for循环的基本语法\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e 变量 \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e 可迭代对象:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 循环体\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    语句块\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"122-遍历各种序列类型\"\u003e1.2.2 遍历各种序列类型\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 遍历字符串\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;=== 遍历字符串 ===\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e char \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Python\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(char)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 遍历列表\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e=== 遍历列表 ===\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003efruits \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;apple\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;banana\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;cherry\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e fruit \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e fruits:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(fruit)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 遍历元组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e=== 遍历元组 ===\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecoordinates \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e coord \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e coordinates:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;坐标: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecoord\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 遍历字典（默认遍历键）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e=== 遍历字典 ===\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eperson \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Alice\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;age\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;city\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Beijing\u0026#34;\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e key \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e person:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ekey\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eperson[key]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e运行结果：\u003c/strong\u003e\u003c/p\u003e","tags":"Python, 编程, for, range","title":"Day8 for循环与range"},{"columns":"acp-course","content":"Day 8 云服务器 ECS 📅 ACP云计算工程师认证系列 · Day 8\n阿里云云服务器 ECS（Elastic Compute Service）是阿里云最基础的计算服务，提供弹性的、可扩展的虚拟计算能力。本篇详细讲解 ECS 的概念、架构、核心组件（实例规格、镜像、磁盘、快照、安全组）、计费方式，以及操作实践与最佳实践。\n🎯考试重点：实例规格族分类、镜像类型对比、快照原理、安全组规则与实践建议、计费方式\n📖 详细讲解 一、服务器基础知识 1.1 服务器的概念 服务器（Server） 是提供计算服务的硬件设备，通常配置高、性能强、稳定可靠，7×24 小时运行。服务器与普通计算机的核心区别在于：可靠性更高、扩展性更强、长期持续运行能力。\n1.2 服务器的发展过程 阶段 形态 特点 传统物理服务器 自购硬件托管 采购周期长、运维成本高、扩展困难 虚拟化服务器 VMware/Hyper-V 虚拟化 资源利用率提升，但仍有物理服务器瓶颈 云服务器 云上虚拟化 按需购买、弹性伸缩、免运维 1.3 云服务器产生的背景 传统硬件服务器存在的不足：\n采购周期长：从采购到上线通常需要数周 资源利用率低：平均利用率仅 15%~20% 运维成本高：需要专人维护硬件、网络、空调等 扩展困难：扩容受限于物理服务器数量 云服务器通过虚拟化技术和资源池化，解决了以上问题，实现了即开即用、弹性伸缩、按需付费。\n二、阿里云云服务器全景图 2.1 飞天云平台与神龙计算 阿里云的基础设施建立在飞天云操作系统之上。2022 年阿里云发布以 CIPU（Cloud Infrastructure Processing Unit） 为核心的新一代计算架构，配合神龙计算平台，实现了设备虚拟化、网络存储转发和随路加解密的硬件全加速。\n神龙架构发展历程：\n第一代：基础虚拟化增强 第二代：性能大幅提升 第三代：超大规模支持 第四代（当前）：硬件加速全面集成，飞天+CIPU体系成型 2.2 弹性计算服务定位 阿里云弹性计算服务（ECS）是阿里云最基础、最核心的 IaaS 层服务，为各类云上业务提供计算支撑。\n三、云服务器 ECS 概述 3.1 ECS 的概念 云服务器 ECS（Elastic Compute Service） 是一种简单高效、处理能力可弹性伸缩的计算服务。无需提前采购硬件，即可在云上快速创建或释放任意数量的云服务器，降低 IT 运维成本，使您更专注于核心业务创新。\n3.2 ECS 的特性与优势 特性 说明 ✅ 弹性扩展 CPU、内存、存储、带宽随时升降配 ✅ 稳定可靠 单实例可用性 99.975%，支持宕机自动迁移 ✅ 安全隔离 VPC 专有网络隔离，多层次安全防护 ✅ 多种实例规格 入门级、企业级，涵盖通用、计算、内存、GPU 等 ✅ 多种镜像 公共镜像、自定义镜像、共享镜像、镜像市场 ✅ 完善的网络 专有网络 VPC、弹性网卡、安全组 ✅ 多种存储 云盘（SSD/ESSD/普通云盘）、本地盘 ✅ 免运维 自动化运维，监控告警一体化 3.3 ECS 产品架构核心组件 ECS 主要包含以下功能组件：\n组件 作用 实例（Instance） 虚拟服务器，核心计算资源 镜像（Image） 操作系统或预装软件的模板 块存储（Block Storage） 云盘，用于存储数据 快照（Snapshot） 某一时点云盘的数据备份 安全组（Security Group） 虚拟防火墙，控制出入站流量 弹性网卡（ENI） 虚拟网卡，挂载到实例 弹性公网 IP（EIP） 独立的公网 IP 地址 VPC 专有网络 逻辑隔离的网络环境 云助手（CloudAssistant） 远程运维管理工具 3.4 地域与可用区 地域（Region）：数据中心所在的地理区域，如华北2（北京）、华东1（杭州）等 可用区（Zone）：同一地域内电力和网络互相独立的区域，支持跨可用区容灾 💡 同一地域内不同可用区之间内网互通；不同地域之间内网完全隔离。\n四、ECS 实例与实例规格 4.1 实例的概念 实例（Instance） 是 vCPU 与内存的组合，是云服务器 ECS 的核心组件。创建实例时需要选择：实例规格、镜像、操作系统、网络类型、存储等。\n4.2 入门级实例 VS 企业级实例 对比项 入门级实例 企业级实例 定位 个人用户、轻量应用 企业级生产环境 性能 共享物理服务器资源 独享物理服务器资源 可用性 适合低负载场景 适合高可用、高性能场景 价格 较低 相对较高 典型规格 t5、t6 g5、c5、r5、hfc7 等 4.3 实例规格族（考试重点） 阿里云 ECS 实例规格族分为以下几大类：\n规格族 特点 适用场景 通用型（g） 平衡 CPU 与内存 中小型 Web 服务器、应用服务器 计算型（c） vCPU 较多 高性能 Web 服务器、游戏服务器 内存型（r） 内存较大 数据库、缓存服务器 GPU 计算型（gn） 配备 GPU 深度学习、科学计算、图形渲染 本地存储型（i） 使用本地 SSD 对磁盘 IO 要求极高的场景 大数据型（d） 大容量本地盘 大数据分析、日志处理 高频计算型（hfc） 高主频 CPU 高性能计算、量化交易 共享型（xn/tn/sn/snfp） 共享资源 轻量级 Web 应用、开发测试 ⚠️ 考试重点：实例规格族的选择直接影响业务性能和成本，需要根据实际业务场景选择合适的规格族。\n4.4 规格族的代际分类 第 7 代：g7、c7、r7 等（最新代际，性能更强） 第 6 代：g6、c6、r6 等 第 5 代：g5、c5、r5 等（入门级推荐） 五、镜像详解 5.1 镜像的概念 镜像（Image） 是 ECS 实例的操作系统或预装软件环境的模板。创建实例时必须指定镜像，镜像决定了实例的操作系统类型和初始软件环境。\n5.2 镜像类型对比（考试重点） 镜像类型 说明 适用场景 公共镜像 阿里云官方提供，纯净操作系统 通用场景，快速部署 自定义镜像 用户自行创建，保留数据盘和配置 环境复制、批量部署 共享镜像 其他阿里云账号共享给你的镜像 团队协作、环境迁移 镜像市场 第三方预装镜像（如 WordPress、Linux 发行版） 一键部署各类应用 5.3 系统镜像 阿里云提供的公共镜像包含多种操作系统：\nLinux 系列：\nAlibaba Cloud Linux（阿里云优化版，性能优异） Ubuntu、CentOS、Debian Red Hat Enterprise Linux SUSE Linux Enterprise Server Windows 系列：\nWindows Server 2012/2016/2019/2022 数据中心版 5.4 镜像的功能 ✅ 创建新实例（必须） ✅ 更换操作系统（系统盘更换） ✅ 复制环境（自定义镜像跨地域复制） ✅ 批量部署（使用自定义镜像创建多台实例） 六、块存储、云盘与快照 6.1 云盘类型 云盘类型 性能级别 适用场景 ESSD 云盘 PL3（最高 100万 IOPS） 高性能数据库、大型应用 SSD 云盘 中等性能 中等负载生产环境 普通云盘 低性能 开发测试、低成本场景 6.2 快照原理 快照（Snapshot） 是某一时刻云盘的数据备份。快照工作原理：\n写入数据 → 数据写入云盘 → 生成快照（记录当前数据状态） ↓ 云盘数据变更 → 快照保留变更前的数据块 快照是增量备份，只保存变化的数据块，节省存储空间 支持自动快照策略（每日/每周定时创建） 可用快照恢复云盘到某一时刻状态 6.3 自定义镜像与快照的关系 创建自定义镜像时会同时创建该云盘对应快照。自定义镜像可用于：\n跨地域复制环境 批量创建相同配置的实例 业务环境备份与恢复 七、专有网络、弹性网卡与安全组 7.1 专有网络 VPC VPC（Virtual Private Cloud）是阿里云提供的逻辑隔离的专有网络：\n完全掌控网络架构 支持自定义 IP 地址范围 通过隧道技术实现二次隔离，安全性高 7.2 弹性网卡 ENI 弹性网卡（Elastic Network Interface，ENI） 是专有网络中的虚拟网卡：\n可绑定到 ECS 实例 支持实例故障时网卡迁移（高可用） 一个实例可绑定多个弹性网卡 7.3 安全组（考试重点） 安全组（Security Group） 是 ECS 实例的虚拟防火墙，用于控制实例的网络访问。\n安全组特点：\n有状态：出站规则允许的流量，对应入站响应自动放行 支持同时关联多台 ECS 实例 同一安全组内实例默认网络不通（需手动授权） 安全组分类：\n分类 说明 基本安全组 仅允许 ICMP/SSH/RDP 3389 端口 高级安全组 支持全量端口和协议 安全组入站规则示例：\n协议 端口范围 来源 描述 TCP 22 0.0.0.0/0 SSH 远程连接（仅测试用） TCP 80 0.0.0.0/0 HTTP 网站访问 TCP 443 0.0.0.0/0 HTTPS 安全访问 TCP 3389 10.0.0.0/8 RDP Windows 远程桌面 ALL -1 sg-xxxxx 允许来自某安全组的流量 安全组实践建议（考试重点）：\n🔐 生产环境不要使用 0.0.0.0/0 开放 SSH/RDP 🔐 按最小权限原则，只开放必要端口 🔐 优先使用安全组内授权而非 IP 白名单 🔐 避免在安全组中存储过多规则，影响性能 八、ECS 高可用与容灾 8.1 宕机自动迁移 ECS 提供宕机自动迁移能力：当物理服务器发生硬件故障时，ECS 实例会自动迁移到健康节点，实例 IP 地址保持不变。\n8.2 迁移服务器 SMC SMC（Server Migration Center） 是阿里云提供的服务器迁移工具：\n支持从线下 IDC、虚拟机环境迁移到 ECS 迁移流程：评估迁移条件 → 配置迁移任务 → 执行迁移 → 验证结果 增量同步技术，最小化业务停机时间 8.3 部署集 部署集（Deployment Set） 用于控制实例的分布策略：\n支持将多台 ECS 实例分散部署到不同物理服务器 适用于需要高可用保障的关键业务 九、ECS 计费方式（考试重点） ECS 支持多种计费方式：\n计费方式 说明 适用场景 包年包月 先付费后使用，单价较低 长期稳定业务 按量付费 按小时/秒计费，灵活 短期、弹性业务 抢占式实例 价格随市场需求波动，最低可至一折 批量计算、离线处理 预留实例券 抵扣按量付费账单 有稳定业务需求 存储容量单位包 抵扣云盘、快照、OSS 存储 大量存储需求 💡 考试重点：包年包月适合长期使用，抢占式实例适合容错性高的批处理任务。\n十、ECS 支持的云服务与生态 ECS 与阿里云其他云服务深度集成：\n云服务 与 ECS 的关系 VPC 网络隔离与通信 RDS 数据库服务（通常与 ECS 私网连接） SLB/ALB/NLB 负载均衡，分发流量到 ECS NAS 文件存储，ECS 可挂载 OSS 对象存储，ECS 通过内网访问 Redis 缓存服务 容器服务 ACK ECS 作为 Kubernetes 节点 弹性伸缩 ESS 根据负载自动扩缩 ECS 📝 背诵版 一、ECS 核心概念速记 云服务器 ECS = 实例（计算）\u0026#43; 镜像（系统）\u0026#43; 云盘（存储）\u0026#43; 安全组（防火墙）\u0026#43; VPC（网络）ECS 四大组件：\n实例 = vCPU + 内存，核心计算资源 镜像 = 操作系统模板（公共/自定义/共享/镜像市场） 云盘 = 存储介质（ESSD/SSD/普通云盘） 安全组 = 虚拟防火墙（有状态，控制出入站流量） 二、实例规格族速记 规格族 特点 典型场景 通用型 g 平衡 Web 应用、中小型数据库 计算型 c vCPU 多 游戏、高性能 Web 内存型 r 内存大 Redis、数据库 GPU 型 gn 配备 GPU AI、深度学习 本地存储型 i 本地 SSD 高 IO 数据库 大数据型 d 大容量本地盘 大数据分析 三、镜像类型速记 公共镜像：阿里云官方提供，纯净系统 自定义镜像：用户自己创建，保留配置 共享镜像：其他账号共享给你 镜像市场：第三方预装应用镜像 四、安全组速记 安全组 = 有状态的虚拟防火墙 入站规则：允许外部访问实例的流量 出站规则：允许实例访问外部的流量 原则：最小权限 + 禁止 0.0.0.0/0 开放 SSH/RDP 五、计费方式速记 计费方式 特点 包年包月 预付费，便宜，长期 按量付费 后付费，灵活，短期 抢占式实例 折扣大（最低一折），可中断 预留实例券 抵扣按量账单 六、关键数字考点 关键词 数值 ECS 单实例可用性 99.975% ESSD 云盘最高 IOPS 100万 IOPS 安全组类型 基本安全组 + 高级安全组 安全组状态 有状态 快照类型 增量备份 ⚡ 速记版 口诀记忆 ECS 五组件：\n\u0026ldquo;实例算，镜像装，盘来存，安全拦，网络通\u0026rdquo;\n实-实例，镜-镜像，盘-云盘，安-安全组，网-VPC/弹性网卡\n镜像四兄弟：\n\u0026ldquo;公共镜像官方造，自定义你来造，共享别人给你用，市场三方来帮忙\u0026rdquo;\n公共/自定义/共享/镜像市场\n云盘三剑客：\n\u0026ldquo;ESSD 性能最强，SSD 中等，普通便宜\u0026rdquo;\nESSD/SSD/普通云盘\n安全组三原则：\n\u0026ldquo;有状态，最小权，别开 0.0.0.0\u0026rdquo;\n计费选择：\n\u0026ldquo;长期用包年包月，弹性用按量付费，容错用抢占式\u0026rdquo;\n对比速记表 对比项 选项A 选项B 入门级实例 共享资源 企业级实例 企业级实例 独享物理服务器 — 公共镜像 官方提供 自定义镜像 安全组 有状态 — 快照备份 增量 全量 长期业务计费 包年包月 按量付费 容错批处理 抢占式实例 — 📝 测试题 一、选择题 1. 【单选】阿里云 ECS 实例中，以下哪种规格族最适用于需要大内存的 Redis 缓存服务器场景？\nA. 通用型 g7\nB. 计算型 c7\nC. 内存型 r7\nD. GPU 型 gn7\n答案：C\n内存型 r7 规格族配备较大内存，适合内存数据库（如 Redis）、缓存服务器等内存密集型场景。通用型平衡 CPU 和内存，计算型 vCPU 更多，GPU 型适用于深度学习。\n2. 【单选】关于阿里云 ECS 安全组的描述，正确的是？\nA. 安全组是无状态的，需要手动放行返回流量\nB. 安全组是有状态的，出站允许的流量对应入站响应自动放行\nC. 一个 ECS 实例只能绑定一个安全组\nD. 安全组规则支持按 IP 地址精确到单个 IP，不支持 CIDR\n答案：B\n安全组是有状态的，这意味着如果出站规则允许流量，对应的入站响应流量会自动放行，无需额外配置入站规则。一个 ECS 实例可以绑定多个安全组，安全组规则支持 CIDR 表示法（如 10.0.0.0/8）。\n3. 【单选】阿里云 ECS 的镜像类型中，适合于批量部署相同配置服务器环境的是？\nA. 公共镜像\nB. 自定义镜像\nC. 共享镜像\nD. 镜像市场\n答案：B\n自定义镜像是用户基于已有实例创建的镜像，包含操作系统和预装软件配置，适合批量部署相同环境的服务器。公共镜像是全新安装，共享镜像是别人授权给你的，镜像市场是第三方应用镜像。\n4. 【单选】以下哪种 ECS 计费方式最适合运行容错性要求高的离线大数据批处理任务，同时控制成本？\nA. 包年包月\nB. 按量付费\nC. 抢占式实例\nD. 预留实例券\n答案：C\n抢占式实例价格最低可达按量付费的一折，适合容错性高的离线批处理任务（可接受中断）。包年包月适合长期稳定业务，按量付费适合短期灵活业务，预留实例券用于抵扣按量账单。\n5. 【单选】关于 ECS 快照的描述，错误的是？\nA. 快照是增量备份，节省存储空间\nB. 可以使用快照恢复云盘数据到某一时刻\nC. 快照可以跨地域复制\nD. 创建自定义镜像时会自动生成云盘的全量备份，而非快照\n答案：D\n创建自定义镜像时会同时创建该云盘对应的快照，快照是增量的，不是全量备份。快照支持跨地域复制，可用于跨地域环境迁移。\n二、判断题 6. 【判断】阿里云 ECS 入门级实例（如 t5/t6）由于采用共享物理服务器资源，性能稳定，适合作为生产环境的数据库服务器。\n答案：❌ 错误\n入门级实例（如 t5/t6）采用共享物理服务器资源，存在资源竞争，性能稳定性不如企业级实例。生产环境的数据库服务器应选择企业级实例（如 g7/c7/r7），以获得稳定的独享资源保障。\n7. 【判断】ECS 安全组规则中，以 0.0.0.0/0 开放 SSH 22 端口和 RDP 3389 端口是生产环境的推荐实践。\n答案：❌ 错误\n生产环境中禁止以 0.0.0.0/0 开放 SSH 和 RDP 端口，否则会导致严重的安全风险。正确做法是：仅开放必要端口，限制来源 IP 范围（如仅允许公司 IP 或 VPN IP 访问），或使用安全组内授权的方式。\n8. 【判断】ESSD 云盘提供最高 100 万 IOPS 的存储性能，适合大型关系数据库和 NoSQL 数据库等对 IOPS 要求极高的场景。\n答案：✅ 正确\n三、连线题 9. 将以下 ECS 组件与其功能进行连线：\n组件 功能 实例 Instance 提供 vCPU 和内存的计算资源 镜像 Image 操作系统和软件的模板 云盘 Disk 数据存储介质 安全组 Security Group 控制网络访问的虚拟防火墙 弹性网卡 ENI 挂载到实例的虚拟网卡 答案：\n实例 → vCPU+内存计算资源\n镜像 → 操作系统模板\n云盘 → 数据存储\n安全组 → 虚拟防火墙\n弹性网卡 → 虚拟网卡\n四、场景题 10. 【场景】某互联网公司计划在阿里云上部署一套电商 Web 应用，前端使用多台 ECS 实例通过负载均衡分发请求，后端使用 RDS MySQL 数据库，静态资源存储在 OSS 中，日均 PV 约 50 万。以下 ECS 选型和架构建议正确的是？\nA. 所有 ECS 均选择入门级实例 t6，节省成本\nB. ECS 实例必须全部加入同一个 VPC 才能通过内网访问 RDS\nC. 使用自定义镜像批量创建 Web 服务器，并通过安全组仅开放 80/443 端口\nD. 数据库服务器直接使用 ECS 自建，不使用 RDS\n答案：C\nA 错误：入门级实例性能不稳定，生产 Web 服务器应选企业级实例；B 部分正确但不完全准确：ECS 和 RDS 需要在同一 VPC 内网互通；C 正确：自定义镜像便于批量部署，安全组最小权限原则是正确的；D 错误：生产数据库应使用 RDS，提供高可用、自动备份等托管服务。\n📚 Day 8 学习完成\n核心掌握：ECS 实例规格族分类、镜像类型对比、快照原理、安全组规则与实践、计费方式选择。\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-08-acp-day-8-%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8ecs/","summary":"\u003ch1 id=\"day-8-云服务器-ecs\"\u003eDay 8 云服务器 ECS\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e📅 ACP云计算工程师认证系列 · Day 8\u003c/strong\u003e\u003cbr\u003e\n阿里云云服务器 ECS（Elastic Compute Service）是阿里云最基础的计算服务，提供弹性的、可扩展的虚拟计算能力。本篇详细讲解 ECS 的概念、架构、核心组件（实例规格、镜像、磁盘、快照、安全组）、计费方式，以及操作实践与最佳实践。\u003cbr\u003e\n🎯考试重点：实例规格族分类、镜像类型对比、快照原理、安全组规则与实践建议、计费方式\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"-详细讲解\"\u003e📖 详细讲解\u003c/h2\u003e\n\u003chr\u003e\n\u003ch3 id=\"一服务器基础知识\"\u003e一、服务器基础知识\u003c/h3\u003e\n\u003ch4 id=\"11-服务器的概念\"\u003e1.1 服务器的概念\u003c/h4\u003e\n\u003cp\u003e\u003cstrong\u003e服务器（Server）\u003c/strong\u003e 是提供计算服务的硬件设备，通常配置高、性能强、稳定可靠，7×24 小时运行。服务器与普通计算机的核心区别在于：\u003cstrong\u003e可靠性更高、扩展性更强、长期持续运行能力\u003c/strong\u003e。\u003c/p\u003e\n\u003ch4 id=\"12-服务器的发展过程\"\u003e1.2 服务器的发展过程\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e阶段\u003c/th\u003e\n          \u003cth\u003e形态\u003c/th\u003e\n          \u003cth\u003e特点\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e传统物理服务器\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e自购硬件托管\u003c/td\u003e\n          \u003ctd\u003e采购周期长、运维成本高、扩展困难\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e虚拟化服务器\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eVMware/Hyper-V 虚拟化\u003c/td\u003e\n          \u003ctd\u003e资源利用率提升，但仍有物理服务器瓶颈\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e云服务器\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e云上虚拟化\u003c/td\u003e\n          \u003ctd\u003e按需购买、弹性伸缩、免运维\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"13-云服务器产生的背景\"\u003e1.3 云服务器产生的背景\u003c/h4\u003e\n\u003cp\u003e传统硬件服务器存在的不足：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e采购周期长\u003c/strong\u003e：从采购到上线通常需要数周\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e资源利用率低\u003c/strong\u003e：平均利用率仅 15%~20%\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e运维成本高\u003c/strong\u003e：需要专人维护硬件、网络、空调等\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e扩展困难\u003c/strong\u003e：扩容受限于物理服务器数量\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e云服务器通过\u003cstrong\u003e虚拟化技术\u003c/strong\u003e和\u003cstrong\u003e资源池化\u003c/strong\u003e，解决了以上问题，实现了\u003cstrong\u003e即开即用、弹性伸缩、按需付费\u003c/strong\u003e。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"二阿里云云服务器全景图\"\u003e二、阿里云云服务器全景图\u003c/h3\u003e\n\u003ch4 id=\"21-飞天云平台与神龙计算\"\u003e2.1 飞天云平台与神龙计算\u003c/h4\u003e\n\u003cp\u003e阿里云的基础设施建立在\u003cstrong\u003e飞天云操作系统\u003c/strong\u003e之上。2022 年阿里云发布以 \u003cstrong\u003eCIPU（Cloud Infrastructure Processing Unit）\u003c/strong\u003e 为核心的新一代计算架构，配合\u003cstrong\u003e神龙计算平台\u003c/strong\u003e，实现了设备虚拟化、网络存储转发和随路加解密的硬件全加速。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e神龙架构发展历程：\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e第一代：基础虚拟化增强\u003c/li\u003e\n\u003cli\u003e第二代：性能大幅提升\u003c/li\u003e\n\u003cli\u003e第三代：超大规模支持\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e第四代（当前）\u003c/strong\u003e：硬件加速全面集成，飞天+CIPU体系成型\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"22-弹性计算服务定位\"\u003e2.2 弹性计算服务定位\u003c/h4\u003e\n\u003cp\u003e阿里云弹性计算服务（ECS）是阿里云\u003cstrong\u003e最基础、最核心\u003c/strong\u003e的 IaaS 层服务，为各类云上业务提供计算支撑。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"三云服务器-ecs-概述\"\u003e三、云服务器 ECS 概述\u003c/h3\u003e\n\u003ch4 id=\"31-ecs-的概念\"\u003e3.1 ECS 的概念\u003c/h4\u003e\n\u003cp\u003e\u003cstrong\u003e云服务器 ECS（Elastic Compute Service）\u003c/strong\u003e 是一种简单高效、\u003cstrong\u003e处理能力可弹性伸缩\u003c/strong\u003e的计算服务。无需提前采购硬件，即可在云上快速创建或释放任意数量的云服务器，降低 IT 运维成本，使您更专注于核心业务创新。\u003c/p\u003e","tags":"ACP, 阿里云, ECS","title":"Day8 云服务器ECS"},{"columns":"python-course","content":" 来源：03_循环 hm_10~hm_12 + 网络资料整理\n一、详细讲解 1.1 核心概念 嵌套循环与图案打印是Python编程中用于处理二维结构数据的重要知识点。在本课程的第9天，我们将学习循环嵌套的基础概念、九九乘法表的实现、以及各种图案的打印技巧。\n嵌套循环是指一个循环内部包含另一个循环的结构。外层循环控制行或外层维度的变化，内层循环控制列或内层维度的变化。通过合理使用嵌套循环，我们可以打印各种规则或不规则的图案，处理矩阵数据，以及解决需要多层迭代的问题。\n1.2 嵌套循环基础 1.2.1 嵌套循环的执行原理 # 嵌套循环的基本结构 for i in range(外层次数): # 外层循环 for j in range(内层次数): # 内层循环 # 内层循环体 # 外层循环体（内层循环结束后执行） 1.2.2 执行次数计算 # 嵌套循环总执行次数 = 外层次数 × 内层次数 print(\u0026#34;=== 嵌套循环执行次数 ===\u0026#34;) outer_times = 3 inner_times = 4 total_executions = outer_times * inner_times print(f\u0026#34;外层循环 {outer_times} 次 × 内层循环 {inner_times} 次 = 总执行 {total_executions} 次\u0026#34;) # 演示 count = 0 for i in range(3): for j in range(4): count += 1 print(f\u0026#34;i={i}, j={j}\u0026#34;, end=\u0026#34; \u0026#34;) print() # 内层循环结束后换行 print(f\u0026#34;\\n实际执行次数: {count}\u0026#34;) 输出：\n=== 嵌套循环执行次数 === 外层循环 3 次 × 内层循环 4 次 = 总执行 12 次 i=0, j=0 i=0, j=1 i=0, j=2 i=0, j=3 i=1, j=0 i=1, j=1 i=1, j=2 i=1, j=3 i=2, j=0 i=2, j=1 i=2, j=2 i=2, j=3 实际执行次数: 121.3 九九乘法表 1.3.1 标准九九乘法表 # 打印标准九九乘法表 print(\u0026#34;=== 九九乘法表 ===\u0026#34;) for i in range(1, 10): # 外层循环：被乘数 1~9 for j in range(1, i + 1): # 内层循环：乘数 1~i product = i * j print(f\u0026#34;{j}×{i}={product}\u0026#34;, end=\u0026#34;\\t\u0026#34;) print() # 换行 输出：\n=== 九九乘法表 === 1×1=1\t2×1=2\t2×2=4\t3×1=3\t2×3=6\t3×3=9\t4×1=4\t2×4=8\t3×4=12\t4×4=16\t5×1=5\t2×5=10\t3×5=15\t4×5=20\t5×5=25\t6×1=6\t2×6=12\t3×6=18\t4×6=24\t5×6=30\t6×6=36\t7×1=7\t2×7=14\t3×7=21\t4×7=28\t5×7=35\t6×7=42\t7×7=49\t8×1=8\t2×8=16\t3×8=24\t4×8=32\t5×8=40\t6×8=48\t7×8=56\t8×8=64\t9×1=9\t2×9=18\t3×9=27\t4×9=36\t5×9=45\t6×9=54\t7×9=63\t8×9=72\t9×9=81\t1.3.2 下三角九九乘法表 # 打印下三角九九乘法表 print(\u0026#34;=== 下三角九九乘法表 ===\u0026#34;) for i in range(1, 10): for j in range(1, 10): if j \u0026lt;= i: # 只打印下三角部分 print(f\u0026#34;{j}×{i}={i*j}\u0026#34;, end=\u0026#34;\\t\u0026#34;) print() 1.3.3 带格式的九九乘法表 # 带对齐格式的九九乘法表 print(\u0026#34;=== 格式化九九乘法表 ===\u0026#34;) for i in range(1, 10): line = \u0026#34;\u0026#34; for j in range(1, i + 1): line += f\u0026#34;{j}×{i}={i*j:2d} \u0026#34; print(line) 1.4 常见图案打印 1.4.1 正方形图案 # 实心正方形 n = 5 print(\u0026#34;=== 实心正方形 ===\u0026#34;) for i in range(n): for j in range(n): print(\u0026#34;█\u0026#34;, end=\u0026#34; \u0026#34;) print() print() # 空心正方形 print(\u0026#34;=== 空心正方形 ===\u0026#34;) for i in range(n): for j in range(n): if i == 0 or i == n - 1 or j == 0 or j == n - 1: print(\u0026#34;█\u0026#34;, end=\u0026#34; \u0026#34;) else: print(\u0026#34; \u0026#34;, end=\u0026#34; \u0026#34;) print() 输出：\n=== 实心正方形 === █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ === 空心正方形 === █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ 1.4.2 三角形图案 # 直角三角形（左下角） n = 5 print(\u0026#34;=== 直角三角形（左下角）===\u0026#34;) for i in range(1, n + 1): for j in range(1, i + 1): print(\u0026#34;█\u0026#34;, end=\u0026#34; \u0026#34;) print() print() # 直角三角形（右下角） print(\u0026#34;=== 直角三角形（右下角）===\u0026#34;) for i in range(1, n + 1): # 先打印空格 for j in range(1, n - i + 1): print(\u0026#34; \u0026#34;, end=\u0026#34; \u0026#34;) # 再打印星号 for j in range(1, i + 1): print(\u0026#34;█\u0026#34;, end=\u0026#34; \u0026#34;) print() print() # 等腰三角形 print(\u0026#34;=== 等腰三角形 ===\u0026#34;) for i in range(1, n + 1): # 打印空格 for j in range(1, n - i + 1): print(\u0026#34; \u0026#34;, end=\u0026#34; \u0026#34;) # 打印星号 for j in range(1, 2 * i): print(\u0026#34;█\u0026#34;, end=\u0026#34;\u0026#34;) print() 输出：\n=== 直角三角形（左下角）=== █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ === 直角三角形（右下角）=== █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ === 等腰三角形 === █ ███ █████ ███████ █████████1.4.3 菱形图案 # 菱形 n = 5 print(\u0026#34;=== 菱形 ===\u0026#34;) # 上半部分（包括中间行） for i in range(1, n + 1): # 打印空格 for j in range(1, n - i + 1): print(\u0026#34; \u0026#34;, end=\u0026#34;\u0026#34;) # 打印星号 for j in range(1, 2 * i): print(\u0026#34;█\u0026#34;, end=\u0026#34;\u0026#34;) print() # 下半部分 for i in range(n - 1, 0, -1): # 打印空格 for j in range(1, n - i + 1): print(\u0026#34; \u0026#34;, end=\u0026#34;\u0026#34;) # 打印星号 for j in range(1, 2 * i): print(\u0026#34;█\u0026#34;, end=\u0026#34;\u0026#34;) print() 1.4.4 数字三角形 # 数字三角形 n = 5 print(\u0026#34;=== 数字三角形 ===\u0026#34;) for i in range(1, n + 1): for j in range(1, i + 1): print(j, end=\u0026#34; \u0026#34;) print() print() # 数字菱形 print(\u0026#34;=== 数字菱形 ===\u0026#34;) for i in range(1, n + 1): # 打印空格 for j in range(1, n - i + 1): print(\u0026#34; \u0026#34;, end=\u0026#34; \u0026#34;) # 打印数字 for j in range(1, i + 1): print(j, end=\u0026#34; \u0026#34;) print() for i in range(n - 1, 0, -1): # 打印空格 for j in range(1, n - i + 1): print(\u0026#34; \u0026#34;, end=\u0026#34; \u0026#34;) # 打印数字 for j in range(1, i + 1): print(j, end=\u0026#34; \u0026#34;) print() 1.5 矩阵操作 1.5.1 矩阵遍历 # 定义一个3x4矩阵 matrix = [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12] ] # 按行遍历 print(\u0026#34;=== 按行遍历 ===\u0026#34;) for row in matrix: for element in row: print(f\u0026#34;{element:3d}\u0026#34;, end=\u0026#34; \u0026#34;) print() # 带索引遍历 print(\u0026#34;\\n=== 带索引遍历 ===\u0026#34;) for i in range(len(matrix)): for j in range(len(matrix[i])): print(f\u0026#34;matrix[{i}][{j}] = {matrix[i][j]}\u0026#34;) 1.5.2 矩阵转置 # 矩阵转置 matrix = [ [1, 2, 3], [4, 5, 6] ] rows = len(matrix) cols = len(matrix[0]) # 创建转置矩阵 transposed = [] for j in range(cols): new_row = [] for i in range(rows): new_row.append(matrix[i][j]) transposed.append(new_row) print(\u0026#34;=== 矩阵转置 ===\u0026#34;) print(\u0026#34;原矩阵:\u0026#34;) for row in matrix: print(row) print(\u0026#34;\\n转置后:\u0026#34;) for row in transposed: print(row) 1.6 实用示例 1.6.1 查找质数（埃拉托斯特尼筛法） # 查找n以内的所有质数 def find_primes(n): # 初始化：假设所有数都是质数 is_prime = [True] * (n + 1) is_prime[0] = is_prime[1] = False # 筛选 for i in range(2, int(n ** 0.5) + 1): if is_prime[i]: # 将i的倍数标记为非质数 for j in range(i * i, n + 1, i): is_prime[j] = False # 收集结果 return [i for i in range(2, n + 1) if is_prime[i]] primes = find_primes(100) print(f\u0026#34;100以内的质数: {primes}\u0026#34;) print(f\u0026#34;共 {len(primes)} 个\u0026#34;) 1.6.2 杨辉三角 # 打印杨辉三角 def print_pascal_triangle(n): triangle = [] for i in range(n): row = [1] * (i + 1) for j in range(1, i): row[j] = triangle[i - 1][j - 1] + triangle[i - 1][j] triangle.append(row) # 打印 for row in triangle: # 前面加空格对齐 print(\u0026#34; \u0026#34; * (n - len(row)) * 2, end=\u0026#34;\u0026#34;) for num in row: print(f\u0026#34;{num:4d}\u0026#34;, end=\u0026#34;\u0026#34;) print() print_pascal_triangle(8) 1.6.3 迷宫模拟 # 简单的迷宫遍历 maze = [ [1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [1, 1, 1, 0, 1], [1, 0, 0, 0, 0], [1, 1, 1, 1, 1] ] def find_path(maze, start, end): \u0026#34;\u0026#34;\u0026#34;简单的迷宫求解（只演示嵌套循环遍历）\u0026#34;\u0026#34;\u0026#34; rows = len(maze) cols = len(maze[0]) # 尝试从起点走到终点 for i in range(rows): for j in range(cols): if i == start[0] and j == start[1]: print(f\u0026#34;起点: ({i}, {j})\u0026#34;) if maze[i][j] == 0: # 可通行的路 print(f\u0026#34;探索: ({i}, {j})\u0026#34;) find_path(maze, (1, 0), (4, 3)) 1.7 嵌套循环的性能优化 1.7.1 减少计算量 # 低效：每次都计算长度 data = list(range(1000)) for i in range(len(data)): for j in range(len(data)): pass # 大量重复计算 # 高效：预先计算长度 n = len(data) for i in range(n): for j in range(n): pass # 避免重复计算 1.7.2 使用列表推导式替代 # 嵌套循环构建矩阵 rows, cols = 3, 4 # 嵌套循环 matrix = [] for i in range(rows): row = [] for j in range(cols): row.append(i * cols + j) matrix.append(row) # 列表推导式（更高效） matrix = [[i * cols + j for j in range(cols)] for i in range(rows)] print(\u0026#34;矩阵:\u0026#34;) for row in matrix: print(row) 1.8 常见错误与调试 # 错误1：缩进错误导致逻辑混乱 # for i in range(3): # for j in range(3): # 缩进不正确！ # print(i, j) # 错误2：循环变量使用错误 # for i in range(3): # for i in range(3): # 覆盖了外层变量 # print(i, j) # 正确做法：使用不同的变量名 for i in range(3): for j in range(3): print(f\u0026#34;i={i}, j={j}\u0026#34;) # 错误3：在内层循环中修改外层循环变量 # for i in range(3): # for j in range(3): # i = 10 # 不要这样做！ 二、背诵版 Day9 要点速记： 【嵌套循环执行次数】 总次数 = 外层次数 × 内层次数 【九九乘法表】 外层: range(1, 10) # 被乘数 1~9 内层: range(1, i\u0026#43;1) # 乘数 1~当前被乘数 print(end=\u0026#39;\\t\u0026#39;) # 制表符分隔 print() # 换行 【图案打印关键】 - 外层循环：控制行数 - 内层循环：控制每行的内容 - print(end=\u0026#39; \u0026#39;) 控制不换行 - 空格数量决定图案形状 【常见图案】 - 正方形：n×n - 三角形：每行递减/递增 - 菱形：上下对称 三、考前记忆 要素 内容 今日主题 嵌套循环与图案打印 关键词 循环嵌套、九九乘法表、图案 执行次数 外层次数 × 内层次数 外层控制 行数/外层维度 内层控制 每行的列数/内层维度 重要考点 嵌套循环执行次数计算、图案分析 四、测试题 1. 单选题： 嵌套循环，外层执行3次，内层执行4次，总执行次数是多少？\nA. 3次 B. 4次 C. 7次 D. 12次 2. 单选题： 以下代码的输出是什么？\nfor i in range(1, 4): for j in range(1, i + 1): print(\u0026#34;*\u0026#34;, end=\u0026#34;\u0026#34;) print() A. *** *** *** B. * ** *** C. * * * * D. 编译错误 3. 填空题： 打印九九乘法表时，外层循环控制 _______（填\u0026quot;被乘数\u0026quot;或\u0026quot;乘数\u0026quot;）。\n4. 填空题： 要打印一个5行的直角三角形，第i行需要打印 _______ 个星号。\n5. 简答题： 请描述嵌套循环的执行原理，并说明如何计算总执行次数。\n6. 代码题： 使用嵌套循环打印以下图案：\n* ** *** ****7. 代码题： 使用嵌套循环打印九九乘法表的第一行到第五行。\n8. 代码题： 打印一个5x5的空心正方形。\n9. 综合题： 设计一个程序，输入一个数字n，打印n行的金字塔图案。\nD - 总次数 = 外层次数 × 内层次数 = 3 × 4 = 12次\nB - i=1时打印1个*，i=2时打印2个*，i=3时打印3个*，输出 * ** ***\n被乘数 - 外层循环控制1~9的被乘数\ni - 第i行打印i个星号\n嵌套循环执行原理： - 外层循环第一次迭代时，内层循环完整执行所有次数 - 外层循环第二次迭代时，内层循环再次完整执行所有次数 - 以此类推，直到外层循环结束 总执行次数 = 外层循环次数 × 内层循环次数 例如：外层3次，内层4次，总共执行 3×4=12 次 n = 4 for i in range(1, n + 1): for j in range(1, i + 1): print(\u0026#34;*\u0026#34;, end=\u0026#34;\u0026#34;) print() for i in range(1, 6): for j in range(1, i + 1): print(f\u0026#34;{j}×{i}={i*j}\u0026#34;, end=\u0026#34;\\t\u0026#34;) print() n = 5 for i in range(n): for j in range(n): if i == 0 or i == n - 1 or j == 0 or j == n - 1: print(\u0026#34;█\u0026#34;, end=\u0026#34; \u0026#34;) else: print(\u0026#34; \u0026#34;, end=\u0026#34; \u0026#34;) print() def print_pyramid(n): for i in range(1, n + 1): # 打印空格 for j in range(1, n - i + 1): print(\u0026#34; \u0026#34;, end=\u0026#34;\u0026#34;) # 打印星号 for j in range(1, 2 * i): print(\u0026#34;█\u0026#34;, end=\u0026#34;\u0026#34;) print() n = int(input(\u0026#34;输入金字塔行数: \u0026#34;)) print_pyramid(n) 五、扩展阅读 5.1 多层嵌套循环 # 三层嵌套循环 for i in range(2): for j in range(2): for k in range(2): print(f\u0026#34;({i}, {j}, {k})\u0026#34;) 5.2 动态图案生成 # 根据用户输入生成不同的图案 def print_pattern(n, pattern_type): if pattern_type == \u0026#34;triangle\u0026#34;: for i in range(1, n + 1): print(\u0026#34;*\u0026#34; * i) elif pattern_type == \u0026#34;inverted_triangle\u0026#34;: for i in range(n, 0, -1): print(\u0026#34;*\u0026#34; * i) elif pattern_type == \u0026#34;diamond\u0026#34;: for i in range(1, n + 1): print(\u0026#34; \u0026#34; * (n - i) + \u0026#34;*\u0026#34; * (2 * i - 1)) for i in range(n - 1, 0, -1): print(\u0026#34; \u0026#34; * (n - i) + \u0026#34;*\u0026#34; * (2 * i - 1)) print_pattern(5, \u0026#34;diamond\u0026#34;) 5.3 二维数组操作技巧 # 创建二维数组 rows, cols = 3, 4 matrix = [[0] * cols for _ in range(rows)] # 填充 for i in range(rows): for j in range(cols): matrix[i][j] = i * cols + j + 1 # 打印 for row in matrix: print(\u0026#34; \u0026#34;.join(f\u0026#34;{x:2d}\u0026#34; for x in row)) # 对角线元素 print(\u0026#34;\\n主对角线:\u0026#34;, [matrix[i][i] for i in range(min(rows, cols))]) 恭喜完成Day9学习！明天我们将学习函数定义与调用，掌握代码封装和复用的基本技能。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-09-nested-loops-patterns/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：03_循环 hm_10~hm_12 + 网络资料整理\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-核心概念\"\u003e1.1 核心概念\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e嵌套循环与图案打印\u003c/strong\u003e是Python编程中用于处理二维结构数据的重要知识点。在本课程的第9天，我们将学习循环嵌套的基础概念、九九乘法表的实现、以及各种图案的打印技巧。\u003c/p\u003e\n\u003cp\u003e嵌套循环是指\u003cstrong\u003e一个循环内部包含另一个循环\u003c/strong\u003e的结构。外层循环控制\u003cstrong\u003e行\u003c/strong\u003e或\u003cstrong\u003e外层维度\u003c/strong\u003e的变化，内层循环控制\u003cstrong\u003e列\u003c/strong\u003e或\u003cstrong\u003e内层维度\u003c/strong\u003e的变化。通过合理使用嵌套循环，我们可以打印各种规则或不规则的图案，处理矩阵数据，以及解决需要多层迭代的问题。\u003c/p\u003e\n\u003ch3 id=\"12-嵌套循环基础\"\u003e1.2 嵌套循环基础\u003c/h3\u003e\n\u003ch4 id=\"121-嵌套循环的执行原理\"\u003e1.2.1 嵌套循环的执行原理\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 嵌套循环的基本结构\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(外层次数):    \u003cspan style=\"color:#75715e\"\u003e# 外层循环\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e j \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(内层次数):  \u003cspan style=\"color:#75715e\"\u003e# 内层循环\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 内层循环体\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 外层循环体（内层循环结束后执行）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"122-执行次数计算\"\u003e1.2.2 执行次数计算\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 嵌套循环总执行次数 = 外层次数 × 内层次数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;=== 嵌套循环执行次数 ===\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eouter_times \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003einner_times \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etotal_executions \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e outer_times \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e inner_times\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;外层循环 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eouter_times\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 次 × 内层循环 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003einner_times\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 次 = 总执行 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etotal_executions\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 次\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 演示\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecount \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e j \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        count \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;i=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ei\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e, j=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ej\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, end\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  \u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print()  \u003cspan style=\"color:#75715e\"\u003e# 内层循环结束后换行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e实际执行次数: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecount\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e输出：\u003c/strong\u003e\u003c/p\u003e","tags":"Python, 编程, 循环嵌套","title":"Day9 嵌套循环与图案打印"},{"columns":"acp-course","content":" 来源：Notion ACP学习笔记\nACP Day9 学习整理｜弹性存储系列 主资料为《弹性存储系列》，配套实验为《云数据库Redis的操作实践》；本节应按“存储体系概念 + Redis 实验落地”两层来理解。\n今日主题 Notion 标题：💾 Day9 弹性存储系列\n核心理解：先建立云上存储体系认知，再掌握 Redis 这种高性能数据服务的接入与操作。\n重点整理 弹性存储系列的整体框架包括：数据存储基础、块存储、文件存储、对象存储 OSS、日志服务 SLS、混合云存储等。\n存储基础要抓住：速度、容量、成本、可靠性，以及快照、备份、故障恢复等概念。\nRedis 属于 NoSQL / Key-Value 数据库，常用于缓存与热点数据访问，核心价值是高性能与高并发。\nRedis 实验重点是：设置白名单、添加安全组、查看连接地址、通过 ECS 使用 redis-cli 连接实例并完成 AUTH 认证。\n高频考点 为什么 Day9 不是只讲 Redis：因为主线是云上存储体系，Redis 只是其中一个具体数据服务实践切口。\n为什么 Redis 常用于缓存：因为它基于内存，性能高，能减轻后端数据库压力。\n为什么连接 Redis 前要处理白名单和安全组：因为云数据库实例处在受控网络中，访问必须满足网络与安全策略。\n为什么通过 ECS 连接 Redis：这更符合云上实际网络模型，也通常是被允许的访问路径。\n背诵版 Day9 主题是弹性存储系列，重点是建立云上存储体系认知。\n常见存储类型包括：块存储、文件存储、对象存储，以及数据库类数据服务。\nRedis 属于 NoSQL / Key-Value 数据库，核心价值是高性能缓存与热点数据承载。\n连接 Redis 前要关注白名单、安全组、连接地址与认证信息。\nDay9 的本质是：理解存储体系 + 掌握 Redis 操作实践。\n自测题 什么叫弹性存储系列？为什么它不是单一产品？\n块存储、文件存储、对象存储分别适合什么场景？\nRedis 为什么常用于缓存场景？\n连接 Redis 前为什么要设置白名单和安全组？\n易错点 不要把 Day9 误解成只讲 Redis，它主标题其实是弹性存储系列。\n不要把 Redis 当成关系型数据库，它属于 NoSQL / Key-Value。\n不要忽略白名单和安全组，它们是云上连接数据库实例的核心前提。\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-09-acp-day-9-%E5%BC%B9%E6%80%A7%E5%AD%98%E5%82%A8%E7%B3%BB%E5%88%97/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：Notion ACP学习笔记\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"acp-day9-学习整理弹性存储系列\"\u003eACP Day9 学习整理｜弹性存储系列\u003c/h2\u003e\n\u003cp\u003e主资料为《弹性存储系列》，配套实验为《云数据库Redis的操作实践》；本节应按“存储体系概念 + Redis 实验落地”两层来理解。\u003c/p\u003e\n\u003ch3 id=\"今日主题\"\u003e今日主题\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eNotion 标题：💾 Day9 弹性存储系列\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e核心理解：先建立云上存储体系认知，再掌握 Redis 这种高性能数据服务的接入与操作。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"重点整理\"\u003e重点整理\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e弹性存储系列的整体框架包括：数据存储基础、块存储、文件存储、对象存储 OSS、日志服务 SLS、混合云存储等。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e存储基础要抓住：速度、容量、成本、可靠性，以及快照、备份、故障恢复等概念。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRedis 属于 NoSQL / Key-Value 数据库，常用于缓存与热点数据访问，核心价值是高性能与高并发。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRedis 实验重点是：设置白名单、添加安全组、查看连接地址、通过 ECS 使用 redis-cli 连接实例并完成 AUTH 认证。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"高频考点\"\u003e高频考点\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e为什么 Day9 不是只讲 Redis：因为主线是云上存储体系，Redis 只是其中一个具体数据服务实践切口。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为什么 Redis 常用于缓存：因为它基于内存，性能高，能减轻后端数据库压力。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为什么连接 Redis 前要处理白名单和安全组：因为云数据库实例处在受控网络中，访问必须满足网络与安全策略。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为什么通过 ECS 连接 Redis：这更符合云上实际网络模型，也通常是被允许的访问路径。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"背诵版\"\u003e背诵版\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eDay9 主题是弹性存储系列，重点是建立云上存储体系认知。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e常见存储类型包括：块存储、文件存储、对象存储，以及数据库类数据服务。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRedis 属于 NoSQL / Key-Value 数据库，核心价值是高性能缓存与热点数据承载。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e连接 Redis 前要关注白名单、安全组、连接地址与认证信息。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eDay9 的本质是：理解存储体系 + 掌握 Redis 操作实践。\u003c/p\u003e","tags":"ACP, 阿里云","title":"ACP Day 9 弹性存储系列"},{"columns":"python-course","content":" 来源：04_函数 hm_01~hm_06 + Python官方文档 + 网络资料整理\n一、详细讲解 1.1 核心概念 函数定义与调用是Python编程中的核心知识点，也是代码模块化、复用和组织的基石。在本课程的第10天，我们将系统学习函数的基本概念、定义语法、参数传递、返回值处理，以及文档字符串的编写。\n函数是一段组织好的、可重复使用的、用来实现单一或相关联功能的代码块。在Python中，函数不仅是一种代码复用的手段，更是实现面向过程编程和模块化设计的基础。通过函数，我们可以将复杂的问题分解为多个小问题，使程序结构更加清晰、易于维护。\n1.2 函数基础 1.2.1 为什么要使用函数 # 不使用函数：代码重复 print(\u0026#34;=== 计算圆的面积 ===\u0026#34;) radius = 5 area = 3.14159 * radius ** 2 print(f\u0026#34;半径{radius}的圆面积: {area}\u0026#34;) radius = 10 area = 3.14159 * radius ** 2 print(f\u0026#34;半径{radius}的圆面积: {area}\u0026#34;) radius = 15 area = 3.14159 * radius ** 2 print(f\u0026#34;半径{radius}的圆面积: {area}\u0026#34;) # 使用函数：代码复用 def calculate_circle_area(radius): \u0026#34;\u0026#34;\u0026#34;计算圆的面积\u0026#34;\u0026#34;\u0026#34; area = 3.14159 * radius ** 2 return area print(\u0026#34;\\n=== 使用函数 ===\u0026#34;) for r in [5, 10, 15]: print(f\u0026#34;半径{r}的圆面积: {calculate_circle_area(r)}\u0026#34;) 1.2.2 函数定义的基本语法 # 函数定义的基本结构 def 函数名(参数1, 参数2, ...): \u0026#34;\u0026#34;\u0026#34;文档字符串（可选）\u0026#34;\u0026#34;\u0026#34; # 函数体 return 返回值 # 可选 1.3 函数的定义与调用 1.3.1 无参函数 # 无参函数：不需要输入参数 def greet(): \u0026#34;\u0026#34;\u0026#34;简单的问候函数\u0026#34;\u0026#34;\u0026#34; print(\u0026#34;Hello, World!\u0026#34;) print(\u0026#34;Welcome to Python!\u0026#34;) # 调用函数 greet() # 可以多次调用 greet() greet() 1.3.2 有参函数 # 有参函数：需要输入参数 def greet_person(name): \u0026#34;\u0026#34;\u0026#34;向指定的人打招呼\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;Hello, {name}!\u0026#34;) print(f\u0026#34;Welcome, {name}!\u0026#34;) # 调用函数，传入参数 greet_person(\u0026#34;Alice\u0026#34;) print() greet_person(\u0026#34;Bob\u0026#34;) 1.3.3 多参数函数 # 多个参数的函数 def calculate_rectangle(length, width): \u0026#34;\u0026#34;\u0026#34;计算矩形的面积和周长\u0026#34;\u0026#34;\u0026#34; area = length * width perimeter = 2 * (length + width) return area, perimeter # 调用函数 result = calculate_rectangle(5, 3) print(f\u0026#34;面积: {result[0]}, 周长: {result[1]}\u0026#34;) # 使用解包 area, perimeter = calculate_rectangle(5, 3) print(f\u0026#34;面积: {area}\u0026#34;) print(f\u0026#34;周长: {perimeter}\u0026#34;) 1.4 参数详解 1.4.1 位置参数 # 位置参数：按顺序传递 def introduce(name, age, city): \u0026#34;\u0026#34;\u0026#34;自我介绍\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;我叫{name}，今年{age}岁，来自{city}。\u0026#34;) # 调用时按位置传递 introduce(\u0026#34;张三\u0026#34;, 25, \u0026#34;北京\u0026#34;) introduce(\u0026#34;李四\u0026#34;, 30, \u0026#34;上海\u0026#34;) introduce(\u0026#34;王五\u0026#34;, 28, \u0026#34;广州\u0026#34;) # 位置参数必须传递，且顺序不能错 # introduce(\u0026#34;赵六\u0026#34;) # 错误：缺少参数 # introduce(25, \u0026#34;钱七\u0026#34;, \u0026#34;深圳\u0026#34;) # 错误：类型不匹配 1.4.2 关键字参数 # 关键字参数：按名称传递 def introduce(name, age, city): \u0026#34;\u0026#34;\u0026#34;自我介绍\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;我叫{name}，今年{age}岁，来自{city}。\u0026#34;) # 使用关键字参数，顺序可以改变 introduce(age=30, name=\u0026#34;张三\u0026#34;, city=\u0026#34;北京\u0026#34;) # 混合使用：位置参数必须在关键字参数前面 introduce(\u0026#34;李四\u0026#34;, city=\u0026#34;上海\u0026#34;, age=28) 1.4.3 默认参数 # 默认参数：给参数设置默认值 def greet(name, greeting=\u0026#34;Hello\u0026#34;): \u0026#34;\u0026#34;\u0026#34;带默认参数的问候函数\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;{greeting}, {name}!\u0026#34;) # 调用时可以不指定默认参数 greet(\u0026#34;Alice\u0026#34;) # Hello, Alice! greet(\u0026#34;Bob\u0026#34;, \u0026#34;Hi\u0026#34;) # Hi, Bob! # 默认参数必须在位置参数后面 # def greet(greeting=\u0026#34;Hello\u0026#34;, name): # 错误！ # 默认参数可以是有副作用的可变对象（需要注意） 1.4.4 默认参数的最佳实践 # 避免使用可变对象作为默认参数 # 错误示例 def add_to_list(item, target_list=[]): # 危险！ target_list.append(item) return target_list print(add_to_list(1)) # [1] print(add_to_list(2)) # [1, 2] - 不是 [2]！ # 正确示例 def add_to_list(item, target_list=None): # 正确 if target_list is None: target_list = [] target_list.append(item) return target_list print(add_to_list(1)) # [1] print(add_to_list(2)) # [2] 1.5 返回值详解 1.5.1 无返回值函数 # 没有return语句的函数，默认返回None def print_sum(a, b): \u0026#34;\u0026#34;\u0026#34;打印两个数的和，不返回值\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;{a} + {b} = {a + b}\u0026#34;) result = print_sum(3, 5) print(f\u0026#34;返回值: {result}\u0026#34;) # None # 使用return单独返回None def check_positive(n): \u0026#34;\u0026#34;\u0026#34;检查是否是正数\u0026#34;\u0026#34;\u0026#34; if n \u0026gt; 0: return True else: return None print(check_positive(5)) # True print(check_positive(-1)) # None 1.5.2 单返回值 # 返回单个值 def square(n): \u0026#34;\u0026#34;\u0026#34;返回n的平方\u0026#34;\u0026#34;\u0026#34; return n ** 2 result = square(5) print(f\u0026#34;5的平方: {result}\u0026#34;) # 25 1.5.3 多返回值 # 返回多个值（实际是返回元组） def calculate(a, b): \u0026#34;\u0026#34;\u0026#34;返回和、差、积\u0026#34;\u0026#34;\u0026#34; return a + b, a - b, a * b # 使用元组接收 result = calculate(10, 3) print(f\u0026#34;结果类型: {type(result)}\u0026#34;) print(f\u0026#34;结果值: {result}\u0026#34;) # 使用解包接收 sum_val, diff, prod = calculate(10, 3) print(f\u0026#34;和: {sum_val}, 差: {diff}, 积: {prod}\u0026#34;) 1.5.4 提前返回 # 使用多个return语句 def absolute_value(n): \u0026#34;\u0026#34;\u0026#34;返回绝对值\u0026#34;\u0026#34;\u0026#34; if n \u0026lt; 0: return -n return n print(absolute_value(-5)) # 5 print(absolute_value(5)) # 5 # 早期返回（Early Return）模式 def process_data(data): \u0026#34;\u0026#34;\u0026#34;处理数据\u0026#34;\u0026#34;\u0026#34; # 验证输入 if not data: return None # 主处理逻辑 result = [] for item in data: if is_valid(item): result.append(process(item)) return result 1.6 文档字符串（Docstring） 1.6.1 文档字符串的作用 文档字符串是紧跟在函数定义之后的一个字符串，用于说明函数的功能、参数、返回值、使用示例等信息。\ndef calculate_circle_area(radius): \u0026#34;\u0026#34;\u0026#34; 计算圆的面积 Parameters: radius (float): 圆的半径，必须为非负数 Returns: float: 圆的面积 Examples: \u0026gt;\u0026gt;\u0026gt; calculate_circle_area(5) 78.53975 \u0026#34;\u0026#34;\u0026#34; if radius \u0026lt; 0: raise ValueError(\u0026#34;半径不能为负数\u0026#34;) return 3.14159 * radius ** 2 1.6.2 文档字符串的格式 # 单行文档字符串 def greet(name): \u0026#34;\u0026#34;\u0026#34;向指定的人打招呼。\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;Hello, {name}!\u0026#34;) # 多行文档字符串 def calculate_stats(numbers): \u0026#34;\u0026#34;\u0026#34; 计算一组数字的统计信息。 参数: numbers (list): 数字列表 返回: dict: 包含平均值、总和、最大值、最小值的字典 示例: \u0026gt;\u0026gt;\u0026gt; calculate_stats([1, 2, 3, 4, 5]) {\u0026#39;avg\u0026#39;: 3.0, \u0026#39;sum\u0026#39;: 15, \u0026#39;max\u0026#39;: 5, \u0026#39;min\u0026#39;: 1} \u0026#34;\u0026#34;\u0026#34; return { \u0026#39;avg\u0026#39;: sum(numbers) / len(numbers), \u0026#39;sum\u0026#39;: sum(numbers), \u0026#39;max\u0026#39;: max(numbers), \u0026#39;min\u0026#39;: min(numbers) } # 访问文档字符串 print(calculate_stats.__doc__) help(calculate_stats) 1.7 函数调用详解 1.7.1 函数调用的过程 # 函数调用过程分析 def add(a, b): \u0026#34;\u0026#34;\u0026#34;加法函数\u0026#34;\u0026#34;\u0026#34; result = a + b return result # 调用步骤： # 1. 传递参数：a=3, b=5 # 2. 执行函数体：result = 8 # 3. 返回结果：return 8 # 4. 接收返回值：total = 8 total = add(3, 5) print(f\u0026#34;结果: {total}\u0026#34;) 1.7.2 嵌套调用 # 函数可以嵌套调用 def square(n): \u0026#34;\u0026#34;\u0026#34;返回n的平方\u0026#34;\u0026#34;\u0026#34; return n ** 2 def sum_of_squares(a, b): \u0026#34;\u0026#34;\u0026#34;返回a的平方加b的平方\u0026#34;\u0026#34;\u0026#34; return square(a) + square(b) result = sum_of_squares(3, 4) # 3² + 4² = 9 + 16 = 25 print(f\u0026#34;3² + 4² = {result}\u0026#34;) 1.8 变量的作用域 1.8.1 局部变量与全局变量 # 全局变量 global_var = \u0026#34;我是全局变量\u0026#34; def test_scope(): # 局部变量 local_var = \u0026#34;我是局部变量\u0026#34; print(f\u0026#34;函数内可以访问全局变量: {global_var}\u0026#34;) print(f\u0026#34;函数内可以访问局部变量: {local_var}\u0026#34;) test_scope() # print(local_var) # 错误！局部变量在函数外无法访问 # 在函数内修改全局变量需要使用global关键字 counter = 0 def increment(): global counter counter += 1 print(f\u0026#34;计数器: {counter}\u0026#34;) increment() increment() print(f\u0026#34;函数外计数器: {counter}\u0026#34;) 1.8.2 LEGB规则 Python查找变量时遵循LEGB规则：\nLocal：局部作用域 Enclosing：闭包作用域 Global：全局作用域 Built-in：内置作用域 # LEGB规则示例 x = \u0026#34;全局变量\u0026#34; def outer(): x = \u0026#34;闭包变量\u0026#34; def inner(): x = \u0026#34;局部变量\u0026#34; print(f\u0026#34;inner中的x: {x}\u0026#34;) # 局部变量 inner() print(f\u0026#34;outer中的x: {x}\u0026#34;) # 闭包变量 outer() print(f\u0026#34;全局中的x: {x}\u0026#34;) # 全局变量 1.9 实用函数示例 1.9.1 数学运算函数 # 判断质数 def is_prime(n): \u0026#34;\u0026#34;\u0026#34;判断n是否为质数\u0026#34;\u0026#34;\u0026#34; if n \u0026lt; 2: return False for i in range(2, int(n ** 0.5) + 1): if n % i == 0: return False return True # 打印n以内的所有质数 def print_primes(n): \u0026#34;\u0026#34;\u0026#34;打印n以内的所有质数\u0026#34;\u0026#34;\u0026#34; primes = [] for i in range(2, n + 1): if is_prime(i): primes.append(i) return primes print(f\u0026#34;100以内的质数: {print_primes(100)}\u0026#34;) # 计算阶乘 def factorial(n): \u0026#34;\u0026#34;\u0026#34;计算n的阶乘\u0026#34;\u0026#34;\u0026#34; if n \u0026lt; 0: raise ValueError(\u0026#34;负数没有阶乘\u0026#34;) if n \u0026lt;= 1: return 1 result = 1 for i in range(2, n + 1): result *= i return result print(f\u0026#34;5! = {factorial(5)}\u0026#34;) # 120 1.9.2 字符串处理函数 # 反转字符串 def reverse_string(s): \u0026#34;\u0026#34;\u0026#34;反转字符串\u0026#34;\u0026#34;\u0026#34; return s[::-1] print(f\u0026#34;反转\u0026#39;abcde\u0026#39;: {reverse_string(\u0026#39;abcde\u0026#39;)}\u0026#34;) # 判断回文 def is_palindrome(s): \u0026#34;\u0026#34;\u0026#34;判断是否为回文\u0026#34;\u0026#34;\u0026#34; clean = \u0026#39;\u0026#39;.join(c.lower() for c in s if c.isalnum()) return clean == clean[::-1] print(f\u0026#34;\u0026#39;上海自来水来自海上\u0026#39;是回文: {is_palindrome(\u0026#39;上海自来水来自海上\u0026#39;)}\u0026#34;) # 统计单词数 def count_words(text): \u0026#34;\u0026#34;\u0026#34;统计单词数量\u0026#34;\u0026#34;\u0026#34; words = text.split() return len(words) print(f\u0026#34;\u0026#39;Hello World Python\u0026#39;有 {count_words(\u0026#39;Hello World Python\u0026#39;)} 个单词\u0026#34;) 1.9.3 数据验证函数 # 验证邮箱格式 def is_valid_email(email): \u0026#34;\u0026#34;\u0026#34;简单验证邮箱格式\u0026#34;\u0026#34;\u0026#34; import re pattern = r\u0026#39;^[\\w\\.-]+@[\\w\\.-]+\\.\\w+$\u0026#39; return bool(re.match(pattern, email)) emails = [\u0026#34;test@example.com\u0026#34;, \u0026#34;invalid-email\u0026#34;, \u0026#34;user@domain.org\u0026#34;] for email in emails: print(f\u0026#34;{email}: {is_valid_email(email)}\u0026#34;) # 验证数字范围 def is_in_range(value, min_val, max_val): \u0026#34;\u0026#34;\u0026#34;验证值是否在指定范围内\u0026#34;\u0026#34;\u0026#34; return min_val \u0026lt;= value \u0026lt;= max_val print(f\u0026#34;5在1-10范围内: {is_in_range(5, 1, 10)}\u0026#34;) 1.10 最佳实践 1.10.1 函数设计原则 # 单一职责原则：每个函数只做一件事 # 不好：一个函数做多件事 def process_user(name, age, action): if action == \u0026#34;create\u0026#34;: print(f\u0026#34;创建用户 {name}, 年龄 {age}\u0026#34;) elif action == \u0026#34;delete\u0026#34;: print(f\u0026#34;删除用户 {name}\u0026#34;) elif action == \u0026#34;update\u0026#34;: print(f\u0026#34;更新用户 {name}, 年龄 {age}\u0026#34;) # 好：每个函数职责单一 def create_user(name, age): \u0026#34;\u0026#34;\u0026#34;创建用户\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;创建用户 {name}, 年龄 {age}\u0026#34;) def delete_user(name): \u0026#34;\u0026#34;\u0026#34;删除用户\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;删除用户 {name}\u0026#34;) def update_user(name, age): \u0026#34;\u0026#34;\u0026#34;更新用户\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;更新用户 {name}, 年龄 {age}\u0026#34;) 1.10.2 参数设计建议 # 使用有意义的参数名 def calculate_area(width, height): # 好 return width * height # 避免使用魔法数字 def calculate_circle_area(radius, pi=3.14159): # 使用默认参数 return pi * radius ** 2 1.10.3 文档字符串编写规范 # 使用docstring格式 def function_name(param1, param2): \u0026#34;\u0026#34;\u0026#34; 简短描述（第一行以动词开头，句号结尾） 详细描述（可选，说明函数的工作原理） Args: param1: 参数1的说明 param2: 参数2的说明 Returns: 返回值的说明 Raises: ValueError: 何时抛出此异常 Examples: \u0026gt;\u0026gt;\u0026gt; function_name(1, 2) 3 \u0026#34;\u0026#34;\u0026#34; pass 1.11 常见错误与调试 1.11.1 常见错误 # 错误1：忘记写冒号 # def greet(name) # 缺少冒号 # print(f\u0026#34;Hello, {name}\u0026#34;) # 错误2：参数名拼写错误 def greet(name): print(f\u0026#34;Hello, {name}\u0026#34;) # greet(neme) # NameError: name \u0026#39;neme\u0026#39; is not defined # 错误3：参数数量不匹配 def add(a, b): return a + b # add(1) # TypeError: add() missing 1 required argument # add(1, 2, 3) # TypeError: add() takes 2 positional arguments but 3 were given # 错误4：修改不可变对象 # def modify_immutable(s): # s += \u0026#34; world\u0026#34; # 创建了新字符串，原字符串不变 1.11.2 调试技巧 # 使用print调试 def buggy_function(n): print(f\u0026#34;[DEBUG] 输入: {n}\u0026#34;) result = 0 for i in range(n): result += i print(f\u0026#34;[DEBUG] i={i}, result={result}\u0026#34;) return result # 使用assert调试 def divide(a, b): assert b != 0, \u0026#34;除数不能为零\u0026#34; return a / b 二、背诵版 Day10 要点速记： 【函数定义】 def 函数名(参数1, 参数2, ...): \u0026#34;\u0026#34;\u0026#34;文档字符串\u0026#34;\u0026#34;\u0026#34; 函数体 return 返回值 【参数类型】 - 位置参数：按顺序传递 - 关键字参数：按名称传递 - 默认参数：parameter=默认值 - *args：**kwargs 【返回值】 - 无return：返回None - return 值：返回单个值 - return 值1, 值2：返回元组 【文档字符串】 单行：\u0026#34;\u0026#34;\u0026#34;简洁描述\u0026#34;\u0026#34;\u0026#34; 多行：详细说明Args/Returns/Examples 【作用域】 LEGB: Local → Enclosing → Global → Built-in global关键字：在函数内修改全局变量 三、考前记忆 要素 内容 今日主题 函数定义与调用 关键词 函数定义、调用、参数、返回值、文档字符串 定义语法 def 函数名(参数): 返回值 无return返回None 多返回值 return a, b（返回元组） 文档字符串 函数后的三引号字符串 参数传递 位置参数、关键字参数、默认参数 重要考点 参数传递、返回值处理、作用域 四、测试题 1. 单选题： 以下哪个是函数定义的正确语法？\nA. function greet(name): B. def greet(name): C. func greet(name): D. greet(name) def: 2. 单选题： 函数没有return语句时，返回值是什么？\nA. 0 B. \u0026quot;\u0026quot; C. None D. False 3. 单选题： 以下代码的输出是什么？\ndef test(a, b=10): return a + b print(test(5)) A. 5 B. 10 C. 15 D. 错误 4. 填空题： return语句可以返回 _______（填\u0026quot;一个\u0026quot;或\u0026quot;多个\u0026quot;）值。\n5. 填空题： 在函数内部修改全局变量，需要使用 _______ 关键字。\n6. 简答题： 请说明位置参数和关键字参数的区别。\n7. 代码题： 定义一个函数，接受两个参数x和y，返回它们的和、差、积。\n8. 代码题： 定义一个函数，计算一个列表中所有正整数的和。\n9. 代码题： 为以下函数编写文档字符串：\ndef find_max(numbers): # 找出列表中的最大值 if not numbers: return None max_val = numbers[0] for num in numbers: if num \u0026gt; max_val: max_val = num return max_val 10. 综合题： 设计一个计算器程序，包含加、减、乘、除四个函数，用户输入两个数和一个运算符，程序返回计算结果。\nB - Python函数定义使用def关键字\nC - 函数没有return语句时，默认返回None\nC - b使用默认值10，所以5+10=15\n多个 - return可以返回多个值，实际是返回元组\nglobal - 使用global关键字可以在函数内修改全局变量\n位置参数和关键字参数的区别： 位置参数： - 按照参数定义的顺序传递 - 必须传递所有必需的位置参数 - 例如：func(1, 2, 3) 关键字参数： - 按照参数名称传递 - 可以改变顺序 - 例如：func(a=1, c=3, b=2) 可以混合使用，但位置参数必须在关键字参数前面 def calculate(a, b): \u0026#34;\u0026#34;\u0026#34;返回a和b的和、差、积\u0026#34;\u0026#34;\u0026#34; return a + b, a - b, a * b sum_val, diff, prod = calculate(10, 3) print(f\u0026#34;和: {sum_val}, 差: {diff}, 积: {prod}\u0026#34;) def sum_positive(numbers): \u0026#34;\u0026#34;\u0026#34;计算列表中所有正整数的和\u0026#34;\u0026#34;\u0026#34; total = 0 for num in numbers: if num \u0026gt; 0: total += num return total print(sum_positive([1, -2, 3, -4, 5])) # 9 def find_max(numbers): \u0026#34;\u0026#34;\u0026#34; 找出列表中的最大值。 Parameters: numbers (list): 数字列表 Returns: number or None: 列表中的最大值，如果列表为空则返回None Examples: \u0026gt;\u0026gt;\u0026gt; find_max([1, 5, 3, 9, 2]) 9 \u0026gt;\u0026gt;\u0026gt; find_max([]) None \u0026#34;\u0026#34;\u0026#34; if not numbers: return None max_val = numbers[0] for num in numbers: if num \u0026gt; max_val: max_val = num return max_val def add(a, b): \u0026#34;\u0026#34;\u0026#34;加法\u0026#34;\u0026#34;\u0026#34; return a + b def subtract(a, b): \u0026#34;\u0026#34;\u0026#34;减法\u0026#34;\u0026#34;\u0026#34; return a - b def multiply(a, b): \u0026#34;\u0026#34;\u0026#34;乘法\u0026#34;\u0026#34;\u0026#34; return a * b def divide(a, b): \u0026#34;\u0026#34;\u0026#34;除法\u0026#34;\u0026#34;\u0026#34; if b == 0: return \u0026#34;错误：除数不能为零\u0026#34; return a / b operations = { \u0026#39;+\u0026#39;: add, \u0026#39;-\u0026#39;: subtract, \u0026#39;*\u0026#39;: multiply, \u0026#39;/\u0026#39;: divide } def calculator(): \u0026#34;\u0026#34;\u0026#34;简单计算器\u0026#34;\u0026#34;\u0026#34; print(\u0026#34;=== 简单计算器 ===\u0026#34;) try: num1 = float(input(\u0026#34;请输入第一个数: \u0026#34;)) operator = input(\u0026#34;请输入运算符(+,-,*,/): \u0026#34;) num2 = float(input(\u0026#34;请输入第二个数: \u0026#34;)) if operator not in operations: print(\u0026#34;无效的运算符\u0026#34;) return result = operations[operator](num1, num2) print(f\u0026#34;结果: {num1} {operator} {num2} = {result}\u0026#34;) except ValueError: print(\u0026#34;输入无效\u0026#34;) calculator() 五、扩展阅读 5.1 函数注解（Type Hints） Python 3.5+支持函数注解，用于指定参数和返回值的类型：\ndef greet(name: str, times: int = 1) -\u0026gt; str: \u0026#34;\u0026#34;\u0026#34;打招呼\u0026#34;\u0026#34;\u0026#34; return (f\u0026#34;Hello, {name}! \u0026#34; * times).strip() # 使用函数注解 print(greet(\u0026#34;Alice\u0026#34;, 2)) # 运行时获取注解 print(greet.__annotations__) 5.2 高阶函数 函数可以像变量一样作为参数传递：\ndef apply_twice(func, value): \u0026#34;\u0026#34;\u0026#34;对值应用函数两次\u0026#34;\u0026#34;\u0026#34; return func(func(value)) def square(x): return x ** 2 print(apply_twice(square, 3)) # (3²)² = 81 5.3 匿名函数（Lambda） # 使用lambda表达式创建简短函数 square = lambda x: x ** 2 print(square(5)) # 25 # 与内置函数结合使用 numbers = [1, 2, 3, 4, 5] squares = list(map(lambda x: x ** 2, numbers)) evens = list(filter(lambda x: x % 2 == 0, numbers)) print(f\u0026#34;平方: {squares}\u0026#34;) print(f\u0026#34;偶数: {evens}\u0026#34;) 恭喜完成Day10学习！Python基础循环与函数部分已全部完成。明天的Day11将进一步学习函数的返回值高级应用。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-10-function-basics/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：04_函数 hm_01~hm_06 + Python官方文档 + 网络资料整理\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-核心概念\"\u003e1.1 核心概念\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e函数定义与调用\u003c/strong\u003e是Python编程中的核心知识点，也是代码模块化、复用和组织的基石。在本课程的第10天，我们将系统学习函数的基本概念、定义语法、参数传递、返回值处理，以及文档字符串的编写。\u003c/p\u003e\n\u003cp\u003e函数是一段\u003cstrong\u003e组织好的、可重复使用的、用来实现单一或相关联功能\u003c/strong\u003e的代码块。在Python中，函数不仅是一种代码复用的手段，更是实现\u003cstrong\u003e面向过程编程\u003c/strong\u003e和\u003cstrong\u003e模块化设计\u003c/strong\u003e的基础。通过函数，我们可以将复杂的问题分解为多个小问题，使程序结构更加清晰、易于维护。\u003c/p\u003e\n\u003ch3 id=\"12-函数基础\"\u003e1.2 函数基础\u003c/h3\u003e\n\u003ch4 id=\"121-为什么要使用函数\"\u003e1.2.1 为什么要使用函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 不使用函数：代码重复\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;=== 计算圆的面积 ===\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eradius \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003earea \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3.14159\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e radius \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;半径\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eradius\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e的圆面积: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003earea\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eradius \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003earea \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3.14159\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e radius \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;半径\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eradius\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e的圆面积: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003earea\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eradius \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e15\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003earea \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3.14159\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e radius \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;半径\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eradius\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e的圆面积: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003earea\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用函数：代码复用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecalculate_circle_area\u003c/span\u003e(radius):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;计算圆的面积\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    area \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3.14159\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e radius \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e area\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e=== 使用函数 ===\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e r \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e15\u003c/span\u003e]:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;半径\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003er\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e的圆面积: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecalculate_circle_area(r)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"122-函数定义的基本语法\"\u003e1.2.2 函数定义的基本语法\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 函数定义的基本结构\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e函数名\u003c/span\u003e(参数1, 参数2, \u003cspan style=\"color:#f92672\"\u003e...\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;文档字符串（可选）\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 函数体\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e 返回值  \u003cspan style=\"color:#75715e\"\u003e# 可选\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"13-函数的定义与调用\"\u003e1.3 函数的定义与调用\u003c/h3\u003e\n\u003ch4 id=\"131-无参函数\"\u003e1.3.1 无参函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 无参函数：不需要输入参数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egreet\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;简单的问候函数\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Hello, World!\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Welcome to Python!\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 调用函数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egreet()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 可以多次调用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egreet()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egreet()\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"132-有参函数\"\u003e1.3.2 有参函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 有参函数：需要输入参数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egreet_person\u003c/span\u003e(name):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;向指定的人打招呼\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Hello, \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e!\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Welcome, \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e!\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 调用函数，传入参数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egreet_person(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Alice\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egreet_person(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Bob\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"133-多参数函数\"\u003e1.3.3 多参数函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 多个参数的函数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecalculate_rectangle\u003c/span\u003e(length, width):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;计算矩形的面积和周长\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    area \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e length \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e width\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    perimeter \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e (length \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e width)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e area, perimeter\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 调用函数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e calculate_rectangle(\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;面积: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresult[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e, 周长: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresult[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用解包\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003earea, perimeter \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e calculate_rectangle(\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;面积: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003earea\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;周长: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eperimeter\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"14-参数详解\"\u003e1.4 参数详解\u003c/h3\u003e\n\u003ch4 id=\"141-位置参数\"\u003e1.4.1 位置参数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 位置参数：按顺序传递\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eintroduce\u003c/span\u003e(name, age, city):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;自我介绍\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;我叫\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e，今年\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eage\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e岁，来自\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecity\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e。\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 调用时按位置传递\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eintroduce(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e25\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;北京\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eintroduce(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;李四\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;上海\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eintroduce(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;王五\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e28\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;广州\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 位置参数必须传递，且顺序不能错\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# introduce(\u0026#34;赵六\u0026#34;)  # 错误：缺少参数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# introduce(25, \u0026#34;钱七\u0026#34;, \u0026#34;深圳\u0026#34;)  # 错误：类型不匹配\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"142-关键字参数\"\u003e1.4.2 关键字参数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 关键字参数：按名称传递\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eintroduce\u003c/span\u003e(name, age, city):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;自我介绍\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;我叫\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e，今年\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eage\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e岁，来自\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecity\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e。\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用关键字参数，顺序可以改变\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eintroduce(age\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e, name\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e, city\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;北京\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 混合使用：位置参数必须在关键字参数前面\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eintroduce(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;李四\u0026#34;\u003c/span\u003e, city\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;上海\u0026#34;\u003c/span\u003e, age\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e28\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"143-默认参数\"\u003e1.4.3 默认参数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 默认参数：给参数设置默认值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egreet\u003c/span\u003e(name, greeting\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Hello\u0026#34;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;带默认参数的问候函数\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003egreeting\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e, \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e!\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 调用时可以不指定默认参数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egreet(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Alice\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# Hello, Alice!\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egreet(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Bob\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Hi\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# Hi, Bob!\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 默认参数必须在位置参数后面\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# def greet(greeting=\u0026#34;Hello\u0026#34;, name):  # 错误！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 默认参数可以是有副作用的可变对象（需要注意）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"144-默认参数的最佳实践\"\u003e1.4.4 默认参数的最佳实践\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 避免使用可变对象作为默认参数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 错误示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eadd_to_list\u003c/span\u003e(item, target_list\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e[]):  \u003cspan style=\"color:#75715e\"\u003e# 危险！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    target_list\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(item)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e target_list\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(add_to_list(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# [1]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(add_to_list(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# [1, 2] - 不是 [2]！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 正确示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eadd_to_list\u003c/span\u003e(item, target_list\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e):  \u003cspan style=\"color:#75715e\"\u003e# 正确\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e target_list \u003cspan style=\"color:#f92672\"\u003eis\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        target_list \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    target_list\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(item)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e target_list\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(add_to_list(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# [1]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(add_to_list(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# [2]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"15-返回值详解\"\u003e1.5 返回值详解\u003c/h3\u003e\n\u003ch4 id=\"151-无返回值函数\"\u003e1.5.1 无返回值函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 没有return语句的函数，默认返回None\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eprint_sum\u003c/span\u003e(a, b):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;打印两个数的和，不返回值\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e + \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eb\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e b\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e print_sum(\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;返回值: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresult\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# None\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用return单独返回None\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003echeck_positive\u003c/span\u003e(n):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;检查是否是正数\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e n \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(check_positive(\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e))   \u003cspan style=\"color:#75715e\"\u003e# True\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(check_positive(\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# None\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"152-单返回值\"\u003e1.5.2 单返回值\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 返回单个值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003esquare\u003c/span\u003e(n):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;返回n的平方\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e n \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e square(\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;5的平方: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresult\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 25\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"153-多返回值\"\u003e1.5.3 多返回值\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 返回多个值（实际是返回元组）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecalculate\u003c/span\u003e(a, b):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;返回和、差、积\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e b, a \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e b, a \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e b\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用元组接收\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e calculate(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;结果类型: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etype(result)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;结果值: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresult\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用解包接收\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esum_val, diff, prod \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e calculate(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;和: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003esum_val\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e, 差: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ediff\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e, 积: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eprod\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"154-提前返回\"\u003e1.5.4 提前返回\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用多个return语句\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eabsolute_value\u003c/span\u003e(n):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;返回绝对值\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e n \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003en\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e n\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(absolute_value(\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(absolute_value(\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e))   \u003cspan style=\"color:#75715e\"\u003e# 5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 早期返回（Early Return）模式\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eprocess_data\u003c/span\u003e(data):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;处理数据\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 验证输入\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e data:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 主处理逻辑\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    result \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e item \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e data:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e is_valid(item):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            result\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(process(item))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e result\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"16-文档字符串docstring\"\u003e1.6 文档字符串（Docstring）\u003c/h3\u003e\n\u003ch4 id=\"161-文档字符串的作用\"\u003e1.6.1 文档字符串的作用\u003c/h4\u003e\n\u003cp\u003e文档字符串是紧跟在函数定义之后的一个字符串，用于说明函数的\u003cstrong\u003e功能、参数、返回值、使用示例\u003c/strong\u003e等信息。\u003c/p\u003e","tags":"Python, 编程, 函数定义","title":"Day10 函数定义与调用"},{"columns":"acp-course","content":" 来源：Notion ACP学习笔记\nACP Day10 学习整理｜云数据库RDS 主资料为《云数据库RDS》，补充资料为《云数据库RDS的操作实践》；本节应按“RDS 产品能力 + DMS / 迁移实践”两层来理解。\n今日主题 Notion 标题：🗄️ Day10 云数据库RDS\n核心理解：RDS 是关系型数据库的云服务化形态，DMS 负责管理，迁移流程负责把业务数据库接入 RDS。\n重点整理 RDS 的核心价值：高可用、自动备份、弹性扩展、安全体系完善、运维成本低。\nRDS 支持 MySQL、SQL Server、PostgreSQL、MariaDB TX 等关系型引擎。\nRDS 重要维度包括：产品系列、规格族、存储类型、备份恢复、安全体系。\n实践主线是：创建账号 -\u0026gt; 通过 DMS 建库 -\u0026gt; 导入本地 MySQL 数据 -\u0026gt; 修改 WordPress 配置 -\u0026gt; 验证应用改连 RDS 成功。\n高频考点 为什么企业更愿意用 RDS：因为高可用、备份恢复、安全和扩容等能力被服务化了。\nDMS 和 RDS 的关系：RDS 是数据库实例，DMS 是数据库管理平台。\n为什么迁移后要改 wp-config.php：因为应用端必须把数据库连接从本地 MySQL 改到 RDS。\n为什么备份恢复是重点：数据库场景最关键的是故障后的可恢复性。\n背诵版 Day10 核心主题是云数据库 RDS。\nRDS 是关系型数据库的云服务化形态。\nRDS 的重要能力包括高可用、自动备份、安全体系、弹性扩展。\nDMS 是数据库管理平台，RDS 是数据库实例本体。\n迁移业务到 RDS 后，应用配置必须改到 RDS 地址。\n自测题 什么是云数据库 RDS？它和传统自建数据库的区别是什么？\nRDS 支持哪些常见数据库引擎？\nDMS 和 RDS 的关系是什么？\n为什么迁移 WordPress 到 RDS 后必须修改 wp-config.php？\n易错点 不要把 RDS 和 DMS 混成一个概念，RDS 是实例，DMS 是管理平台。\n不要把 Day10 理解成只会建库，它真正考的是产品能力 + 管理链路 + 迁移链路。\n不要忽略备份恢复，它们是数据库可靠性能力的核心。\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-10-acp-day-10-%E4%BA%91%E6%95%B0%E6%8D%AE%E5%BA%93rds/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：Notion ACP学习笔记\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"acp-day10-学习整理云数据库rds\"\u003eACP Day10 学习整理｜云数据库RDS\u003c/h2\u003e\n\u003cp\u003e主资料为《云数据库RDS》，补充资料为《云数据库RDS的操作实践》；本节应按“RDS 产品能力 + DMS / 迁移实践”两层来理解。\u003c/p\u003e\n\u003ch3 id=\"今日主题\"\u003e今日主题\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eNotion 标题：🗄️ Day10 云数据库RDS\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e核心理解：RDS 是关系型数据库的云服务化形态，DMS 负责管理，迁移流程负责把业务数据库接入 RDS。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"重点整理\"\u003e重点整理\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eRDS 的核心价值：高可用、自动备份、弹性扩展、安全体系完善、运维成本低。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRDS 支持 MySQL、SQL Server、PostgreSQL、MariaDB TX 等关系型引擎。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRDS 重要维度包括：产品系列、规格族、存储类型、备份恢复、安全体系。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e实践主线是：创建账号 -\u0026gt; 通过 DMS 建库 -\u0026gt; 导入本地 MySQL 数据 -\u0026gt; 修改 WordPress 配置 -\u0026gt; 验证应用改连 RDS 成功。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"高频考点\"\u003e高频考点\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e为什么企业更愿意用 RDS：因为高可用、备份恢复、安全和扩容等能力被服务化了。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eDMS 和 RDS 的关系：RDS 是数据库实例，DMS 是数据库管理平台。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为什么迁移后要改 wp-config.php：因为应用端必须把数据库连接从本地 MySQL 改到 RDS。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为什么备份恢复是重点：数据库场景最关键的是故障后的可恢复性。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"背诵版\"\u003e背诵版\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eDay10 核心主题是云数据库 RDS。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRDS 是关系型数据库的云服务化形态。\u003c/p\u003e","tags":"ACP, 阿里云","title":"ACP Day 10 云数据库RDS"},{"columns":"python-course","content":"Python 第十一天：函数返回值与 None 目录 函数返回值基础 return 语句详解 None 的本质与应用 多返回值与元组解包 return 与 print 的区别 早期返回（Early Return）模式 条件返回与三目运算符 生成器函数的返回值 lambda 表达式与返回值 实战练习与最佳实践 1. 函数返回值基础 什么是返回值 返回值是函数执行完毕后向调用者提供的结果数据。在 Python 中，使用 return 语句来指定函数的返回值。当一个函数没有 return 语句，或者 return 语句后面没有任何表达式时，函数默认返回 None。\n# 最简单的返回值示例 def greet(): return \u0026#34;你好，世界！\u0026#34; result = greet() print(result) # 输出: 你好，世界！ 返回值的基本类型 Python 函数可以返回各种类型的数据，包括但不限于：\n字符串：返回文本信息 数字：返回计算结果 布尔值：返回判断结果 列表/元组/字典：返回集合数据 对象：返回自定义类的实例 None：表示空或无返回值 # 返回不同类型的示例 def return_types_demo(): return \u0026#34;Hello\u0026#34; # 字符串 return 42 # 数字 return [1, 2, 3] # 列表 return {\u0026#34;name\u0026#34;: \u0026#34;Alice\u0026#34;} # 字典 return True # 布尔值 return None # None 值 注意：函数一旦执行到 return 语句就会立即结束，后面的代码不会执行。上面的例子中，只有第一个 return 会生效。\n函数调用与返回值 函数调用本身是一个表达式，它的值就是函数的返回值。我们可以将返回值赋值给变量，参与运算，或者作为其他函数的参数。\n# 基本赋值 def add(a, b): return a + b result = add(3, 5) print(f\u0026#34;3 + 5 = {result}\u0026#34;) # 输出: 3 + 5 = 8 # 参与运算 double = add(3, 5) * 2 print(f\u0026#34;(3 + 5) * 2 = {double}\u0026#34;) # 输出: (3 + 5) * 2 = 16 # 作为函数参数 print(f\u0026#34;结果是: {add(10, 20)}\u0026#34;) # 输出: 结果是: 30 2. return 语句详解 return 的语法形式 Python 中 return 语句有多种语法形式：\n# 形式1: return 表达式 def return_expression(): return 42 # 形式2: return (表达式) - 括号可省略 def return_with_parens(): return (3.14) # 形式3: return - 返回 None def return_no_value(): return # 形式4: 无 return 语句 - 隐式返回 None def no_return(): pass return 与函数终止 return 语句不仅返回值，还会立即终止函数的执行。这意味着在 return 之后的任何代码都不会执行。\ndef process_and_return(): print(\u0026#34;第一步：处理数据\u0026#34;) return \u0026#34;完成\u0026#34; print(\u0026#34;这一步永远不会执行\u0026#34;) result = process_and_return() # 输出: 第一步：处理数据 print(f\u0026#34;返回值: {result}\u0026#34;) # 输出: 返回值: 完成 在循环中使用 return 在函数内的循环中使用 return 可以提前退出函数，这在搜索场景中非常有用。\ndef find_even_number(numbers): \u0026#34;\u0026#34;\u0026#34;查找第一个偶数，找到则立即返回\u0026#34;\u0026#34;\u0026#34; for num in numbers: if num % 2 == 0: return f\u0026#34;找到偶数: {num}\u0026#34; return \u0026#34;未找到偶数\u0026#34; # 测试 print(find_even_number([1, 3, 5, 8, 9])) # 输出: 找到偶数: 8 print(find_even_number([1, 3, 5, 7, 9])) # 输出: 未找到偶数 return 与异常处理 在 try-except-finally 结构中，return 行为有其特殊性：\ndef try_return(): try: print(\u0026#34;try 块执行\u0026#34;) return \u0026#34;try 返回值\u0026#34; except: return \u0026#34;except 返回值\u0026#34; finally: print(\u0026#34;finally 块总是执行\u0026#34;) result = try_return() # 输出: # try 块执行 # finally 块总是执行 print(f\u0026#34;返回值: {result}\u0026#34;) # 输出: 返回值: try 返回值 3. None 的本质与应用 什么是 None None 是 Python 中一个特殊的单例对象，表示\u0026quot;空\u0026quot;或\u0026quot;无值\u0026quot;。它不是 0、False 或空字符串，而是一个完全独立的类型 NoneType。\n# None 的类型 print(type(None)) # 输出: \u0026lt;class \u0026#39;NoneType\u0026#39;\u0026gt; # None 是单例对象 a = None b = None print(a is b) # 输出: True（注意：应该用 is 而不是 == 比较 None） None 与 == / is 的区别 这是一个非常容易出错的点：== 比较的是值相等，而 is 比较的是身份（内存地址）相同。\nresult = None # 正确判断 None 的方式 if result is None: print(\u0026#34;result 是 None\u0026#34;) else: print(\u0026#34;result 不是 None\u0026#34;) # 不推荐的方式（虽然通常也能工作） if result == None: print(\u0026#34;result 等于 None\u0026#34;) # None 与 False 的区别 print(None == False) # 输出: False print(None == 0) # 输出: False print(None == \u0026#34;\u0026#34;) # 输出: False print(None == []) # 输出: False 函数默认返回 None 以下情况函数会返回 None：\n# 情况1: 完全没有 return 语句 def func1(): print(\u0026#34;执行了一些操作\u0026#34;) # 情况2: return 后面没有表达式 def func2(): return # 情况3: 只有 pass 语句 def func3(): pass # 验证 print(func1()) # 输出: 执行了一些操作 \\n None print(func2()) # 输出: None print(func3()) # 输出: None None 的实际应用场景 场景1：可选参数的默认值 def create_user(name, email=None, phone=None): \u0026#34;\u0026#34;\u0026#34;创建用户，可选参数默认为 None\u0026#34;\u0026#34;\u0026#34; user = {\u0026#34;name\u0026#34;: name} if email: user[\u0026#34;email\u0026#34;] = email if phone: user[\u0026#34;phone\u0026#34;] = phone return user # 使用默认值的例子 user1 = create_user(\u0026#34;张三\u0026#34;) print(user1) # 输出: {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;} user2 = create_user(\u0026#34;李四\u0026#34;, email=\u0026#34;li@example.com\u0026#34;) print(user2) # 输出: {\u0026#39;name\u0026#39;: \u0026#39;李四\u0026#39;, \u0026#39;email\u0026#39;: \u0026#39;li@example.com\u0026#39;} 场景2：表示\u0026quot;没有找到\u0026quot; def find_by_id(items, target_id): \u0026#34;\u0026#34;\u0026#34;在列表中查找 id 匹配的元素\u0026#34;\u0026#34;\u0026#34; for item in items: if item[\u0026#34;id\u0026#34;] == target_id: return item return None # 明确返回 None 表示未找到 users = [ {\u0026#34;id\u0026#34;: 1, \u0026#34;name\u0026#34;: \u0026#34;Alice\u0026#34;}, {\u0026#34;id\u0026#34;: 2, \u0026#34;name\u0026#34;: \u0026#34;Bob\u0026#34;}, {\u0026#34;id\u0026#34;: 3, \u0026#34;name\u0026#34;: \u0026#34;Charlie\u0026#34;} ] result = find_by_id(users, 5) if result is None: print(\u0026#34;未找到该用户\u0026#34;) else: print(f\u0026#34;找到: {result}\u0026#34;) 场景3：条件赋值 def get_display_name(user): \u0026#34;\u0026#34;\u0026#34;获取显示名称，如果昵称为空则用真名\u0026#34;\u0026#34;\u0026#34; nickname = user.get(\u0026#34;nickname\u0026#34;) return nickname if nickname else user.get(\u0026#34;name\u0026#34;, \u0026#34;匿名用户\u0026#34;) user1 = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;nickname\u0026#34;: \u0026#34;小张\u0026#34;} user2 = {\u0026#34;name\u0026#34;: \u0026#34;李四\u0026#34;} print(get_display_name(user1)) # 输出: 小张 print(get_display_name(user2)) # 输出: 李四 4. 多返回值与元组解包 返回多个值 Python 函数可以通过返回元组的方式返回多个值：\ndef get_statistics(numbers): \u0026#34;\u0026#34;\u0026#34;返回多个统计值\u0026#34;\u0026#34;\u0026#34; total = sum(numbers) count = len(numbers) average = total / count if count \u0026gt; 0 else 0 return total, count, average # 实际上是返回一个元组 # 调用并接收返回值 result = get_statistics([10, 20, 30, 40, 50]) print(result) # 输出: (150, 5, 30.0) print(type(result)) # 输出: \u0026lt;class \u0026#39;tuple\u0026#39;\u0026gt; 元组解包接收多返回值 Python 支持元组解包，可以将返回的元组直接分解为多个变量：\ndef get_min_max(numbers): \u0026#34;\u0026#34;\u0026#34;返回最小值和最大值\u0026#34;\u0026#34;\u0026#34; if not numbers: return None, None return min(numbers), max(numbers) # 方式1：元组整体接收 result = get_min_max([3, 1, 4, 1, 5, 9, 2, 6]) print(f\u0026#34;返回的元组: {result}\u0026#34;) # 方式2：元组解包 min_val, max_val = get_min_max([3, 1, 4, 1, 5, 9, 2, 6]) print(f\u0026#34;最小值: {min_val}, 最大值: {max_val}\u0026#34;) # 方式3：使用 _ 忽略不需要的值 _, _, average = get_statistics([10, 20, 30]) print(f\u0026#34;平均值: {average}\u0026#34;) 多返回值的高级用法 交换两个变量的值 def swap(a, b): \u0026#34;\u0026#34;\u0026#34;交换两个值\u0026#34;\u0026#34;\u0026#34; return b, a x, y = 10, 20 print(f\u0026#34;交换前: x = {x}, y = {y}\u0026#34;) x, y = swap(x, y) print(f\u0026#34;交换后: x = {x}, y = {y}\u0026#34;) # 输出: # 交换前: x = 10, y = 20 # 交换后: x = 20, y = 10 返回命名数据 from dataclasses import dataclass @dataclass class Result: success: bool message: str data: any = None def divide(a, b): \u0026#34;\u0026#34;\u0026#34;除法运算，返回命名结果\u0026#34;\u0026#34;\u0026#34; if b == 0: return Result(success=False, message=\u0026#34;除数不能为零\u0026#34;) return Result(success=True, message=\u0026#34;成功\u0026#34;, data=a / b) result = divide(10, 3) if result.success: print(f\u0026#34;计算结果: {result.data}\u0026#34;) else: print(f\u0026#34;错误: {result.message}\u0026#34;) 5. return 与 print 的区别 核心区别 这是一个新手常犯的错误：print 只是将信息输出到控制台，不返回任何有用的值；而 return 是将值返回给调用者。\n# 错误示例：混淆 print 和 return def add_and_print(a, b): print(a + b) # 只是打印，没有返回值 def add_and_return(a, b): return a + b # 返回结果 # print 返回 None result = add_and_print(3, 5) print(f\u0026#34;print 的返回值: {result}\u0026#34;) # 输出: print 的返回值: None # return 返回计算结果 result = add_and_return(3, 5) print(f\u0026#34;return 的返回值: {result}\u0026#34;) # 输出: return 的返回值: 8 实际应用对比 print 用于调试 def calculate_with_debug(numbers): \u0026#34;\u0026#34;\u0026#34;计算时打印中间结果用于调试\u0026#34;\u0026#34;\u0026#34; total = 0 for i, num in enumerate(numbers): total += num print(f\u0026#34;第 {i+1} 步: 加 {num}, 当前总和 = {total}\u0026#34;) return total result = calculate_with_debug([1, 2, 3, 4, 5]) print(f\u0026#34;最终结果: {result}\u0026#34;) # 输出: # 第 1 步: 加 1, 当前总和 = 1 # 第 2 步: 加 2, 当前总和 = 3 # 第 3 步: 加 3, 当前总和 = 6 # 第 4 步: 加 4, 当前总和 = 10 # 第 5 步: 加 5, 当前总和 = 15 # 最终结果: 15 return 用于返回结果 def calculate_total(numbers): \u0026#34;\u0026#34;\u0026#34;真正返回计算结果\u0026#34;\u0026#34;\u0026#34; total = sum(numbers) return total # 返回值可以用于后续计算 result = calculate_total([1, 2, 3, 4, 5]) print(f\u0026#34;结果可以参与后续计算: {result * 2}\u0026#34;) # 输出: 30 日志记录与返回值的最佳实践 import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def process_data(data): \u0026#34;\u0026#34;\u0026#34;演示：正确区分日志和返回值\u0026#34;\u0026#34;\u0026#34; logger.info(f\u0026#34;开始处理数据: {data}\u0026#34;) if not data: logger.warning(\u0026#34;数据为空\u0026#34;) return None # 处理逻辑... result = data.upper() logger.info(f\u0026#34;处理完成: {data} -\u0026gt; {result}\u0026#34;) return result # 使用 output = process_data(\u0026#34;hello world\u0026#34;) print(f\u0026#34;最终输出: {output}\u0026#34;) 6. 早期返回（Early Return）模式 什么是早期返回 早期返回是指在函数的开头或早期阶段检查条件，如果不满足条件则立即返回，而不是继续执行后续代码。这是一种防御性编程技巧。\n验证参数模式 def divide(a, b): \u0026#34;\u0026#34;\u0026#34;除法函数，使用早期返回验证参数\u0026#34;\u0026#34;\u0026#34; # 早期返回：检查参数有效性 if b == 0: print(\u0026#34;错误：除数不能为零\u0026#34;) return None # 早期返回：检查类型 if not isinstance(a, (int, float)): print(\u0026#34;错误：被除数必须是数字\u0026#34;) return None if not isinstance(b, (int, float)): print(\u0026#34;错误：除数必须是数字\u0026#34;) return None # 主逻辑 return a / b # 测试 print(divide(10, 2)) # 输出: 5.0 print(divide(10, 0)) # 输出: 错误：除数不能为零 \\n None print(divide(\u0026#34;abc\u0026#34;, 2)) # 输出: 错误：被除数必须是数字 \\n None 减少嵌套的早期返回 # 不使用早期返回（深层嵌套） def process_order_bad(order): if order: if order.is_valid(): if order.has_items(): # 终于到达主逻辑 return process(order) else: return {\u0026#34;error\u0026#34;: \u0026#34;订单没有商品\u0026#34;} else: return {\u0026#34;error\u0026#34;: \u0026#34;订单无效\u0026#34;} else: return {\u0026#34;error\u0026#34;: \u0026#34;订单为空\u0026#34;} # 使用早期返回（扁平结构） def process_order_good(order): \u0026#34;\u0026#34;\u0026#34;使用早期返回减少嵌套\u0026#34;\u0026#34;\u0026#34; if not order: return {\u0026#34;error\u0026#34;: \u0026#34;订单为空\u0026#34;} if not order.is_valid(): return {\u0026#34;error\u0026#34;: \u0026#34;订单无效\u0026#34;} if not order.has_items(): return {\u0026#34;error\u0026#34;: \u0026#34;订单没有商品\u0026#34;} # 主逻辑在最外层 return process(order) 早期返回与资源清理 import sqlite3 def get_user_by_id(user_id): \u0026#34;\u0026#34;\u0026#34;查询用户，使用早期返回处理各种情况\u0026#34;\u0026#34;\u0026#34; # 参数验证 if user_id is None: print(\u0026#34;错误：user_id 不能为 None\u0026#34;) return None if user_id \u0026lt;= 0: print(\u0026#34;错误：user_id 必须是正整数\u0026#34;) return None # 连接数据库 conn = None cursor = None try: conn = sqlite3.connect(\u0026#34;users.db\u0026#34;) cursor = conn.cursor() # 执行查询 cursor.execute(\u0026#34;SELECT id, name, email FROM users WHERE id = ?\u0026#34;, (user_id,)) row = cursor.fetchone() # 早期返回：未找到 if not row: print(f\u0026#34;未找到 id 为 {user_id} 的用户\u0026#34;) return None # 找到结果 return {\u0026#34;id\u0026#34;: row[0], \u0026#34;name\u0026#34;: row[1], \u0026#34;email\u0026#34;: row[2]} except sqlite3.Error as e: print(f\u0026#34;数据库错误: {e}\u0026#34;) return None finally: # 清理资源 if cursor: cursor.close() if conn: conn.close() 7. 条件返回与三目运算符 if-else 分支返回 def get_grade(score): \u0026#34;\u0026#34;\u0026#34;根据分数返回等级\u0026#34;\u0026#34;\u0026#34; if score \u0026gt;= 90: return \u0026#34;A\u0026#34; elif score \u0026gt;= 80: return \u0026#34;B\u0026#34; elif score \u0026gt;= 70: return \u0026#34;C\u0026#34; elif score \u0026gt;= 60: return \u0026#34;D\u0026#34; else: return \u0026#34;F\u0026#34; # 测试 print(get_grade(95)) # A print(get_grade(82)) # B print(get_grade(55)) # F 三目运算符（条件表达式） Python 的三目运算符语法：value_if_true if condition else value_if_false\n# 基本用法 age = 20 status = \u0026#34;成年\u0026#34; if age \u0026gt;= 18 else \u0026#34;未成年\u0026#34; print(status) # 输出: 成年 # 三目运算符与返回值 def get_max(a, b): return a if a \u0026gt; b else b print(get_max(10, 20)) # 输出: 20 # 嵌套三目运算符（谨慎使用） def grade(score): return \u0026#34;A\u0026#34; if score \u0026gt;= 90 else \u0026#34;B\u0026#34; if score \u0026gt;= 80 else \u0026#34;C\u0026#34; if score \u0026gt;= 70 else \u0026#34;D\u0026#34; if score \u0026gt;= 60 else \u0026#34;F\u0026#34; # 更清晰的写法 def grade_clear(score): if score \u0026gt;= 90: return \u0026#34;A\u0026#34; elif score \u0026gt;= 80: return \u0026#34;B\u0026#34; elif score \u0026gt;= 70: return \u0026#34;C\u0026#34; elif score \u0026gt;= 60: return \u0026#34;D\u0026#34; else: return \u0026#34;F\u0026#34; 返回布尔值 直接返回比较表达式的结果是常见模式：\ndef is_adult(age): \u0026#34;\u0026#34;\u0026#34;判断是否成年\u0026#34;\u0026#34;\u0026#34; return age \u0026gt;= 18 def is_even(number): \u0026#34;\u0026#34;\u0026#34;判断是否为偶数\u0026#34;\u0026#34;\u0026#34; return number % 2 == 0 def is_palindrome(text): \u0026#34;\u0026#34;\u0026#34;判断是否为回文\u0026#34;\u0026#34;\u0026#34; return text == text[::-1] # 测试 print(is_adult(20)) # True print(is_even(7)) # False print(is_palindrome(\u0026#34;上海自来水来自海上\u0026#34;)) # True 8. 生成器函数的返回值 生成器函数基础 生成器函数使用 yield 语句返回值，而不是 return。但生成器函数也可以有 return 语句。\ndef count_up_to(n): \u0026#34;\u0026#34;\u0026#34;生成器：计数到 n\u0026#34;\u0026#34;\u0026#34; count = 1 while count \u0026lt;= n: yield count count += 1 # 创建生成器对象 generator = count_up_to(5) print(generator) # 输出: \u0026lt;generator object count_up_to at 0x...\u0026gt; # 迭代获取值 for num in count_up_to(5): print(num, end=\u0026#34; \u0026#34;) # 输出: 1 2 3 4 5 生成器的 return 值 当生成器耗尽时，return 语句的值会成为 StopIteration 异常的 value 属性：\ndef fibonacci(n): \u0026#34;\u0026#34;\u0026#34;生成斐波那契数列的前 n 个数\u0026#34;\u0026#34;\u0026#34; a, b = 0, 1 for _ in range(n): yield a a, b = b, a + b return \u0026#34;生成完成\u0026#34; # 这会在 StopIteration 中 gen = fibonacci(10) try: while True: print(next(gen), end=\u0026#34; \u0026#34;) except StopIteration as e: print(f\u0026#34;\\n生成器结束: {e.value}\u0026#34;) # 输出: 0 1 1 2 3 5 8 13 21 34 # 生成器结束: 生成完成 yield from 与返回值 def chain_generators(): \u0026#34;\u0026#34;\u0026#34;yield from 会把 return 值传递出去\u0026#34;\u0026#34;\u0026#34; def gen1(): yield from [1, 2, 3] return \u0026#34;gen1 完成\u0026#34; def gen2(): yield from [4, 5, 6] return \u0026#34;gen2 完成\u0026#34; def main_gen(): result1 = yield from gen1() print(f\u0026#34; {result1}\u0026#34;) result2 = yield from gen2() print(f\u0026#34; {result2}\u0026#34;) return \u0026#34;全部完成\u0026#34; gen = main_gen() try: while True: next(gen) except StopIteration as e: print(f\u0026#34;最终返回值: {e.value}\u0026#34;) chain_generators() # 输出: # 1 2 3 # gen1 完成 # 4 5 6 # gen2 完成 # 最终返回值: 全部完成 9. lambda 表达式与返回值 lambda 的基本语法 lambda 是创建匿名函数的简洁方式，它自动包含 return 语句：\n# 普通函数 def add(a, b): return a + b # lambda 版本 add_lambda = lambda a, b: a + b # 两者等价 print(add(3, 5)) # 8 print(add_lambda(3, 5)) # 8 lambda 的 return 特性 lambda 函数体只能包含一个表达式，该表达式的值会自动返回：\n# lambda 自动返回表达式的值 square = lambda x: x ** 2 print(square(5)) # 25 # 等价于 def square_def(x): return x ** 2 # lambda 不能有赋值语句 # 下面的写法是错误的: # bad_lambda = lambda x: y = x ** 2 # SyntaxError # lambda 不能有多个表达式 # 下面的写法是错误的: # bad_lambda = lambda x: print(x); return x ** 2 # SyntaxError lambda 与条件表达式 # 使用条件表达式的 lambda abs_value = lambda x: x if x \u0026gt;= 0 else -x print(abs_value(-5)) # 5 # 嵌套 lambda max_val = lambda a, b: a if a \u0026gt; b else b min_val = lambda a, b: a if a \u0026lt; b else b # 使用场景：排序 students = [ {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;score\u0026#34;: 85}, {\u0026#34;name\u0026#34;: \u0026#34;李四\u0026#34;, \u0026#34;score\u0026#34;: 92}, {\u0026#34;name\u0026#34;: \u0026#34;王五\u0026#34;, \u0026#34;score\u0026#34;: 78} ] # 按分数降序排序 students_sorted = sorted(students, key=lambda s: s[\u0026#34;score\u0026#34;], reverse=True) for s in students_sorted: print(f\u0026#34;{s[\u0026#39;name\u0026#39;]}: {s[\u0026#39;score\u0026#39;]}\u0026#34;) lambda 与高阶函数 # map - 对每个元素应用 lambda numbers = [1, 2, 3, 4, 5] squares = list(map(lambda x: x ** 2, numbers)) print(f\u0026#34;平方: {squares}\u0026#34;) # [1, 4, 9, 16, 25] # filter - 过滤元素 evens = list(filter(lambda x: x % 2 == 0, numbers)) print(f\u0026#34;偶数: {evens}\u0026#34;) # [2, 4] # reduce - 累积计算 from functools import reduce total = reduce(lambda acc, x: acc + x, numbers, 0) print(f\u0026#34;总和: {total}\u0026#34;) # 15 # sorted 的 key 函数 words = [\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;cherry\u0026#34;, \u0026#34;date\u0026#34;] by_length = sorted(words, key=lambda w: len(w)) print(f\u0026#34;按长度排序: {by_length}\u0026#34;) # [\u0026#39;date\u0026#39;, \u0026#39;apple\u0026#39;, \u0026#39;cherry\u0026#39;, \u0026#39;banana\u0026#39;] 10. 实战练习与最佳实践 综合练习：学生成绩管理系统 \u0026#34;\u0026#34;\u0026#34; 学生成绩管理系统 - 综合练习返回值、None 和多返回值 \u0026#34;\u0026#34;\u0026#34; class Student: def __init__(self, student_id, name): self.student_id = student_id self.name = name self.scores = {} def add_score(self, subject, score): \u0026#34;\u0026#34;\u0026#34;添加科目成绩\u0026#34;\u0026#34;\u0026#34; if not isinstance(score, (int, float)): print(f\u0026#34;错误：成绩必须是数字\u0026#34;) return False if score \u0026lt; 0 or score \u0026gt; 100: print(f\u0026#34;错误：成绩必须在 0-100 之间\u0026#34;) return False self.scores[subject] = score return True def get_score(self, subject): \u0026#34;\u0026#34;\u0026#34;获取单科成绩，不存在返回 None\u0026#34;\u0026#34;\u0026#34; return self.scores.get(subject) def get_average(self): \u0026#34;\u0026#34;\u0026#34;计算平均分，无成绩时返回 None\u0026#34;\u0026#34;\u0026#34; if not self.scores: return None return sum(self.scores.values()) / len(self.scores) def get_summary(self): \u0026#34;\u0026#34;\u0026#34;返回学生成绩摘要（元组格式）\u0026#34;\u0026#34;\u0026#34; if not self.scores: return (self.student_id, self.name, None, None, 0) scores = list(self.scores.values()) return ( self.student_id, self.name, min(scores), # 最低分 max(scores), # 最高分 sum(scores) / len(scores) # 平均分 ) def calculate_class_statistics(students): \u0026#34;\u0026#34;\u0026#34;计算班级统计数据\u0026#34;\u0026#34;\u0026#34; if not students: return None all_scores = [] for student in students: all_scores.extend(student.scores.values()) if not all_scores: return None return { \u0026#34;student_count\u0026#34;: len(students), \u0026#34;total_exams\u0026#34;: len(all_scores), \u0026#34;class_average\u0026#34;: sum(all_scores) / len(all_scores), \u0026#34;highest_score\u0026#34;: max(all_scores), \u0026#34;lowest_score\u0026#34;: min(all_scores) } # 测试 if __name__ == \u0026#34;__main__\u0026#34;: # 创建学生 s1 = Student(\u0026#34;001\u0026#34;, \u0026#34;张三\u0026#34;) s2 = Student(\u0026#34;002\u0026#34;, \u0026#34;李四\u0026#34;) s3 = Student(\u0026#34;003\u0026#34;, \u0026#34;王五\u0026#34;) # 添加成绩 s1.add_score(\u0026#34;数学\u0026#34;, 95) s1.add_score(\u0026#34;语文\u0026#34;, 88) s1.add_score(\u0026#34;英语\u0026#34;, 92) s2.add_score(\u0026#34;数学\u0026#34;, 78) s2.add_score(\u0026#34;语文\u0026#34;, 85) s2.add_score(\u0026#34;英语\u0026#34;, 82) s3.add_score(\u0026#34;数学\u0026#34;, 92) s3.add_score(\u0026#34;语文\u0026#34;, 90) s3.add_score(\u0026#34;英语\u0026#34;, 88) students = [s1, s2, s3] # 打印每个学生的成绩摘要 print(\u0026#34;=\u0026#34; * 60) print(\u0026#34;学生成绩摘要\u0026#34;) print(\u0026#34;=\u0026#34; * 60) for student in students: stu_id, name, min_s, max_s, avg = student.get_summary() if avg is not None: print(f\u0026#34;{name} ({stu_id}): 最低={min_s}, 最高={max_s}, 平均={avg:.1f}\u0026#34;) else: print(f\u0026#34;{name} ({stu_id}): 暂无成绩\u0026#34;) # 打印班级统计 stats = calculate_class_statistics(students) print(\u0026#34;\\n\u0026#34; + \u0026#34;=\u0026#34; * 60) print(\u0026#34;班级统计\u0026#34;) print(\u0026#34;=\u0026#34; * 60) if stats: print(f\u0026#34;学生人数: {stats[\u0026#39;student_count\u0026#39;]}\u0026#34;) print(f\u0026#34;考试总数: {stats[\u0026#39;total_exams\u0026#39;]}\u0026#34;) print(f\u0026#34;班级平均分: {stats[\u0026#39;class_average\u0026#39;]:.1f}\u0026#34;) print(f\u0026#34;最高分: {stats[\u0026#39;highest_score\u0026#39;]}\u0026#34;) print(f\u0026#34;最低分: {stats[\u0026#39;lowest_score\u0026#39;]}\u0026#34;) 最佳实践总结 明确返回值：函数应该总是有明确的返回值，或者明确返回 None 避免返回不同类型：尽量保持函数返回类型的一致性 使用早期返回：减少嵌套，提高代码可读性 正确区分 print 和 return：print 用于调试和用户输出，return 用于返回数据 善用 None：使用 None 表示\u0026quot;没有\u0026quot;或\u0026quot;未找到\u0026quot;是 Python 的惯例 类型注解：为函数添加类型注解使代码更清晰 def find_user(users: list, user_id: int) -\u0026gt; dict | None: \u0026#34;\u0026#34;\u0026#34; 根据 ID 查找用户 Args: users: 用户列表 user_id: 要查找的用户 ID Returns: 找到返回用户字典，未找到返回 None \u0026#34;\u0026#34;\u0026#34; for user in users: if user.get(\u0026#34;id\u0026#34;) == user_id: return user return None 常见错误与避免方法 错误 后果 正确做法 忘记 return 函数返回 None 明确需要返回什么 return 后有代码 代码永不执行 return 放在最后或使用早期返回 用 == 比较 None 不好（虽然通常能工作） 使用 is None print 当 return 返回 None 使用 return value 返回可变默认值 列表/字典会被共享 使用 None 作为默认值 总结 今天我们学习了 Python 函数返回值和 None 的核心概念：\nreturn 语句：将值返回给调用者，同时终止函数执行 None 类型：表示\u0026quot;空\u0026quot;或\u0026quot;无值\u0026quot;，是 NoneType 的唯一实例 多返回值：通过返回元组实现，可以用元组解包接收 return vs print：前者返回数据，后者仅输出到控制台 早期返回：减少嵌套，提高代码可读性 生成器返回值：使用 return 指定迭代结束的值 lambda 表达式：自动返回表达式结果 掌握这些概念对于编写高质量的 Python 代码至关重要。在实际开发中，要养成明确返回值、使用早期返回、正确处理 None 的好习惯。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-11-function-return/","summary":"\u003ch1 id=\"python-第十一天函数返回值与-none\"\u003ePython 第十一天：函数返回值与 None\u003c/h1\u003e\n\u003ch2 id=\"目录\"\u003e目录\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\u003ca href=\"#1-%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%E5%80%BC%E5%9F%BA%E7%A1%80\"\u003e函数返回值基础\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#2-return-%E8%AF%AD%E5%8F%A5%E8%AF%A6%E8%A7%A3\"\u003ereturn 语句详解\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#3-none-%E7%9A%84%E6%9C%AC%E8%B4%A8%E4%B8%8E%E5%BA%94%E7%94%A8\"\u003eNone 的本质与应用\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#4-%E5%A4%9A%E8%BF%94%E5%9B%9E%E5%80%BC%E4%B8%8E%E5%85%83%E7%BB%84%E8%A7%A3%E5%8C%85\"\u003e多返回值与元组解包\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#5-return-%E4%B8%8E-print-%E7%9A%84%E5%8C%BA%E5%88%AB\"\u003ereturn 与 print 的区别\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#6-%E6%97%A9%E6%9C%9F%E8%BF%94%E5%9B%9Eearly-return%E6%A8%A1%E5%BC%8F\"\u003e早期返回（Early Return）模式\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#7-%E6%9D%A1%E4%BB%B6%E8%BF%94%E5%9B%9E%E4%B8%8E%E4%B8%89%E7%9B%AE%E8%BF%90%E7%AE%97%E7%AC%A6\"\u003e条件返回与三目运算符\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#8-%E7%94%9F%E6%88%90%E5%99%A8%E5%87%BD%E6%95%B0%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC\"\u003e生成器函数的返回值\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#9-lambda-%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%8E%E8%BF%94%E5%9B%9E%E5%80%BC\"\u003elambda 表达式与返回值\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#10-%E5%AE%9E%E6%88%98%E7%BB%83%E4%B9%A0%E4%B8%8E%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5\"\u003e实战练习与最佳实践\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-函数返回值基础\"\u003e1. 函数返回值基础\u003c/h2\u003e\n\u003ch3 id=\"什么是返回值\"\u003e什么是返回值\u003c/h3\u003e\n\u003cp\u003e返回值是函数执行完毕后向调用者提供的结果数据。在 Python 中，使用 \u003ccode\u003ereturn\u003c/code\u003e 语句来指定函数的返回值。当一个函数没有 return 语句，或者 return 语句后面没有任何表达式时，函数默认返回 \u003ccode\u003eNone\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 最简单的返回值示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egreet\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;你好，世界！\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e greet()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# 输出: 你好，世界！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"返回值的基本类型\"\u003e返回值的基本类型\u003c/h3\u003e\n\u003cp\u003ePython 函数可以返回各种类型的数据，包括但不限于：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e字符串\u003c/strong\u003e：返回文本信息\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e数字\u003c/strong\u003e：返回计算结果\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e布尔值\u003c/strong\u003e：返回判断结果\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e列表/元组/字典\u003c/strong\u003e：返回集合数据\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e对象\u003c/strong\u003e：返回自定义类的实例\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNone\u003c/strong\u003e：表示空或无返回值\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 返回不同类型的示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ereturn_types_demo\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Hello\u0026#34;\u003c/span\u003e           \u003cspan style=\"color:#75715e\"\u003e# 字符串\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e42\u003c/span\u003e                 \u003cspan style=\"color:#75715e\"\u003e# 数字\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e]          \u003cspan style=\"color:#75715e\"\u003e# 列表\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e {\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Alice\u0026#34;\u003c/span\u003e}  \u003cspan style=\"color:#75715e\"\u003e# 字典\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e               \u003cspan style=\"color:#75715e\"\u003e# 布尔值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e               \u003cspan style=\"color:#75715e\"\u003e# None 值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e注意\u003c/strong\u003e：函数一旦执行到 \u003ccode\u003ereturn\u003c/code\u003e 语句就会立即结束，后面的代码不会执行。上面的例子中，只有第一个 return 会生效。\u003c/p\u003e","tags":"Python, 编程","title":"Python 第十一天：函数返回值与 None"},{"columns":"acp-course","content":"Day11 负载均衡SLB 一、详细讲解 1.1 负载均衡概述 负载均衡（Load Balancing）是将访问流量根据转发策略分发到多台后端服务器的技术，通过消除单点故障、提升应用系统的吞吐能力和可用性。\n负载均衡发展背景 互联网初期：单机部署即可满足需求 业务增长期：访问量增加导致服务器延迟或宕机 集群方案：多台服务器组成集群，通过负载均衡设备统一分发 负载均衡分类 类别 特点 DNS负载均衡 通过DNS服务器配置多个A记录实现 二层负载均衡(MAC) 基于MAC地址分发，对应OSI第二层 三层负载均衡(IP) 基于IP分发，对应OSI网络层 四层负载均衡(TCP/UDP) 基于IP+端口分发，高效率 七层负载均衡(HTTP) 基于URL、语言等应用层信息，灵活 最常用的是四层和七层负载均衡。\n负载均衡算法 静态算法（不考虑服务器状态）：\n轮询法（RR）：轮流分配请求 加权轮询（WRR）：按权重分配 随机法：随机分配 Hash类：基于关键字Hash分配 动态算法（考虑服务器实时负载）：\n最小连接法（LC）：分配给连接数最少的服务器 加权最小连接法（WLC）：综合权重和连接数 1.2 阿里云负载均衡SLB产品家族 阿里云SLB包含三种负载均衡产品：\n产品 定位 性能 ALB（应用型负载均衡） 七层，HTTP/HTTPS/QUIC 单实例最大100万QPS NLB（网络型负载均衡） 四层，TCP/UDP/TCPSSL 单实例最大1亿并发 CLB（传统型负载均衡） 四层+七层，TCP/UDP/HTTP/HTTPS 100万并发、5万QPS ALB特点 强大七层处理能力与高级路由功能 基于内容的路由、重写、重定向、限速 云原生Ingress网关支持 适用场景：互联网应用七层高性能、音视频、IoT、云原生金丝雀发布 NLB特点 新一代四层负载均衡 超高性能（1亿并发）、自动弹性 支持TCPSSL卸载 适用场景：四层大流量高并发、物联网、车联网 CLB特点 基于物理机架构 四层：LVS + keepalived 七层：Tengine集群 适用场景：网站四层流量分发、同城灾备 1.3 CLB核心概念 实例类型 公网CLB：自动分配公网IP，用于互联网访问 私网CLB：通过私网IP对外提供服务 实例规格 性能共享型：资源共享，不保障性能 性能保障型：可保障性能指标 高可用架构 单实例高可用：支持多可用区，跨机房容灾 多实例高可用：通过云解析DNS调度或全球负载均衡 两地三中心：同城双活 + 异地容灾 会话保持 四层：同一IP持续发往同一服务器 七层：相同Cookie发往同一服务器 健康检查 判断后端ECS业务可用性 TCP健康检查：发送SYN报文 HTTP健康检查：发送HEAD/GET请求，检查2xx状态码 异常服务器自动移除流量 SSL证书管理 证书统一管理在SLB，解密在SLB上进行 降低后端ECS的CPU开销 日志管理 操作日志：ActionTrail集成 健康检查日志：三天内，可存OSS 访问日志：存储SLS日志库 1.4 SLB操作配置流程 准备工作：规划地域、VPC、ECS实例 创建实例：选择网络类型、VPC、可用区、IP模式 创建后端服务器组：添加ECS/ECI/ENI或IP 配置监听：配置协议、端口、转发规则 设置域名解析：CNAME解析到SLB域名 监听配置要点 协议选择：HTTP/HTTPS/QUIC/TCP/UDP 端口配置 转发规则（ALB支持丰富规则） 健康检查配置 HTTP重定向至HTTPS 创建HTTPS监听（443端口） 创建HTTP监听（80端口） 开启监听转发，选择目的HTTPS监听 1.5 SLB最佳实践场景 场景 特点 推荐搭配 公网流量入口 ECS无公网IP，提高可用性 弹性公网IP、NAT网关 音视频/游戏大流量 突发访问、海量流量、QUIC支持 全球加速GA、共享带宽 零售/金融弹性高可靠 弹性伸缩、即开即用 云企业网CEN 云原生应用 ACK/ASK/SAE集成 容器服务ACK、云数据库RDS 跨地域容灾 多地域用户智能调度 云企业网CEN 二、背诵版 2.1 负载均衡基础 负载均衡将流量分发到多台后端服务器，消除单点故障，提升可用性 四层负载均衡：基于IP+端口（TCP/UDP），效率高 七层负载均衡：基于应用层信息（HTTP/URL），灵活 静态算法：轮询、加权轮询、随机、Hash 动态算法：最小连接法、加权最小连接法 2.2 阿里云SLB产品家族 产品 层次 协议 性能指标 ALB 七层 HTTP/HTTPS/QUIC 100万QPS NLB 四层 TCP/UDP/TCPSSL 1亿并发 CLB 四层+七层 TCP/UDP/HTTP/HTTPS 100万并发/5万QPS 2.3 CLB核心要点 CLB四层：LVS + keepalived；七层：Tengine集群 公网CLB自动分配公网IP；私网CLB使用私网IP 性能保障型可保障性能指标 会话保持：四层基于IP，七层基于Cookie 健康检查：探测后端ECS可用性，异常自动移除 SSL证书在SLB解密，减轻后端ECS压力 支持HTTPS重定向（HTTP→HTTPS） 2.4 SLB操作流程 创建实例 → 创建后端服务器组 → 配置监听 → 设置域名解析\n2.5 典型应用场景 公网流量入口（高可用架构） 音视频/游戏大流量（QUIC协议、自动弹性） 零售/金融弹性高可靠（即开即用） 云原生Ingress网关 跨地域容灾（多可用区、多地域） 三、速记版 3.1 负载均衡分类速记 负载均衡分类： DNS → 二层MAC → 三层IP → 四层IP\u0026#43;Port → 七层HTTP （越来越灵活，效率略有下降）3.2 SLB三兄弟速记 ALB：七层应用（HTTP/HTTPS/QUIC）→ 100万QPS NLB：四层网络（TCP/UDP）→ 1亿并发 CLB：四层\u0026#43;七层 → 100万并发/5万QPS3.3 CLB架构速记 四层：LVS \u0026#43; keepalived 七层：Tengine集群 公网：自动分配公网IP 私网：私网IP，灵活绑定EIP3.4 健康检查速记 TCP：SYN → SYN\u0026#43;ACK HTTP：HEAD/GET → 2xx状态码 异常：流量不再转发至该服务器3.5 调度算法速记 静态（不看状态）：轮询、加权轮询、随机、Hash 动态（看状态）：最小连接、加权最小连接 四、测试题 4.1 单选题 阿里云SLB产品中，专门面向七层、支持QUIC协议的是？\nA. CLB B. NLB C. ALB D. SLB 答案：C 解析：ALB（应用型负载均衡）专门面向七层，支持HTTP/HTTPS/QUIC协议。\nCLB四层负载均衡的后端架构是？\nA. Tengine集群 B. Nginx集群 C. LVS + keepalived D. HAProxy集群 答案：C 解析：CLB四层使用LVS + keepalived，七层使用Tengine集群。\n以下哪种不属于静态负载均衡算法？\nA. 轮询法 B. 加权轮询 C. 随机法 D. 最小连接法 答案：D 解析：最小连接法是动态算法，考虑服务器当前连接数。\nALB实例单实例最大QPS是？\nA. 100万 B. 5000 C. 1亿 D. 10万 答案：A 解析：ALB单实例最大支持100万QPS，NLB最大1亿并发连接。\nHTTP监听重定向至HTTPS需要配置什么功能？\nA. 健康检查 B. 会话保持 C. 监听转发 D. 虚拟服务器组 答案：C 解析：通过开启监听转发功能，将HTTP请求转发至HTTPS监听。\n4.2 多选题 阿里云SLB产品家族包含哪些？\nA. ALB B. NLB C. CLB D. GLB 答案：ABC 解析：阿里云SLB包含ALB（应用型）、NLB（网络型）、CLB（传统型）。\n以下哪些是七层负载均衡的特点？\nA. 基于IP+端口分发 B. 基于URL或应用层信息分发 C. 灵活性高 D. 效率高于四层 答案：BC 解析：七层基于应用层信息（A错误），四层效率更高（D错误）。\nSLB健康检查支持哪些协议？\nA. TCP B. UDP C. HTTP D. HTTPS 答案：AC 解析：健康检查支持TCP和HTTP协议，UDP健康检查不常用。\n会话保持的实现方式包括？\nA. 四层：同一IP发往同一服务器 B. 七层：相同Cookie发往同一服务器 C. 四层：相同端口发往同一服务器 D. 七层：相同URL发往同一服务器 答案：AB 解析：四层基于源IP，七层基于Cookie。\n创建SLB的操作流程包括？\nA. 创建实例 B. 创建后端服务器组 C. 配置监听 D. 配置域名解析 答案：ABCD 解析：标准流程为：准备工作→创建实例→创建后端服务器组→配置监听→设置域名解析。\n4.3 判断题 SLB和后端ECS之间通过内网通信，无需额外配置即可访问外网。\n答案：错误 解析：SLB和ECS之间是内网通信，如需ECS访问外网需要配置公网IP、NAT网关等。 NLB单实例最大支持1亿并发连接。\n答案：正确 解析：NLB面向万物互联，单实例可达1亿并发连接和100 Gbps带宽。 CLB主备服务器组只支持四层监听（TCP/UDP）。\n答案：正确 解析：主备服务器组特性决定只支持四层监听。 性能共享型实例可以保障性能指标。\n答案：错误 解析：性能共享型资源共享，不保障性能；性能保障型才可保障性能指标。 ALB支持将HTTP请求重定向至HTTPS。\n答案：正确 解析：ALB支持通过监听转发功能实现HTTP到HTTPS的重定向。 学习提示：\n理解四层与七层负载均衡的区别与适用场景 掌握ALB/NLB/CLB三种产品的定位与性能指标 熟悉CLB的组成（实例、监听、后端服务器组） 了解健康检查、会话保持、SSL证书等核心功能 ","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-11-acp-day-11-%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1slb/","summary":"\u003ch1 id=\"day11-负载均衡slb\"\u003eDay11 负载均衡SLB\u003c/h1\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-负载均衡概述\"\u003e1.1 负载均衡概述\u003c/h3\u003e\n\u003cp\u003e负载均衡（Load Balancing）是将访问流量根据转发策略分发到多台后端服务器的技术，通过消除单点故障、提升应用系统的吞吐能力和可用性。\u003c/p\u003e\n\u003ch4 id=\"负载均衡发展背景\"\u003e负载均衡发展背景\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e互联网初期\u003c/strong\u003e：单机部署即可满足需求\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e业务增长期\u003c/strong\u003e：访问量增加导致服务器延迟或宕机\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e集群方案\u003c/strong\u003e：多台服务器组成集群，通过负载均衡设备统一分发\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"负载均衡分类\"\u003e负载均衡分类\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e类别\u003c/th\u003e\n          \u003cth\u003e特点\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDNS负载均衡\u003c/td\u003e\n          \u003ctd\u003e通过DNS服务器配置多个A记录实现\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e二层负载均衡(MAC)\u003c/td\u003e\n          \u003ctd\u003e基于MAC地址分发，对应OSI第二层\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e三层负载均衡(IP)\u003c/td\u003e\n          \u003ctd\u003e基于IP分发，对应OSI网络层\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e四层负载均衡(TCP/UDP)\u003c/td\u003e\n          \u003ctd\u003e基于IP+端口分发，高效率\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e七层负载均衡(HTTP)\u003c/td\u003e\n          \u003ctd\u003e基于URL、语言等应用层信息，灵活\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e最常用的是\u003cstrong\u003e四层\u003c/strong\u003e和\u003cstrong\u003e七层\u003c/strong\u003e负载均衡。\u003c/p\u003e\n\u003ch4 id=\"负载均衡算法\"\u003e负载均衡算法\u003c/h4\u003e\n\u003cp\u003e\u003cstrong\u003e静态算法\u003c/strong\u003e（不考虑服务器状态）：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e轮询法（RR）：轮流分配请求\u003c/li\u003e\n\u003cli\u003e加权轮询（WRR）：按权重分配\u003c/li\u003e\n\u003cli\u003e随机法：随机分配\u003c/li\u003e\n\u003cli\u003eHash类：基于关键字Hash分配\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e动态算法\u003c/strong\u003e（考虑服务器实时负载）：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e最小连接法（LC）：分配给连接数最少的服务器\u003c/li\u003e\n\u003cli\u003e加权最小连接法（WLC）：综合权重和连接数\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"12-阿里云负载均衡slb产品家族\"\u003e1.2 阿里云负载均衡SLB产品家族\u003c/h3\u003e\n\u003cp\u003e阿里云SLB包含三种负载均衡产品：\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e产品\u003c/th\u003e\n          \u003cth\u003e定位\u003c/th\u003e\n          \u003cth\u003e性能\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eALB\u003c/strong\u003e（应用型负载均衡）\u003c/td\u003e\n          \u003ctd\u003e七层，HTTP/HTTPS/QUIC\u003c/td\u003e\n          \u003ctd\u003e单实例最大100万QPS\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eNLB\u003c/strong\u003e（网络型负载均衡）\u003c/td\u003e\n          \u003ctd\u003e四层，TCP/UDP/TCPSSL\u003c/td\u003e\n          \u003ctd\u003e单实例最大1亿并发\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eCLB\u003c/strong\u003e（传统型负载均衡）\u003c/td\u003e\n          \u003ctd\u003e四层+七层，TCP/UDP/HTTP/HTTPS\u003c/td\u003e\n          \u003ctd\u003e100万并发、5万QPS\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"alb特点\"\u003eALB特点\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e强大七层处理能力与高级路由功能\u003c/li\u003e\n\u003cli\u003e基于内容的路由、重写、重定向、限速\u003c/li\u003e\n\u003cli\u003e云原生Ingress网关支持\u003c/li\u003e\n\u003cli\u003e适用场景：互联网应用七层高性能、音视频、IoT、云原生金丝雀发布\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"nlb特点\"\u003eNLB特点\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e新一代四层负载均衡\u003c/li\u003e\n\u003cli\u003e超高性能（1亿并发）、自动弹性\u003c/li\u003e\n\u003cli\u003e支持TCPSSL卸载\u003c/li\u003e\n\u003cli\u003e适用场景：四层大流量高并发、物联网、车联网\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"clb特点\"\u003eCLB特点\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e基于物理机架构\u003c/li\u003e\n\u003cli\u003e四层：LVS + keepalived\u003c/li\u003e\n\u003cli\u003e七层：Tengine集群\u003c/li\u003e\n\u003cli\u003e适用场景：网站四层流量分发、同城灾备\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"13-clb核心概念\"\u003e1.3 CLB核心概念\u003c/h3\u003e\n\u003ch4 id=\"实例类型\"\u003e实例类型\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e公网CLB\u003c/strong\u003e：自动分配公网IP，用于互联网访问\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e私网CLB\u003c/strong\u003e：通过私网IP对外提供服务\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"实例规格\"\u003e实例规格\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e性能共享型\u003c/strong\u003e：资源共享，不保障性能\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e性能保障型\u003c/strong\u003e：可保障性能指标\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"高可用架构\"\u003e高可用架构\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e单实例高可用\u003c/strong\u003e：支持多可用区，跨机房容灾\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e多实例高可用\u003c/strong\u003e：通过云解析DNS调度或全球负载均衡\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e两地三中心\u003c/strong\u003e：同城双活 + 异地容灾\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"会话保持\"\u003e会话保持\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e四层\u003c/strong\u003e：同一IP持续发往同一服务器\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e七层\u003c/strong\u003e：相同Cookie发往同一服务器\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"健康检查\"\u003e健康检查\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e判断后端ECS业务可用性\u003c/li\u003e\n\u003cli\u003eTCP健康检查：发送SYN报文\u003c/li\u003e\n\u003cli\u003eHTTP健康检查：发送HEAD/GET请求，检查2xx状态码\u003c/li\u003e\n\u003cli\u003e异常服务器自动移除流量\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"ssl证书管理\"\u003eSSL证书管理\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e证书统一管理在SLB，解密在SLB上进行\u003c/li\u003e\n\u003cli\u003e降低后端ECS的CPU开销\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"日志管理\"\u003e日志管理\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e操作日志\u003c/strong\u003e：ActionTrail集成\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e健康检查日志\u003c/strong\u003e：三天内，可存OSS\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e访问日志\u003c/strong\u003e：存储SLS日志库\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"14-slb操作配置流程\"\u003e1.4 SLB操作配置流程\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e准备工作\u003c/strong\u003e：规划地域、VPC、ECS实例\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e创建实例\u003c/strong\u003e：选择网络类型、VPC、可用区、IP模式\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e创建后端服务器组\u003c/strong\u003e：添加ECS/ECI/ENI或IP\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e配置监听\u003c/strong\u003e：配置协议、端口、转发规则\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e设置域名解析\u003c/strong\u003e：CNAME解析到SLB域名\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"监听配置要点\"\u003e监听配置要点\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e协议选择：HTTP/HTTPS/QUIC/TCP/UDP\u003c/li\u003e\n\u003cli\u003e端口配置\u003c/li\u003e\n\u003cli\u003e转发规则（ALB支持丰富规则）\u003c/li\u003e\n\u003cli\u003e健康检查配置\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"http重定向至https\"\u003eHTTP重定向至HTTPS\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e创建HTTPS监听（443端口）\u003c/li\u003e\n\u003cli\u003e创建HTTP监听（80端口）\u003c/li\u003e\n\u003cli\u003e开启监听转发，选择目的HTTPS监听\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch3 id=\"15-slb最佳实践场景\"\u003e1.5 SLB最佳实践场景\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e场景\u003c/th\u003e\n          \u003cth\u003e特点\u003c/th\u003e\n          \u003cth\u003e推荐搭配\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e公网流量入口\u003c/td\u003e\n          \u003ctd\u003eECS无公网IP，提高可用性\u003c/td\u003e\n          \u003ctd\u003e弹性公网IP、NAT网关\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e音视频/游戏大流量\u003c/td\u003e\n          \u003ctd\u003e突发访问、海量流量、QUIC支持\u003c/td\u003e\n          \u003ctd\u003e全球加速GA、共享带宽\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e零售/金融弹性高可靠\u003c/td\u003e\n          \u003ctd\u003e弹性伸缩、即开即用\u003c/td\u003e\n          \u003ctd\u003e云企业网CEN\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e云原生应用\u003c/td\u003e\n          \u003ctd\u003eACK/ASK/SAE集成\u003c/td\u003e\n          \u003ctd\u003e容器服务ACK、云数据库RDS\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e跨地域容灾\u003c/td\u003e\n          \u003ctd\u003e多地域用户智能调度\u003c/td\u003e\n          \u003ctd\u003e云企业网CEN\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch2 id=\"二背诵版\"\u003e二、背诵版\u003c/h2\u003e\n\u003ch3 id=\"21-负载均衡基础\"\u003e2.1 负载均衡基础\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e负载均衡将流量分发到多台后端服务器，消除单点故障，提升可用性\u003c/li\u003e\n\u003cli\u003e四层负载均衡：基于IP+端口（TCP/UDP），效率高\u003c/li\u003e\n\u003cli\u003e七层负载均衡：基于应用层信息（HTTP/URL），灵活\u003c/li\u003e\n\u003cli\u003e静态算法：轮询、加权轮询、随机、Hash\u003c/li\u003e\n\u003cli\u003e动态算法：最小连接法、加权最小连接法\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"22-阿里云slb产品家族\"\u003e2.2 阿里云SLB产品家族\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e产品\u003c/th\u003e\n          \u003cth\u003e层次\u003c/th\u003e\n          \u003cth\u003e协议\u003c/th\u003e\n          \u003cth\u003e性能指标\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eALB\u003c/td\u003e\n          \u003ctd\u003e七层\u003c/td\u003e\n          \u003ctd\u003eHTTP/HTTPS/QUIC\u003c/td\u003e\n          \u003ctd\u003e100万QPS\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eNLB\u003c/td\u003e\n          \u003ctd\u003e四层\u003c/td\u003e\n          \u003ctd\u003eTCP/UDP/TCPSSL\u003c/td\u003e\n          \u003ctd\u003e1亿并发\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCLB\u003c/td\u003e\n          \u003ctd\u003e四层+七层\u003c/td\u003e\n          \u003ctd\u003eTCP/UDP/HTTP/HTTPS\u003c/td\u003e\n          \u003ctd\u003e100万并发/5万QPS\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"23-clb核心要点\"\u003e2.3 CLB核心要点\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eCLB四层：LVS + keepalived；七层：Tengine集群\u003c/li\u003e\n\u003cli\u003e公网CLB自动分配公网IP；私网CLB使用私网IP\u003c/li\u003e\n\u003cli\u003e性能保障型可保障性能指标\u003c/li\u003e\n\u003cli\u003e会话保持：四层基于IP，七层基于Cookie\u003c/li\u003e\n\u003cli\u003e健康检查：探测后端ECS可用性，异常自动移除\u003c/li\u003e\n\u003cli\u003eSSL证书在SLB解密，减轻后端ECS压力\u003c/li\u003e\n\u003cli\u003e支持HTTPS重定向（HTTP→HTTPS）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"24-slb操作流程\"\u003e2.4 SLB操作流程\u003c/h3\u003e\n\u003cp\u003e创建实例 → 创建后端服务器组 → 配置监听 → 设置域名解析\u003c/p\u003e","tags":"ACP, 阿里云, SLB","title":"Day11 负载均衡SLB"},{"columns":"python-course","content":"Python 第十二天：*args、**kwargs 与默认参数 目录 函数参数基础回顾 默认参数详解 *args 可变位置参数 **kwargs 可变关键字参数 参数组合使用 参数解包与拆包 深入理解 * 的作用 强制关键字参数 参数注解与类型提示 实战练习 1. 函数参数基础回顾 位置参数 位置参数是最基本的参数类型，必须按照定义顺序传递：\ndef greet(name, age, city): \u0026#34;\u0026#34;\u0026#34;三个位置参数\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;我是{name}，今年{age}岁，来自{city}\u0026#34; # 必须按顺序传递 print(greet(\u0026#34;张三\u0026#34;, 25, \u0026#34;北京\u0026#34;)) # 输出: 我是张三，今年25岁，来自北京 # 错误示例：顺序不对 print(greet(\u0026#34;北京\u0026#34;, \u0026#34;张三\u0026#34;, 25)) # 结果可能不符合预期 关键字参数 使用参数名传递，可以不按顺序：\ndef greet(name, age, city): return f\u0026#34;我是{name}，今年{age}岁，来自{city}\u0026#34; # 使用关键字参数，顺序可以任意 print(greet(age=25, city=\u0026#34;北京\u0026#34;, name=\u0026#34;张三\u0026#34;)) # 输出: 我是张三，今年25岁，来自北京 # 混合使用：位置参数在前，关键字参数在后 print(greet(\u0026#34;张三\u0026#34;, city=\u0026#34;北京\u0026#34;, age=25)) # 输出: 我是张三，今年25岁，来自北京 2. 默认参数详解 基本语法 在函数定义时给参数指定默认值，使其成为可选参数：\ndef greet(name, greeting=\u0026#34;你好\u0026#34;, punctuation=\u0026#34;!\u0026#34;): \u0026#34;\u0026#34;\u0026#34;默认参数示例\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;{greeting}，{name}{punctuation}\u0026#34; # 使用默认 greeting 和 punctuation print(greet(\u0026#34;张三\u0026#34;)) # 你好，张三! print(greet(\u0026#34;李四\u0026#34;, \u0026#34;早上好\u0026#34;)) # 早上好，李四! print(greet(\u0026#34;王五\u0026#34;, \u0026#34;晚上好\u0026#34;, \u0026#34;。\u0026#34;)) # 晚上好，王五。 默认参数的重要性 # 没有默认参数：每次都要提供所有参数 def connect_db(host, port, user, password, database): \u0026#34;\u0026#34;\u0026#34;连接数据库（无默认参数）\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;连接 {host}:{port}/{database} 用户={user}\u0026#34; # 必须提供所有参数 conn1 = connect_db(\u0026#34;localhost\u0026#34;, 3306, \u0026#34;root\u0026#34;, \u0026#34;123456\u0026#34;, \u0026#34;mydb\u0026#34;) # 有默认参数：简化调用 def connect_db_default(host, port=3306, user=\u0026#34;root\u0026#34;, password=\u0026#34;\u0026#34;, database=\u0026#34;test\u0026#34;): \u0026#34;\u0026#34;\u0026#34;连接数据库（带默认参数）\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;连接 {host}:{port}/{database} 用户={user}\u0026#34; # 使用默认值 conn2 = connect_db_default(\u0026#34;localhost\u0026#34;) conn3 = connect_db_default(\u0026#34;localhost\u0026#34;, user=\u0026#34;admin\u0026#34;) conn4 = connect_db_default(\u0026#34;localhost\u0026#34;, database=\u0026#34;production\u0026#34;) 默认参数的常见陷阱 陷阱1：使用可变对象作为默认值 这是 Python 中最常见的错误之一！\n# 错误示例：可变默认值被共享 def add_item_bad(item, items=[]): # 永远不要这样做！ items.append(item) return items # 每次调用共享同一个列表 print(add_item_bad(\u0026#34;apple\u0026#34;)) # [\u0026#39;apple\u0026#39;] print(add_item_bad(\u0026#34;banana\u0026#34;)) # [\u0026#39;apple\u0026#39;, \u0026#39;banana\u0026#39;] print(add_item_bad(\u0026#34;cherry\u0026#34;)) # [\u0026#39;apple\u0026#39;, \u0026#39;banana\u0026#39;, \u0026#39;cherry\u0026#39;] # 正确示例：使用 None 作为默认值 def add_item_good(item, items=None): # 正确做法 if items is None: items = [] items.append(item) return items # 每次调用创建新列表 print(add_item_good(\u0026#34;apple\u0026#34;)) # [\u0026#39;apple\u0026#39;] print(add_item_good(\u0026#34;banana\u0026#34;)) # [\u0026#39;banana\u0026#39;] print(add_item_good(\u0026#34;cherry\u0026#34;)) # [\u0026#39;cherry\u0026#39;] 陷阱2：默认参数在函数定义时求值 import datetime # 错误示例：时间在函数定义时固定 def log_bad(msg, when=datetime.datetime.now()): return f\u0026#34;{when}: {msg}\u0026#34; # 多次调用会得到相同的时间 print(log_bad(\u0026#34;第一次\u0026#34;)) # 假设输出: 2024-01-01 10:00:00.123456: 第一次 print(log_bad(\u0026#34;第二次\u0026#34;)) # 输出: 2024-01-01 10:00:00.123456: 第二次（时间相同！） # 正确示例：使用 None 并在函数内判断 def log_good(msg, when=None): if when is None: when = datetime.datetime.now() return f\u0026#34;{when}: {msg}\u0026#34; # 每次调用得到当前时间 print(log_good(\u0026#34;第一次\u0026#34;)) print(log_good(\u0026#34;第二次\u0026#34;)) 默认参数的最佳实践 # 最佳实践1：使用不可变类型作为默认值 def func1(path, mode=\u0026#34;r\u0026#34;): \u0026#34;\u0026#34;\u0026#34;字符串是不可变类型，可以安全使用\u0026#34;\u0026#34;\u0026#34; pass # 最佳实践2：使用 None 作为可变默认值的默认值 def func2(data=None): if data is None: data = [] data.append(1) return data # 最佳实践3：对于需要保持状态的函数，显式传递 def process_items(initial_items): \u0026#34;\u0026#34;\u0026#34;显式传递初始列表\u0026#34;\u0026#34;\u0026#34; items = initial_items.copy() # 创建副本 items.append(\u0026#34;new\u0026#34;) return items my_items = [\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;] result = process_items(my_items) print(my_items) # [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;] - 原列表未被修改 3. *args 可变位置参数 基本语法 *args 允许函数接受任意数量的位置参数，这些参数被收集到一个元组中：\ndef sum_all(*args): \u0026#34;\u0026#34;\u0026#34;求和函数，接受任意数量的参数\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;接收到的参数类型: {type(args)}\u0026#34;) print(f\u0026#34;参数内容: {args}\u0026#34;) return sum(args) # 调用方式 print(sum_all(1, 2, 3)) # 6 print(sum_all(1, 2, 3, 4, 5)) # 15 print(sum_all()) # 0 *args 的工作原理 def debug_args(*args): \u0026#34;\u0026#34;\u0026#34;展示 args 的本质\u0026#34;\u0026#34;\u0026#34; print(\u0026#34;=\u0026#34; * 40) print(f\u0026#34;参数个数: {len(args)}\u0026#34;) for i, arg in enumerate(args): print(f\u0026#34; 参数{i}: {arg} (类型: {type(arg).__name__})\u0026#34;) debug_args(1, \u0026#34;hello\u0026#34;, 3.14, True, [1, 2, 3]) # 输出: # ======================================== # 参数个数: 5 # 参数0: 1 (类型: int) # 参数1: hello (类型: str) # 参数2: 3.14 (类型: float) # 参数3: True (类型: bool) # 参数4: [1, 2, 3] (类型: list) 使用 *args 实现灵活函数 # 示例1：计算任意数字的算术平均 def arithmetic_mean(*numbers): \u0026#34;\u0026#34;\u0026#34;计算算术平均数\u0026#34;\u0026#34;\u0026#34; if not numbers: return None return sum(numbers) / len(numbers) print(arithmetic_mean(10, 20, 30)) # 20.0 print(arithmetic_mean(5, 10, 15, 20, 25)) # 15.0 # 示例2：找出最大值 def find_max(*numbers): \u0026#34;\u0026#34;\u0026#34;找出一组数的最大值\u0026#34;\u0026#34;\u0026#34; if not numbers: return None max_val = numbers[0] for num in numbers[1:]: if num \u0026gt; max_val: max_val = num return max_val print(find_max(3, 7, 2, 9, 1)) # 9 # 示例3：字符串连接 def join_strings(*strings, separator=\u0026#34; \u0026#34;): \u0026#34;\u0026#34;\u0026#34;用分隔符连接字符串\u0026#34;\u0026#34;\u0026#34; return separator.join(strings) print(join_strings(\u0026#34;Hello\u0026#34;, \u0026#34;World\u0026#34;, \u0026#34;Python\u0026#34;)) print(join_strings(\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;cherry\u0026#34;, separator=\u0026#34;, \u0026#34;)) *args 与普通参数组合 def func(prefix, *args, suffix=\u0026#34;!\u0026#34;): \u0026#34;\u0026#34;\u0026#34;前缀 + 可变参数 + 后缀\u0026#34;\u0026#34;\u0026#34; result = prefix for arg in args: result += str(arg) result += suffix return result print(func(\u0026#34;数字:\u0026#34;, 1, 2, 3, 4, 5)) # 数字:12345! print(func(\u0026#34;单词:\u0026#34;, \u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;, suffix=\u0026#34;?\u0026#34;)) # 单词:abc? 4. **kwargs 可变关键字参数 基本语法 **kwargs 允许函数接受任意数量的关键字参数，这些参数被收集到一个字典中：\ndef print_info(**kwargs): \u0026#34;\u0026#34;\u0026#34;打印所有关键字参数\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;接收到的参数类型: {type(kwargs)}\u0026#34;) print(f\u0026#34;参数内容: {kwargs}\u0026#34;) for key, value in kwargs.items(): print(f\u0026#34; {key} = {value}\u0026#34;) # 调用方式 print_info(name=\u0026#34;张三\u0026#34;, age=25, city=\u0026#34;北京\u0026#34;) print_info(a=1, b=2, c=3) **kwargs 的工作原理 def debug_kwargs(**kwargs): \u0026#34;\u0026#34;\u0026#34;展示 kwargs 的本质\u0026#34;\u0026#34;\u0026#34; print(\u0026#34;=\u0026#34; * 40) print(f\u0026#34;参数个数: {len(kwargs)}\u0026#34;) for key, value in kwargs.items(): print(f\u0026#34; {key}: {value} (类型: {type(value).__name__})\u0026#34;) debug_kwargs(name=\u0026#34;Alice\u0026#34;, score=95, is_active=True, hobbies=[\u0026#34;reading\u0026#34;, \u0026#34;coding\u0026#34;]) # 输出: # ======================================== # 参数个数: 4 # name: Alice (类型: str) # score: 95 (类型: int) # is_active: True (类型: bool) # hobbies: [\u0026#39;reading\u0026#39;, \u0026#39;coding\u0026#39;] (类型: list) 使用 **kwargs 实现灵活配置 # 示例1：创建用户配置 def create_user(name, **profile): \u0026#34;\u0026#34;\u0026#34;创建用户，可选添加任意配置项\u0026#34;\u0026#34;\u0026#34; user = {\u0026#34;name\u0026#34;: name} user.update(profile) return user user1 = create_user(\u0026#34;张三\u0026#34;, age=25, city=\u0026#34;北京\u0026#34;, profession=\u0026#34;工程师\u0026#34;) user2 = create_user(\u0026#34;李四\u0026#34;, email=\u0026#34;li@example.com\u0026#34;, phone=\u0026#34;1234567890\u0026#34;) print(user1) print(user2) # 示例2：格式化日志消息 def log(level, message, **options): \u0026#34;\u0026#34;\u0026#34;日志函数，支持自定义格式\u0026#34;\u0026#34;\u0026#34; timestamp = options.get(\u0026#34;timestamp\u0026#34;, \u0026#34;2024-01-01 12:00:00\u0026#34;) prefix = options.get(\u0026#34;prefix\u0026#34;, \u0026#34;\u0026#34;) full_message = f\u0026#34;[{timestamp}] [{level}]\u0026#34; if prefix: full_message += f\u0026#34; [{prefix}]\u0026#34; full_message += f\u0026#34; {message}\u0026#34; return full_message print(log(\u0026#34;INFO\u0026#34;, \u0026#34;服务启动成功\u0026#34;)) print(log(\u0026#34;ERROR\u0026#34;, \u0026#34;连接失败\u0026#34;, timestamp=\u0026#34;2024-06-15 10:30:00\u0026#34;, prefix=\u0026#34;DB\u0026#34;)) **kwargs 与普通参数组合 def func(required_arg, *args, **kwargs): \u0026#34;\u0026#34;\u0026#34;参数组合示例\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;必需参数: {required_arg}\u0026#34;) if args: print(f\u0026#34;位置参数组: {args}\u0026#34;) if kwargs: print(f\u0026#34;关键字参数组: {kwargs}\u0026#34;) func(\u0026#34;test\u0026#34;) # 必需参数: test func(\u0026#34;test\u0026#34;, 1, 2, 3) # 必需参数: test, 位置参数组: (1, 2, 3) func(\u0026#34;test\u0026#34;, 1, 2, 3, name=\u0026#34;Alice\u0026#34;, age=25) # 全部参数 5. 参数组合使用 完整参数顺序 Python 函数参数的标准顺序：\ndef func(positional_only, /, positional_or_keyword, *args, keyword_only, **kwargs): positional_only: 仅位置参数（/ 之前） positional_or_keyword: 位置或关键字参数 *args: 可变位置参数 keyword_only: 仅关键字参数 **kwargs: 可变关键字参数 def complete_example(pos_only, /, standard, *args, kw_only, **kwargs): \u0026#34;\u0026#34;\u0026#34; 完整参数示例 - pos_only: 只能用位置传递 - standard: 位置或关键字传递 - args: 收集额外位置参数 - kw_only: 必须用关键字传递 - kwargs: 收集额外关键字参数 \u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;pos_only: {pos_only}\u0026#34;) print(f\u0026#34;standard: {standard}\u0026#34;) print(f\u0026#34;args: {args}\u0026#34;) print(f\u0026#34;kw_only: {kw_only}\u0026#34;) print(f\u0026#34;kwargs: {kwargs}\u0026#34;) # 调用 complete_example(1, 2, 3, 4, kw_only=5, extra=\u0026#34;value\u0026#34;) # 输出: # pos_only: 1 # standard: 2 # args: (3, 4) # kw_only: 5 # kwargs: {\u0026#39;extra\u0026#39;: \u0026#39;value\u0026#39;} 常见组合模式 # 模式1：*args + **kwargs（最灵活） def flexible(*args, **kwargs): print(f\u0026#34;args: {args}\u0026#34;) print(f\u0026#34;kwargs: {kwargs}\u0026#34;) flexible(1, 2, 3, name=\u0026#34;test\u0026#34;, value=100) # 模式2：默认参数 + *args + **kwargs def with_defaults(a, b=10, *args, **kwargs): print(f\u0026#34;a={a}, b={b}\u0026#34;) print(f\u0026#34;args={args}\u0026#34;) print(f\u0026#34;kwargs={kwargs}\u0026#34;) with_defaults(1, 2, 3, 4, x=10, y=20) # a=1, b=2, args=(3, 4), kwargs={\u0026#39;x\u0026#39;: 10, \u0026#39;y\u0026#39;: 20} # 模式3：默认值 + *args def func3(a, b=20, *args): print(f\u0026#34;a={a}, b={b}, args={args}\u0026#34;) func3(1) # a=1, b=20, args=() func3(1, 2) # a=1, b=2, args=() func3(1, 2, 3) # a=1, b=2, args=(3,) 实际应用示例 class Calculator: \u0026#34;\u0026#34;\u0026#34;计算器类，演示参数组合\u0026#34;\u0026#34;\u0026#34; def calculate(self, operation, *numbers, precision=2, **options): \u0026#34;\u0026#34;\u0026#34;执行计算操作\u0026#34;\u0026#34;\u0026#34; self._validate_numbers(*numbers) if operation == \u0026#34;sum\u0026#34;: result = sum(numbers) elif operation == \u0026#34;avg\u0026#34;: result = sum(numbers) / len(numbers) if numbers else 0 elif operation == \u0026#34;max\u0026#34;: result = max(numbers) if numbers else None elif operation == \u0026#34;min\u0026#34;: result = min(numbers) if numbers else None else: raise ValueError(f\u0026#34;未知操作: {operation}\u0026#34;) # 应用选项 if options.get(\u0026#34;round\u0026#34;, True): result = round(result, precision) if options.get(\u0026#34;negative\u0026#34;): result = -result return result def _validate_numbers(self, *numbers): \u0026#34;\u0026#34;\u0026#34;验证输入\u0026#34;\u0026#34;\u0026#34; for num in numbers: if not isinstance(num, (int, float)): raise TypeError(f\u0026#34;所有参数必须是数字，得到: {type(num)}\u0026#34;) # 使用 calc = Calculator() print(calc.calculate(\u0026#34;sum\u0026#34;, 1, 2, 3, 4, 5)) # 15 print(calc.calculate(\u0026#34;avg\u0026#34;, 10, 20, 30)) # 20.0 print(calc.calculate(\u0026#34;max\u0026#34;, 3, 7, 2, 9, 1)) # 9 print(calc.calculate(\u0026#34;avg\u0026#34;, 1, 2, 3, precision=1)) # 2.0 print(calc.calculate(\u0026#34;sum\u0026#34;, 1, 2, 3, negative=True)) # -6 6. 参数解包与拆包 在函数调用时使用 * 将列表或元组拆包为位置参数：\ndef add(a, b, c): \u0026#34;\u0026#34;\u0026#34;三个参数求和\u0026#34;\u0026#34;\u0026#34; return a + b + c # 普通调用 print(add(1, 2, 3)) # 6 # 使用 * 解包 numbers = [1, 2, 3] print(add(*numbers)) # 6 # 解包与直接传参混用 print(add(*[1, 2], 3)) # 6 在函数调用时使用 ** 将字典拆包为关键字参数：\ndef create_user(name, age, city): \u0026#34;\u0026#34;\u0026#34;创建用户\u0026#34;\u0026#34;\u0026#34; return {\u0026#34;name\u0026#34;: name, \u0026#34;age\u0026#34;: age, \u0026#34;city\u0026#34;: city} # 普通调用 print(create_user(\u0026#34;张三\u0026#34;, 25, \u0026#34;北京\u0026#34;)) # 使用 ** 解包字典 config = {\u0026#34;name\u0026#34;: \u0026#34;李四\u0026#34;, \u0026#34;age\u0026#34;: 30, \u0026#34;city\u0026#34;: \u0026#34;上海\u0026#34;} print(create_user(**config)) # 部分解包 print(create_user(\u0026#34;王五\u0026#34;, **{\u0026#34;age\u0026#34;: 28, \u0026#34;city\u0026#34;: \u0026#34;广州\u0026#34;})) 在函数定义时使用 *（强制收集） def func(*args): \u0026#34;\u0026#34;\u0026#34;收集所有位置参数\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;收集到: {args}\u0026#34;) # 调用时解包 func(*[1, 2, 3]) # 收集到: (1, 2, 3) func(*[1, 2, 3], *[4, 5]) # 收集到: (1, 2, 3, 4, 5) 在函数定义时使用 **（强制收集） def func(**kwargs): \u0026#34;\u0026#34;\u0026#34;收集所有关键字参数\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;收集到: {kwargs}\u0026#34;) # 调用时解包 func(**{\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2}) # 收集到: {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 2} func(**{\u0026#34;x\u0026#34;: 10}, **{\u0026#34;y\u0026#34;: 20}) # 收集到: {\u0026#39;x\u0026#39;: 10, \u0026#39;y\u0026#39;: 20} 综合示例 def configure(title, width=800, height=600, **options): \u0026#34;\u0026#34;\u0026#34;配置窗口\u0026#34;\u0026#34;\u0026#34; config = { \u0026#34;title\u0026#34;: title, \u0026#34;width\u0026#34;: width, \u0026#34;height\u0026#34;: height } config.update(options) return config # 各种调用方式 print(configure(\u0026#34;主窗口\u0026#34;)) # 基本调用 print(configure(\u0026#34;设置\u0026#34;, 1024, 768)) # 指定宽高 print(configure(\u0026#34;游戏\u0026#34;, height=1080, fullscreen=True, vsync=False)) # 关键字参数 print(configure(**{\u0026#34;title\u0026#34;: \u0026#34;对话框\u0026#34;, \u0026#34;width\u0026#34;: 600})) # 字典解包 7. 深入理解 * 的作用 * 的两个角色 # 角色1：在函数定义时 - 收集参数 def collect(*args): \u0026#34;\u0026#34;\u0026#34;收集位置参数\u0026#34;\u0026#34;\u0026#34; print(args) # 角色2：在函数调用时 - 展开参数 def show(a, b, c): print(f\u0026#34;a={a}, b={b}, c={c}\u0026#34;) numbers = [1, 2, 3] show(*numbers) # a=1, b=2, c=3 * 用在赋值中 # 解包赋值 a, *b, c = [1, 2, 3, 4, 5] print(f\u0026#34;a={a}, b={b}, c={c}\u0026#34;) # a=1, b=[2, 3, 4], c=5 # 忽略不需要的值 head, *_, tail = [1, 2, 3, 4, 5] print(f\u0026#34;head={head}, tail={tail}\u0026#34;) # head=1, tail=5 ** 的两个角色 # 角色1：在函数定义时 - 收集关键字参数 def collect(**kwargs): print(kwargs) # 角色2：在函数调用时 - 展开字典 def show(name, age): print(f\u0026#34;name={name}, age={age}\u0026#34;) info = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25} show(**info) # name=张三, age=25 组合使用的完整示例 def demo(pos1, pos2, /, standard, *args, kw_only, **kwargs): \u0026#34;\u0026#34;\u0026#34;完整演示\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;pos1={pos1}, pos2={pos2}\u0026#34;) print(f\u0026#34;standard={standard}\u0026#34;) print(f\u0026#34;args={args}\u0026#34;) print(f\u0026#34;kw_only={kw_only}\u0026#34;) print(f\u0026#34;kwargs={kwargs}\u0026#34;) # 各种调用方式 print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;方式1: 基本调用\u0026#34;) demo(1, 2, 3, kw_only=4) print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;方式2: 使用 * 解包\u0026#34;) demo(*[1, 2], 3, kw_only=4, **{\u0026#34;extra\u0026#34;: 5}) print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;方式3: 使用 ** 解包\u0026#34;) demo(1, 2, standard=3, kw_only=4, extra1=5, extra2=6) 8. 强制关键字参数 Python 3 的仅关键字参数 在 * 之后定义的参数必须使用关键字传递：\ndef func(a, b, *, c, d): \u0026#34;\u0026#34;\u0026#34; a, b: 可以用位置或关键字传递 c, d: 必须用关键字传递 \u0026#34;\u0026#34;\u0026#34; return f\u0026#34;a={a}, b={b}, c={c}, d={d}\u0026#34; # 正确调用 print(func(1, 2, c=3, d=4)) # 错误调用 - c, d 不能用位置传递 # print(func(1, 2, 3, 4)) # TypeError 仅关键字参数的应用场景 # 场景1：防止参数顺序混淆 def create_user(name, /, *, age, email): \u0026#34;\u0026#34;\u0026#34; name: 仅位置（用户名） age, email: 仅关键字（必须指定参数名） \u0026#34;\u0026#34;\u0026#34; return {\u0026#34;name\u0026#34;: name, \u0026#34;age\u0026#34;: age, \u0026#34;email\u0026#34;: email} # name 可以直接传，其他必须用关键字 print(create_user(\u0026#34;张三\u0026#34;, age=25, email=\u0026#34;zhang@example.com\u0026#34;)) print(create_user(\u0026#34;李四\u0026#34;, email=\u0026#34;li@example.com\u0026#34;, age=30)) # 场景2：增强代码可读性 def send_message(message, /, *, to, from_address, subject=\u0026#34;\u0026#34;, priority=\u0026#34;normal\u0026#34;): \u0026#34;\u0026#34;\u0026#34; 强制使用关键字参数，代码更清晰 \u0026#34;\u0026#34;\u0026#34; return { \u0026#34;message\u0026#34;: message, \u0026#34;to\u0026#34;: to, \u0026#34;from\u0026#34;: from_address, \u0026#34;subject\u0026#34;: subject, \u0026#34;priority\u0026#34;: priority } msg = send_message(\u0026#34;你好\u0026#34;, to=\u0026#34;user@example.com\u0026#34;, from_address=\u0026#34;system@company.com\u0026#34;) / 和 * 的组合使用 def complex_func( pos_only, # 位置限定: 必须用位置传参 /, # 斜杠：左边仅位置 pos_or_kw, # 普通参数: 位置或关键字 *, # 星号：右边仅关键字 kw_only # 关键字限定: 必须用关键字传参 ): return f\u0026#34;{pos_only}, {pos_or_kw}, {kw_only}\u0026#34; # 测试 print(complex_func(1, 2, kw_only=3)) # 正确 # print(complex_func(1, pos_or_kw=2, kw_only=3)) # 错误: pos_or_kw 不能用关键字 # print(complex_func(pos_only=1, 2, kw_only=3)) # 错误: pos_only 必须用位置 9. 参数注解与类型提示 基本类型注解 def greet(name: str, age: int) -\u0026gt; str: \u0026#34;\u0026#34;\u0026#34;带类型注解的函数\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;你好，{name}！你 {age} 岁了。\u0026#34; print(greet(\u0026#34;张三\u0026#34;, 25)) *args 和 **kwargs 的类型注解 from typing import Tuple, Dict, Any def func(*args: int, **kwargs: str) -\u0026gt; Tuple[tuple, dict]: \u0026#34;\u0026#34;\u0026#34;带类型的 *args 和 **kwargs\u0026#34;\u0026#34;\u0026#34; return args, kwargs # 调用 result = func(1, 2, 3, name=\u0026#34;Alice\u0026#34;, city=\u0026#34;Beijing\u0026#34;) print(result) # ((1, 2, 3), {\u0026#39;name\u0026#39;: \u0026#39;Alice\u0026#39;, \u0026#39;city\u0026#39;: \u0026#39;Beijing\u0026#39;}) Optional 和 Union 类型 from typing import Optional, Union, List def process( data: List[int], multiplier: Optional[float] = None, **options: Union[str, int] ) -\u0026gt; Dict[str, Any]: \u0026#34;\u0026#34;\u0026#34;复杂类型注解示例\u0026#34;\u0026#34;\u0026#34; result = sum(data) if multiplier is not None: result *= multiplier return { \u0026#34;sum\u0026#34;: result, \u0026#34;count\u0026#34;: len(data), \u0026#34;options\u0026#34;: options } print(process([1, 2, 3], multiplier=2.0, name=\u0026#34;test\u0026#34;)) TypedDict（Python 3.8+） from typing import TypedDict, List class UserProfile(TypedDict): name: str age: int email: str hobbies: List[str] def create_profile(**kwargs: str) -\u0026gt; UserProfile: \u0026#34;\u0026#34;\u0026#34;TypedDict 用法\u0026#34;\u0026#34;\u0026#34; profile = UserProfile( name=kwargs.get(\u0026#34;name\u0026#34;, \u0026#34;\u0026#34;), age=int(kwargs.get(\u0026#34;age\u0026#34;, 0)), email=kwargs.get(\u0026#34;email\u0026#34;, \u0026#34;\u0026#34;), hobbies=kwargs.get(\u0026#34;hobbies\u0026#34;, []) ) return profile 10. 实战练习 练习1：通用格式化函数 def format_table( *columns, delimiter: str = \u0026#34; | \u0026#34;, header: bool = True, align: str = \u0026#34;left\u0026#34;, padding: int = 1 ) -\u0026gt; str: \u0026#34;\u0026#34;\u0026#34; 将多个列表格式化为表格字符串 Args: *columns: 任意数量的列表，每个列表作为一列 delimiter: 列分隔符 header: 是否显示列标题 align: 对齐方式 (\u0026#39;left\u0026#39;, \u0026#39;right\u0026#39;, \u0026#39;center\u0026#39;) padding: 单元格内边距 Returns: 格式化的表格字符串 \u0026#34;\u0026#34;\u0026#34; if not columns: return \u0026#34;\u0026#34; # 获取每列的最大宽度 num_rows = max(len(col) for col in columns) col_widths = [] for col in columns: col_widths.append(max(len(str(item)) for item in col) if col else 0) # 构建表格 rows = [] padding_str = \u0026#34; \u0026#34; * padding def format_cell(content, width): content = str(content) pad = padding_str if align == \u0026#34;left\u0026#34;: return f\u0026#34;{pad}{content:\u0026lt;{width}}{pad}\u0026#34; elif align == \u0026#34;right\u0026#34;: return f\u0026#34;{pad}{content:\u0026gt;{width}}{pad}\u0026#34; else: # center return f\u0026#34;{pad}{content:^{width}}{pad}\u0026#34; # 添加表头行 if header: header_row = delimiter.join( format_cell(f\u0026#34;列{i+1}\u0026#34;, col_widths[i]) for i in range(len(columns)) ) rows.append(header_row) # 分隔线 separator = delimiter.join(\u0026#34;-\u0026#34; * (w + 2 * padding) for w in col_widths) rows.append(separator) # 添加数据行 for row_idx in range(num_rows): row_values = [] for col_idx, col in enumerate(columns): value = col[row_idx] if row_idx \u0026lt; len(col) else \u0026#34;\u0026#34; row_values.append(format_cell(value, col_widths[col_idx])) rows.append(delimiter.join(row_values)) return \u0026#34;\\n\u0026#34;.join(rows) # 测试 names = [\u0026#34;Alice\u0026#34;, \u0026#34;Bob\u0026#34;, \u0026#34;Charlie\u0026#34;, \u0026#34;David\u0026#34;] ages = [25, 30, 35, 28] cities = [\u0026#34;Beijing\u0026#34;, \u0026#34;Shanghai\u0026#34;, \u0026#34;Guangzhou\u0026#34;, \u0026#34;Shenzhen\u0026#34;] print(format_table(names, ages, cities)) print(\u0026#34;\\n\u0026#34; + \u0026#34;=\u0026#34; * 50 + \u0026#34;\\n\u0026#34;) print(format_table(names, ages, cities, header=False)) print(\u0026#34;\\n\u0026#34; + \u0026#34;=\u0026#34; * 50 + \u0026#34;\\n\u0026#34;) print(format_table(names, ages, cities, align=\u0026#34;right\u0026#34;, padding=2)) 练习2：函数装饰器（使用 *args, **kwargs） from functools import wraps from typing import Callable, Any import time def timing(func: Callable) -\u0026gt; Callable: \u0026#34;\u0026#34;\u0026#34;测量函数执行时间的装饰器\u0026#34;\u0026#34;\u0026#34; @wraps(func) def wrapper(*args, **kwargs) -\u0026gt; Any: start = time.perf_counter() result = func(*args, **kwargs) end = time.perf_counter() print(f\u0026#34;函数 {func.__name__} 执行时间: {end - start:.4f} 秒\u0026#34;) return result return wrapper def validate_args(**validators): \u0026#34;\u0026#34;\u0026#34;验证参数类型的装饰器工厂\u0026#34;\u0026#34;\u0026#34; def decorator(func: Callable) -\u0026gt; Callable: @wraps(func) def wrapper(*args, **kwargs): # 获取函数签名 import inspect sig = inspect.signature(func) bound = sig.bind(*args, **kwargs) bound.apply_defaults() # 验证参数 for name, validator in validators.items(): if name in bound.arguments: value = bound.arguments[name] if not validator(value): raise ValueError(f\u0026#34;参数 {name}={value} 验证失败\u0026#34;) return func(*args, **kwargs) return wrapper return decorator @timing @validate_args(age=lambda x: 0 \u0026lt; x \u0026lt; 150, name=lambda x: isinstance(x, str) and len(x) \u0026gt; 0) def create_person(name: str, age: int, city: str = \u0026#34;北京\u0026#34;) -\u0026gt; dict: \u0026#34;\u0026#34;\u0026#34;创建人物信息\u0026#34;\u0026#34;\u0026#34; return {\u0026#34;name\u0026#34;: name, \u0026#34;age\u0026#34;: age, \u0026#34;city\u0026#34;: city} # 测试 print(create_person(\u0026#34;张三\u0026#34;, 25)) print(create_person(\u0026#34;李四\u0026#34;, age=30)) # create_person(\u0026#34;\u0026#34;, 25) # 会抛出异常 # create_person(\u0026#34;王五\u0026#34;, 200) # 会抛出异常 练习3：链式函数调用 class QueryBuilder: \u0026#34;\u0026#34;\u0026#34;SQL 查询构建器，演示参数传递\u0026#34;\u0026#34;\u0026#34; def __init__(self, table: str): self.table = table self._fields = [\u0026#34;*\u0026#34;] self._conditions = [] self._order_by = None self._limit_val = None def select(self, *fields: str) -\u0026gt; \u0026#34;QueryBuilder\u0026#34;: \u0026#34;\u0026#34;\u0026#34;选择字段\u0026#34;\u0026#34;\u0026#34; if fields: self._fields = list(fields) return self def where(self, condition: str, *params) -\u0026gt; \u0026#34;QueryBuilder\u0026#34;: \u0026#34;\u0026#34;\u0026#34;添加 WHERE 条件\u0026#34;\u0026#34;\u0026#34; self._conditions.append((condition, params)) return self def order_by(self, field: str, direction: str = \u0026#34;ASC\u0026#34;) -\u0026gt; \u0026#34;QueryBuilder\u0026#34;: \u0026#34;\u0026#34;\u0026#34;排序\u0026#34;\u0026#34;\u0026#34; self._order_by = (field, direction.upper()) return self def limit(self, count: int, offset: int = 0) -\u0026gt; \u0026#34;QueryBuilder\u0026#34;: \u0026#34;\u0026#34;\u0026#34;限制结果数\u0026#34;\u0026#34;\u0026#34; self._limit_val = (count, offset) return self def build(self) -\u0026gt; tuple: \u0026#34;\u0026#34;\u0026#34;构建 SQL 和参数\u0026#34;\u0026#34;\u0026#34; # SELECT sql = f\u0026#34;SELECT {\u0026#39;, \u0026#39;.join(self._fields)} FROM {self.table}\u0026#34; # WHERE params = [] if self._conditions: where_parts = [] for cond, cond_params in self._conditions: where_parts.append(cond) params.extend(cond_params) sql += \u0026#34; WHERE \u0026#34; + \u0026#34; AND \u0026#34;.join(where_parts) # ORDER BY if self._order_by: sql += f\u0026#34; ORDER BY {self._order_by[0]} {self._order_by[1]}\u0026#34; # LIMIT if self._limit_val: sql += f\u0026#34; LIMIT ? OFFSET ?\u0026#34; params.extend(self._limit_val) return sql, tuple(params) def __repr__(self): sql, params = self.build() return f\u0026#34;SQL: {sql}\\nParams: {params}\u0026#34; # 使用 query = ( QueryBuilder(\u0026#34;users\u0026#34;) .select(\u0026#34;id\u0026#34;, \u0026#34;name\u0026#34;, \u0026#34;email\u0026#34;) .where(\u0026#34;age \u0026gt; ?\u0026#34;, 18) .where(\u0026#34;city = ?\u0026#34;, \u0026#34;北京\u0026#34;) .order_by(\u0026#34;name\u0026#34;, \u0026#34;ASC\u0026#34;) .limit(10, 0) ) print(query) 总结 今天我们深入学习了 Python 函数参数的高级特性：\n默认参数：为参数提供默认值，但避免使用可变对象作为默认值 *args：收集任意数量的位置参数为元组 **kwargs：收集任意数量的关键字参数为字典 参数组合：多种参数类型可以组合使用，有固定顺序 解包与拆包：使用 * 和 ** 在调用时展开参数 仅关键字参数：使用 * 分隔符强制某些参数必须用关键字传递 类型注解：使用 : type 和 -\u0026gt; type 提供类型提示 掌握这些知识可以编写出更加灵活和强大的 Python 函数。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-12-args-kwargs/","summary":"\u003ch1 id=\"python-第十二天argskwargs-与默认参数\"\u003ePython 第十二天：*args、**kwargs 与默认参数\u003c/h1\u003e\n\u003ch2 id=\"目录\"\u003e目录\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\u003ca href=\"#1-%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%E5%9F%BA%E7%A1%80%E5%9B%9E%E9%A1%BE\"\u003e函数参数基础回顾\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#2-%E9%BB%98%E8%AE%A4%E5%8F%82%E6%95%B0%E8%AF%A6%E8%A7%A3\"\u003e默认参数详解\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#3-args-%E5%8F%AF%E5%8F%98%E4%BD%8D%E7%BD%AE%E5%8F%82%E6%95%B0\"\u003e*args 可变位置参数\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#4-kwargs-%E5%8F%AF%E5%8F%98%E5%85%B3%E9%94%AE%E5%AD%97%E5%8F%82%E6%95%B0\"\u003e**kwargs 可变关键字参数\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#5-%E5%8F%82%E6%95%B0%E7%BB%84%E5%90%88%E4%BD%BF%E7%94%A8\"\u003e参数组合使用\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#6-%E5%8F%82%E6%95%B0%E8%A7%A3%E5%8C%85%E4%B8%8E%E6%8B%86%E5%8C%85\"\u003e参数解包与拆包\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#7-%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3--%E7%9A%84%E4%BD%9C%E7%94%A8\"\u003e深入理解 * 的作用\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#8-%E5%BC%BA%E5%88%B6%E5%85%B3%E9%94%AE%E5%AD%97%E5%8F%82%E6%95%B0\"\u003e强制关键字参数\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#9-%E5%8F%82%E6%95%B0%E6%B3%A8%E8%A7%A3%E4%B8%8E%E7%B1%BB%E5%9E%8B%E6%8F%90%E7%A4%BA\"\u003e参数注解与类型提示\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#10-%E5%AE%9E%E6%88%98%E7%BB%83%E4%B9%A0\"\u003e实战练习\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-函数参数基础回顾\"\u003e1. 函数参数基础回顾\u003c/h2\u003e\n\u003ch3 id=\"位置参数\"\u003e位置参数\u003c/h3\u003e\n\u003cp\u003e位置参数是最基本的参数类型，必须按照定义顺序传递：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egreet\u003c/span\u003e(name, age, city):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;三个位置参数\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;我是\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e，今年\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eage\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e岁，来自\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecity\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 必须按顺序传递\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(greet(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e25\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;北京\u0026#34;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 输出: 我是张三，今年25岁，来自北京\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 错误示例：顺序不对\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(greet(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;北京\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e25\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 结果可能不符合预期\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"关键字参数\"\u003e关键字参数\u003c/h3\u003e\n\u003cp\u003e使用参数名传递，可以不按顺序：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egreet\u003c/span\u003e(name, age, city):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;我是\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e，今年\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eage\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e岁，来自\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecity\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用关键字参数，顺序可以任意\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(greet(age\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e25\u003c/span\u003e, city\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;北京\u0026#34;\u003c/span\u003e, name\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 输出: 我是张三，今年25岁，来自北京\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 混合使用：位置参数在前，关键字参数在后\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(greet(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e, city\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;北京\u0026#34;\u003c/span\u003e, age\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e25\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 输出: 我是张三，今年25岁，来自北京\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"2-默认参数详解\"\u003e2. 默认参数详解\u003c/h2\u003e\n\u003ch3 id=\"基本语法\"\u003e基本语法\u003c/h3\u003e\n\u003cp\u003e在函数定义时给参数指定默认值，使其成为可选参数：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egreet\u003c/span\u003e(name, greeting\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;你好\u0026#34;\u003c/span\u003e, punctuation\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;!\u0026#34;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;默认参数示例\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003egreeting\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e，\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}{\u003c/span\u003epunctuation\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用默认 greeting 和 punctuation\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(greet(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e))              \u003cspan style=\"color:#75715e\"\u003e# 你好，张三!\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(greet(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;李四\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;早上好\u0026#34;\u003c/span\u003e))    \u003cspan style=\"color:#75715e\"\u003e# 早上好，李四!\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(greet(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;王五\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;晚上好\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;。\u0026#34;\u003c/span\u003e)) \u003cspan style=\"color:#75715e\"\u003e# 晚上好，王五。\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"默认参数的重要性\"\u003e默认参数的重要性\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 没有默认参数：每次都要提供所有参数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003econnect_db\u003c/span\u003e(host, port, user, password, database):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;连接数据库（无默认参数）\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;连接 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ehost\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eport\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edatabase\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 用户=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003euser\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 必须提供所有参数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003econn1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e connect_db(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;localhost\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3306\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;root\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;123456\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;mydb\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 有默认参数：简化调用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003econnect_db_default\u003c/span\u003e(host, port\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e3306\u003c/span\u003e, user\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;root\u0026#34;\u003c/span\u003e, password\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e, database\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;test\u0026#34;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;连接数据库（带默认参数）\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;连接 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ehost\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eport\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edatabase\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 用户=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003euser\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用默认值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003econn2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e connect_db_default(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;localhost\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003econn3 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e connect_db_default(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;localhost\u0026#34;\u003c/span\u003e, user\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;admin\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003econn4 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e connect_db_default(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;localhost\u0026#34;\u003c/span\u003e, database\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;production\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"默认参数的常见陷阱\"\u003e默认参数的常见陷阱\u003c/h3\u003e\n\u003ch4 id=\"陷阱1使用可变对象作为默认值\"\u003e陷阱1：使用可变对象作为默认值\u003c/h4\u003e\n\u003cp\u003e\u003cstrong\u003e这是 Python 中最常见的错误之一！\u003c/strong\u003e\u003c/p\u003e","tags":"Python, 编程","title":"Python 第十二天：*args、**kwargs 与默认参数"},{"columns":"acp-course","content":"Day 12：云数据库Redis 本文基于阿里云ACP云计算工程师认证课程内容整理，涵盖Redis非关系型数据库核心知识、云数据库Redis架构选型、操作配置及性能优化最佳实践。\n一、非关系型数据库与Redis核心原理 什么是非关系型数据库（NoSQL） NoSQL（Not Only SQL） 泛指非关系型数据库，区别于传统关系数据库不保证ACID特性，核心优势在于：\n易扩展：无固定表结构，数据模型灵活 大数据量、高性能：支持TB级数据存储，高并发读写 灵活的数据模型：键值、列存储、文档、图形多种类型 高可用：副本集、分片集群自动故障切换 Redis核心特性 Redis（Remote Dictionary Server） 是开源的ANSI C语言编写的内存数据库，支持网络、可基于内存或持久化运行：\n特性 说明 持久化 周期性地将内存更新写入磁盘，重启可恢复 数据结构丰富 支持String、List、Set、ZSet、Hash等 主从备份 Master-Slave模式数据复制 原子操作 所有操作原子性，支持事务合并执行 发布/订阅 支持消息通知、Key过期等高级特性 Redis vs 其他数据库 MySQL/PostgreSQL（关系型）→ 复杂查询、事务强一致性 MongoDB（文档型）→ JSON文档存储、半结构化数据 Redis（键值型）→ 高性能缓存、Session存储、实时计算Redis典型使用场景：缓存层加速 在大并发场景下，直接访问数据库会造成IO压力过大：\n用户请求 → 应用服务器 → Redis缓存（先访问） ↓ 未命中 数据库服务器Redis基于内存存储，QPS可达10万以上，远超MySQL等磁盘数据库，是应对高并发访问的核心武器。\n考试要点：Redis不仅支持简单的Key-Value，还提供List、Set、ZSet、Hash等复杂数据结构。Redis操作是原子性的，支持事务。\n二、云数据库Redis架构选型指南 阿里云Redis产品家族 阿里云提供社区版Redis和企业版Tair两大产品线：\n版本 简介 适用场景 社区版 兼容开源Redis协议 小型网站、开发测试、个人学习 企业版Tair 阿里集团自研，增强性能 企业级缓存、高性能并发、低延迟场景 Tair企业版三大存储形态 类型 核心技术 适用场景 性能增强型 多线程模型，性能≈社区版3倍 高性能、低延迟要求 持久内存型 掉电数据不丢失，成本降低30% 温冷数据存储、兼顾性能与成本 容量存储型 基于ESSD，大容量低成本 大容量、低访问频率数据 部署架构选型 标准版-双副本（Master-Replica） 主节点提供日常访问，备节点提供HA高可用 主节点故障后30秒内自动切换到备节点 适用：Redis协议兼容性要求高、作为持久化数据存储、单节点性能压力可控 标准版-单副本 单节点部署，无备用节点 提供数据持久化和备份机制 价格优势明显，适合纯缓存业务 集群版-双副本 代理（Proxy）模式，一个统一连接地址访问集群 数据分片横向扩展，每个分片双副本高可用 适用：数据量大、QPS高、吞吐密集型场景 读写分离版 主备节点 + 只读节点 + 代理节点 链式复制架构，只读节点扩展使整体性能线性增长 适用：读多写少、读取QPS压力大的场景 容灾方案三级对比 灾备级别 架构 说明 ★★★☆☆ 单可用区双副本 主备部署在不同机器，同一可用区 ★★★★☆ 双可用区高可用 主备分属同一地域两个可用区，单AZ故障自动切换 ★★★★★ 全球多活分布式 多子实例跨地域同步，支持异地灾备、就近访问 考试要点：标准版-双副本的主备自动切换时间约为30秒。集群版采用代理模式，通过统一域名访问。读写分离版只读节点采用链式复制架构。\n三、云数据库Redis操作配置实战 Redis使用全流程 规格选型 → 创建Redis实例 → 设置白名单 → 连接Redis实例 → 管理Redis实例规格选型关键决策点 决策项 选项 考量因素 存储介质 云盘版 vs 本地盘 云盘版支持存储弹性扩容 版本 社区版 vs 企业版 企业版性能更强、功能更丰富 架构 标准/集群/读写分离 根据QPS和数据量选择 容灾 单AZ/多AZ/全球多活 业务连续性要求 大版本 Redis 5.0/6.0/7.0 兼容性需求 创建Redis实例配置项 地域与可用区：选择靠近应用服务器的地域 网络类型：专有网络（推荐），需指定VPC和交换机 版本类型：社区版4.0/5.0/6.0；企业版Tair 架构类型：单副本/双副本；标准/集群/读写分离 规格：根据预估内存需求选择 密码：需设置强密码 白名单设置 白名单是Redis安全的第一道防线，两种设置方式：\n方式 适用场景 手动添加IP 固定IP的客户端，精确控制 绑定ECS安全组 多个ECS实例授权，快速便捷 注意：默认白名单为127.0.0.1（拒绝所有外部访问），必须添加客户端IP或绑定安全组才能连接。\n连接Redis实例 redis-cli连接方式 # 基本连接 redis-cli -h \u0026lt;hostname\u0026gt; -p 6379 # 集群模式连接 redis-cli -h \u0026lt;hostname\u0026gt; -p 6379 -c # 认证 AUTH \u0026lt;username\u0026gt; \u0026lt;password\u0026gt; 连接地址类型 地址类型 说明 需要手动申请 内网连接地址 VPC内访问，默认提供 否 直连地址 专有网络连接 是 公网连接地址 互联网访问 是 Linux下编译安装Redis客户端 # 安装编译环境 yum install -y gcc-c++ yum -y install centos-release-scl yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils scl enable devtoolset-9 bash # 编译安装Redis wget https://download.redis.io/releases/redis-6.0.9.tar.gz tar xzf redis-6.0.9.tar.gz cd redis-6.0.9 \u0026amp;\u0026amp; make \u0026amp;\u0026amp; make install 四、Redis性能优化与最佳实践 性能边界与常见瓶颈 三大资源消耗源 资源 消耗源 影响 计算资源 通配符、Lua并发、PUBSUB、热点Key 访问倾斜，无法利用所有分片 存储资源 Stream慢消费、大Key 数据倾斜，分片利用不均 网络资源 KEYS命令、大Value、HGETALL全量读取 线程阻塞，响应延迟上升 CPU使用率高的排查 当平均CPU使用率\u0026gt;50% 或 **连续5分钟峰值\u0026gt;90%**时需及时排查：\n开启审计日志分析高消耗命令 检查是否存在热点Key导致处理倾斜 评估是否需要扩容或升级规格 内存使用率高的排查 当**内存使用率\u0026gt;95%**时需要关注：\n查询历史累计逐出的Key总数 分析命令最大时延 判断是否存在大Key或内存泄漏 热点Key问题解决：Proxy Query Cache 针对热点Key发起大量读请求导致的访问倾斜，阿里云Redis提供代理查询缓存功能：\n代理节点缓存热点Key的请求和查询结果 有效时间内相同请求直接返回，无需与后端数据分片交互 大幅降低访问倾斜，提升集群整体吞吐量 典型应用场景搭配 场景一：网站缓存（单节点Redis + RDS） 推荐搭配：ECS \u0026#43; RDS MySQL \u0026#43; Redis \u0026#43; SLB 解决问题：高读写性能、高可用、高性价比 适用：纯缓存类业务，读多写少场景二：视频直播（Redis集群版） 推荐搭配：ECS \u0026#43; RDS MySQL \u0026#43; Redis集群版 \u0026#43; SLB 解决问题：流量突发、QPS百万级、低延迟 适用：视频点播、直播、秒杀场景ACP认证核心知识点速查 Redis数据类型：String、List、Set、ZSet、Hash 持久化机制：RDB（周期快照）+ AOF（追加日志） 主从复制：Master-Slave模式，支持读写分离 标准版双副本：主节点故障30秒自动切换 集群版：代理模式，统一域名访问，数据分片横向扩展 白名单：默认127.0.0.1，必须配置才能外部访问 Tair企业版：性能增强型（3倍性能）、持久内存型、容量存储型 热点Key：Proxy Query Cache优化访问倾斜 大Key危害：CPU、内存、网络资源消耗，导致分片不均衡 连接命令：redis-cli -h hostname -p 6379 [-c] 典型实验流程（沙箱环境） 创建Redis实例 → 设置白名单/添加安全组 → 连接Redis实例（redis-cli）→ 执行AUTH认证 → 执行Redis命令验证（GET/SET/DBSIZE等） 相关推荐：\nDay 7：云数据库RDS操作实践 Day 13：容器服务ACK部署与配置 阿里云Redis企业版文档 ","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-12-acp-day-12-%E4%BA%91%E6%95%B0%E6%8D%AE%E5%BA%93redis/","summary":"\u003ch1 id=\"day-12云数据库redis\"\u003eDay 12：云数据库Redis\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e本文基于阿里云ACP云计算工程师认证课程内容整理，涵盖Redis非关系型数据库核心知识、云数据库Redis架构选型、操作配置及性能优化最佳实践。\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一非关系型数据库与redis核心原理\"\u003e一、非关系型数据库与Redis核心原理\u003c/h2\u003e\n\u003ch3 id=\"什么是非关系型数据库nosql\"\u003e什么是非关系型数据库（NoSQL）\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eNoSQL（Not Only SQL）\u003c/strong\u003e 泛指非关系型数据库，区别于传统关系数据库不保证ACID特性，核心优势在于：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e易扩展\u003c/strong\u003e：无固定表结构，数据模型灵活\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e大数据量、高性能\u003c/strong\u003e：支持TB级数据存储，高并发读写\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e灵活的数据模型\u003c/strong\u003e：键值、列存储、文档、图形多种类型\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e高可用\u003c/strong\u003e：副本集、分片集群自动故障切换\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"redis核心特性\"\u003eRedis核心特性\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eRedis（Remote Dictionary Server）\u003c/strong\u003e 是开源的ANSI C语言编写的内存数据库，支持网络、可基于内存或持久化运行：\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e特性\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e持久化\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e周期性地将内存更新写入磁盘，重启可恢复\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e数据结构丰富\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e支持String、List、Set、ZSet、Hash等\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e主从备份\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eMaster-Slave模式数据复制\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e原子操作\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e所有操作原子性，支持事务合并执行\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e发布/订阅\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e支持消息通知、Key过期等高级特性\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"redis-vs-其他数据库\"\u003eRedis vs 其他数据库\u003c/h3\u003e\nMySQL/PostgreSQL（关系型）→ 复杂查询、事务强一致性\nMongoDB（文档型）→ JSON文档存储、半结构化数据\nRedis（键值型）→ 高性能缓存、Session存储、实时计算\u003ch3 id=\"redis典型使用场景缓存层加速\"\u003eRedis典型使用场景：缓存层加速\u003c/h3\u003e\n\u003cp\u003e在大并发场景下，直接访问数据库会造成IO压力过大：\u003c/p\u003e\n用户请求 → 应用服务器 → Redis缓存（先访问）\n                          ↓ 未命中\n                       数据库服务器\u003cp\u003eRedis基于内存存储，QPS可达\u003cstrong\u003e10万以上\u003c/strong\u003e，远超MySQL等磁盘数据库，是应对高并发访问的核心武器。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e考试要点\u003c/strong\u003e：Redis不仅支持简单的Key-Value，还提供List、Set、ZSet、Hash等复杂数据结构。Redis操作是原子性的，支持事务。\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"二云数据库redis架构选型指南\"\u003e二、云数据库Redis架构选型指南\u003c/h2\u003e\n\u003ch3 id=\"阿里云redis产品家族\"\u003e阿里云Redis产品家族\u003c/h3\u003e\n\u003cp\u003e阿里云提供\u003cstrong\u003e社区版Redis\u003c/strong\u003e和\u003cstrong\u003e企业版Tair\u003c/strong\u003e两大产品线：\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e版本\u003c/th\u003e\n          \u003cth\u003e简介\u003c/th\u003e\n          \u003cth\u003e适用场景\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e社区版\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e兼容开源Redis协议\u003c/td\u003e\n          \u003ctd\u003e小型网站、开发测试、个人学习\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e企业版Tair\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e阿里集团自研，增强性能\u003c/td\u003e\n          \u003ctd\u003e企业级缓存、高性能并发、低延迟场景\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"tair企业版三大存储形态\"\u003eTair企业版三大存储形态\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e类型\u003c/th\u003e\n          \u003cth\u003e核心技术\u003c/th\u003e\n          \u003cth\u003e适用场景\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e性能增强型\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e多线程模型，性能≈社区版3倍\u003c/td\u003e\n          \u003ctd\u003e高性能、低延迟要求\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e持久内存型\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e掉电数据不丢失，成本降低30%\u003c/td\u003e\n          \u003ctd\u003e温冷数据存储、兼顾性能与成本\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e容量存储型\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e基于ESSD，大容量低成本\u003c/td\u003e\n          \u003ctd\u003e大容量、低访问频率数据\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"部署架构选型\"\u003e部署架构选型\u003c/h3\u003e\n\u003ch4 id=\"标准版-双副本master-replica\"\u003e标准版-双副本（Master-Replica）\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e主节点提供日常访问，备节点提供HA高可用\u003c/li\u003e\n\u003cli\u003e主节点故障后\u003cstrong\u003e30秒内\u003c/strong\u003e自动切换到备节点\u003c/li\u003e\n\u003cli\u003e适用：Redis协议兼容性要求高、作为持久化数据存储、单节点性能压力可控\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"标准版-单副本\"\u003e标准版-单副本\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e单节点部署，无备用节点\u003c/li\u003e\n\u003cli\u003e提供数据持久化和备份机制\u003c/li\u003e\n\u003cli\u003e价格优势明显，适合\u003cstrong\u003e纯缓存\u003c/strong\u003e业务\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"集群版-双副本\"\u003e集群版-双副本\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e代理（Proxy）模式，一个统一连接地址访问集群\u003c/li\u003e\n\u003cli\u003e数据分片横向扩展，每个分片双副本高可用\u003c/li\u003e\n\u003cli\u003e适用：\u003cstrong\u003e数据量大、QPS高、吞吐密集型\u003c/strong\u003e场景\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"读写分离版\"\u003e读写分离版\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e主备节点 + 只读节点 + 代理节点\u003c/li\u003e\n\u003cli\u003e链式复制架构，只读节点扩展使整体性能线性增长\u003c/li\u003e\n\u003cli\u003e适用：\u003cstrong\u003e读多写少、读取QPS压力大的场景\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"容灾方案三级对比\"\u003e容灾方案三级对比\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e灾备级别\u003c/th\u003e\n          \u003cth\u003e架构\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e★★★☆☆\u003c/td\u003e\n          \u003ctd\u003e单可用区双副本\u003c/td\u003e\n          \u003ctd\u003e主备部署在不同机器，同一可用区\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e★★★★☆\u003c/td\u003e\n          \u003ctd\u003e双可用区高可用\u003c/td\u003e\n          \u003ctd\u003e主备分属同一地域两个可用区，单AZ故障自动切换\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e★★★★★\u003c/td\u003e\n          \u003ctd\u003e全球多活分布式\u003c/td\u003e\n          \u003ctd\u003e多子实例跨地域同步，支持异地灾备、就近访问\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e考试要点\u003c/strong\u003e：标准版-双副本的主备自动切换时间约为30秒。集群版采用代理模式，通过统一域名访问。读写分离版只读节点采用链式复制架构。\u003c/p\u003e","tags":"Alibaba Cloud, Redis, 云数据库, 缓存, ACP, 云计算","title":"Day 12: 云数据库Redis - ACP云计算工程师认证"},{"columns":"","content":"Python Day 13 - 列表增删改查（List Operations） 课程概述 本节课将深入学习 Python 列表（List）这一核心数据结构。列表是 Python 中最常用、最灵活的数据类型之一，它是有序的可变序列，可以存储任意类型的对象。本课程基于 Python 3.11 编写，所有示例均经过验证。\n列表（List）类似于其他语言中的数组，但比传统数组更强大：数组只能存储相同类型的元素，而列表可以存储混合类型的元素。此外，列表的长度可以动态变化，这是列表与元组（Tuple）的根本区别。\n一、列表基础概念 1.1 什么是列表 列表是一个有序的可变序列。列表中的每个元素都有一个明确的索引，从 0 开始计数（从左到右）。第一个元素的索引是 0，第二个是 1，以此类推。Python 也支持负索引，-1 表示最后一个元素，-2 表示倒数第二个，以此类推。\n# 列表的基本定义 fruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;, \u0026#34;葡萄\u0026#34;] print(fruits) # [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;葡萄\u0026#39;] print(type(fruits)) # \u0026lt;class \u0026#39;list\u0026#39;\u0026gt; 1.2 列表的特点 特点 说明 有序性 元素按插入顺序存储，每个元素有固定的位置索引 可变性 可以在原地修改列表：添加、删除、替换元素 可存储任意类型 可以存储整数、浮点数、字符串、布尔值、甚至是另一个列表 动态增长 不需要预先声明大小，可以随时添加新元素 支持切片 可以通过切片操作获取列表的子集 可嵌套 列表可以包含列表，形成多层嵌套结构 1.3 列表的创建方式 Python 提供了多种创建列表的方法：\n# 方法1：使用方括号直接创建 empty_list = [] numbers = [1, 2, 3, 4, 5] mixed = [1, \u0026#34;hello\u0026#34;, 3.14, True, None] # 方法2：使用 list() 构造函数 another_list = list() # 空列表 char_list = list(\u0026#34;Python\u0026#34;) # [\u0026#39;P\u0026#39;, \u0026#39;y\u0026#39;, \u0026#39;t\u0026#39;, \u0026#39;h\u0026#39;, \u0026#39;o\u0026#39;, \u0026#39;n\u0026#39;] range_list = list(range(1, 10)) # [1, 2, 3, 4, 5, 6, 7, 8, 9] # 方法3：使用列表推导式（后续课程详讲） squares = [x**2 for x in range(1, 6)] # [1, 4, 9, 16, 25] # 方法4：使用 * 运算符重复列表 zeros = [0] * 10 # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] repeated = [\u0026#34;A\u0026#34;] * 3 # [\u0026#39;A\u0026#39;, \u0026#39;A\u0026#39;, \u0026#39;A\u0026#39;] # 方法5：使用 list.split() 从字符串分割 sentence = \u0026#34;Python 是 一门 很 好 学 的 语言\u0026#34; words = sentence.split(\u0026#34; \u0026#34;) # [\u0026#39;Python\u0026#39;, \u0026#39;是\u0026#39;, \u0026#39;一门\u0026#39;, \u0026#39;很\u0026#39;, \u0026#39;好\u0026#39;, \u0026#39;学\u0026#39;, \u0026#39;的\u0026#39;, \u0026#39;语言\u0026#39;] 二、列表的查询操作（查） 2.1 索引访问 通过索引可以直接访问列表中的单个元素。索引的有效范围是 0 到 len(list)-1。如果索引超出范围，Python 会抛出 IndexError 异常。\nfruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;, \u0026#34;葡萄\u0026#34;, \u0026#34;草莓\u0026#34;] # 正向索引访问 print(fruits[0]) # 苹果（第一个元素） print(fruits[1]) # 香蕉（第二个元素） print(fruits[4]) # 草莓（第五个元素） # 负索引访问（从右向左） print(fruits[-1]) # 草莓（最后一个元素） print(fruits[-2]) # 葡萄（倒数第二个元素） print(fruits[-5]) # 苹果（倒数第五个元素） # 索引越界会报错 # print(fruits[10]) # IndexError: list index out of range # 使用 len() 获取列表长度 print(len(fruits)) # 5 2.2 切片操作 切片用于获取列表的一个子集，基本语法是 list[start:stop:step]，其中：\nstart：起始索引（包含），默认为 0 stop：结束索引（不包含），默认为列表长度 step：步长，默认为 1 numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 基本切片 print(numbers[2:7]) # [2, 3, 4, 5, 6] 从索引2到索引6 print(numbers[:5]) # [0, 1, 2, 3, 4] 从开头到索引4 print(numbers[5:]) # [5, 6, 7, 8, 9] 从索引5到末尾 print(numbers[:]) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 复制整个列表 # 使用步长 print(numbers[::2]) # [0, 2, 4, 6, 8] 隔一个取一个 print(numbers[1::2]) # [1, 3, 5, 7, 9] 从索引1开始，隔一个取一个 print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 反转列表 print(numbers[5:1:-1]) # [5, 4, 3, 2] 从索引5到索引2（反向） # 切片不会越界 print(numbers[0:100]) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 不会报错 2.3 列表的查找方法 方法 说明 返回值 list.index(x) 返回元素 x 第一次出现的索引 int，未找到抛出 ValueError list.count(x) 返回元素 x 出现的次数 int x in list 检查元素 x 是否在列表中 bool x not in list 检查元素 x 是否不在列表中 bool numbers = [1, 3, 5, 7, 9, 3, 2, 3, 4, 3] # index() - 查找元素首次出现的索引 print(numbers.index(3)) # 1（数字3第一次出现在索引1） # print(numbers.index(100)) # ValueError: 100 is not in list # count() - 统计元素出现次数 print(numbers.count(3)) # 4（数字3出现了4次） print(numbers.count(100)) # 0（数字100不存在） # in / not in 操作符 print(5 in numbers) # True print(100 in numbers) # False print(100 not in numbers) # True 2.4 查找最大最小值 scores = [88, 92, 75, 96, 85, 73, 90] print(max(scores)) # 96 print(min(scores)) # 73 print(sum(scores)) # 599 # 配合 key 参数使用 names = [\u0026#34;Alice\u0026#34;, \u0026#34;Bob\u0026#34;, \u0026#34;Charlie\u0026#34;, \u0026#34;David\u0026#34;] print(max(names, key=len)) # Charlie（最长的名字） print(min(names, key=len)) # Bob（最短的名字） 三、列表的添加操作（增） 3.1 append() - 末尾追加单个元素 append() 方法用于在列表末尾添加一个元素，原地操作，无返回值（返回 None）。\nfruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;] print(f\u0026#34;追加前: {fruits}\u0026#34;) # [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;] fruits.append(\u0026#34;橙子\u0026#34;) print(f\u0026#34;追加后: {fruits}\u0026#34;) # [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;] # append() 返回 None，不要这样写 # result = fruits.append(\u0026#34;葡萄\u0026#34;) # result 是 None # 可以连续追加 fruits.append(\u0026#34;草莓\u0026#34;) fruits.append(\u0026#34;西瓜\u0026#34;) print(fruits) # [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;草莓\u0026#39;, \u0026#39;西瓜\u0026#39;] 3.2 extend() - 末尾追加多个元素 extend() 方法用于在列表末尾批量添加多个元素，参数必须是可迭代对象（列表、元组、集合、字符串等）。\nfruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;] # 追加列表 fruits.extend([\u0026#34;橙子\u0026#34;, \u0026#34;葡萄\u0026#34;]) print(fruits) # [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;葡萄\u0026#39;] # 追加元组 fruits.extend((\u0026#34;草莓\u0026#34;, \u0026#34;西瓜\u0026#34;)) print(fruits) # [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;葡萄\u0026#39;, \u0026#39;草莓\u0026#39;, \u0026#39;西瓜\u0026#39;] # 追加字符串（字符串会被拆分成单个字符） fruits.extend(\u0026#34;Mango\u0026#34;) print(fruits) # [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;葡萄\u0026#39;, \u0026#39;草莓\u0026#39;, \u0026#39;西瓜\u0026#39;, \u0026#39;M\u0026#39;, \u0026#39;a\u0026#39;, \u0026#39;n\u0026#39;, \u0026#39;g\u0026#39;, \u0026#39;o\u0026#39;] # 追加 range 对象 fruits.extend(range(3)) print(fruits) # [..., 0, 1, 2] append() vs extend() 的区别：\na = [1, 2, 3] b = [4, 5, 6] a.append(b) # [1, 2, 3, [4, 5, 6]] - 把 b 作为整体添加进去 a.extend(b) # [1, 2, 3, 4, 5, 6] - 把 b 的元素拆分添加进去 3.3 insert() - 指定位置插入 insert(index, element) 方法用于在指定位置插入一个元素。\nfruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;] print(f\u0026#34;插入前: {fruits}\u0026#34;) # [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;] # 在索引0位置插入 fruits.insert(0, \u0026#34;葡萄\u0026#34;) print(fruits) # [\u0026#39;葡萄\u0026#39;, \u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;] # 在列表中间插入 fruits.insert(2, \u0026#34;草莓\u0026#34;) print(fruits) # [\u0026#39;葡萄\u0026#39;, \u0026#39;苹果\u0026#39;, \u0026#39;草莓\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;] # 在末尾插入（等同于 append） fruits.insert(len(fruits), \u0026#34;西瓜\u0026#34;) print(fruits) # [\u0026#39;葡萄\u0026#39;, \u0026#39;苹果\u0026#39;, \u0026#39;草莓\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;西瓜\u0026#39;] # 如果索引超出范围，自动在末尾插入 fruits.insert(999, \u0026#34;猕猴桃\u0026#34;) print(fruits) # [..., \u0026#39;猕猴桃\u0026#39;] 3.4 + 运算符拼接 使用 + 运算符可以拼接两个列表，生成一个新列表，原列表不变。\nlist1 = [1, 2, 3] list2 = [4, 5, 6] list3 = list1 + list2 print(list3) # [1, 2, 3, 4, 5, 6] # 原列表保持不变 print(list1) # [1, 2, 3] print(list2) # [4, 5, 6] # 使用 += 运算符（相当于 extend，就地修改） list1 += list2 print(list1) # [1, 2, 3, 4, 5, 6] 3.5 * 运算符重复 使用 * 运算符可以重复列表多次，生成一个新列表。\nzeros = [0] * 5 print(zeros) # [0, 0, 0, 0, 0] pattern = [1, 2, 3] * 3 print(pattern) # [1, 2, 3, 1, 2, 3, 1, 2, 3] # 重复空列表 empty = [] * 10 print(empty) # [] 四、列表的删除操作（删） 4.1 pop() - 按索引删除 pop() 方法删除并返回指定位置的元素。默认删除最后一个元素。如果索引超出范围会抛出 IndexError。\nfruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;, \u0026#34;葡萄\u0026#34;, \u0026#34;草莓\u0026#34;] # pop() 默认删除并返回最后一个元素 removed = fruits.pop() print(f\u0026#34;删除的元素: {removed}\u0026#34;) # 草莓 print(f\u0026#34;删除后: {fruits}\u0026#34;) # [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;葡萄\u0026#39;] # pop(index) 删除并返回指定索引的元素 removed = fruits.pop(1) print(f\u0026#34;删除的元素: {removed}\u0026#34;) # 香蕉 print(f\u0026#34;删除后: {fruits}\u0026#34;) # [\u0026#39;苹果\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;葡萄\u0026#39;] # 删除所有元素后，列表变为空 fruits.pop() fruits.pop() fruits.pop() print(fruits) # [] # pop() 在空列表上会报错 # fruits.pop() # IndexError: pop from empty list 4.2 remove() - 按值删除 remove() 方法删除第一个匹配的指定值。如果值不存在，抛出 ValueError。此方法没有返回值。\nfruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;, \u0026#34;苹果\u0026#34;, \u0026#34;葡萄\u0026#34;] # 删除第一个匹配的元素 fruits.remove(\u0026#34;苹果\u0026#34;) print(fruits) # [\u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;苹果\u0026#39;, \u0026#39;葡萄\u0026#39;] # 删除第二个\u0026#34;苹果\u0026#34;（现在在索引2） fruits.remove(\u0026#34;苹果\u0026#34;) print(fruits) # [\u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;葡萄\u0026#39;] # 删除不存在的元素会报错 # fruits.remove(\u0026#34;西瓜\u0026#34;) # ValueError: list.remove(x): x not in list 4.3 clear() - 清空列表 clear() 方法删除列表中的所有元素，使列表变为空列表。\nfruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;] print(f\u0026#34;清空前: {fruits}\u0026#34;) # [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;] fruits.clear() print(f\u0026#34;清空后: {fruits}\u0026#34;) # [] # 两种清空方式的比较 # 方法1：clear() - 清空列表，保留列表对象 list1 = [1, 2, 3] list1.clear() # [] # 方法2：重新赋值 - 创建新的空列表 list2 = [1, 2, 3] list2 = [] # list2 指向新的空列表 4.4 del 语句 del 是 Python 的语句，可以删除列表中的指定元素或切片，也可以删除整个变量。\nfruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;, \u0026#34;葡萄\u0026#34;, \u0026#34;草莓\u0026#34;] # del 删除单个元素 del fruits[2] print(fruits) # [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;葡萄\u0026#39;, \u0026#39;草莓\u0026#39;] # del 删除切片 del fruits[1:3] print(fruits) # [\u0026#39;苹果\u0026#39;, \u0026#39;草莓\u0026#39;] # del 删除整个列表 del fruits # print(fruits) # NameError: name \u0026#39;fruits\u0026#39; is not defined 4.5 删除操作对比 方法 语法 返回值 特点 pop() lst.pop(i) 返回被删除的元素 按索引删除，默认末尾 remove() lst.remove(x) None 按值删除，删除第一个匹配 clear() lst.clear() None 清空所有元素 del del lst[i] 无 可删除元素、切片或变量 五、列表的修改操作（改） 5.1 按索引赋值 直接通过索引对列表元素进行赋值修改。\nfruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;, \u0026#34;葡萄\u0026#34;] print(f\u0026#34;修改前: {fruits}\u0026#34;) fruits[0] = \u0026#34;猕猴桃\u0026#34; # 修改第一个元素 print(fruits) # [\u0026#39;猕猴桃\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;葡萄\u0026#39;] fruits[-1] = \u0026#34;西瓜\u0026#34; # 修改最后一个元素 print(fruits) # [\u0026#39;猕猴桃\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;西瓜\u0026#39;] # fruits[10] = \u0026#34;菠萝\u0026#34; # IndexError: 索引不能超出范围 5.2 切片赋值 使用切片赋值可以同时修改多个元素，甚至可以改变列表的长度和内容。\nnumbers = [1, 2, 3, 4, 5] # 替换切片 numbers[1:4] = [20, 30, 40] print(numbers) # [1, 20, 30, 40, 5] # 使用空列表删除元素 numbers = [1, 2, 3, 4, 5] numbers[1:3] = [] print(numbers) # [1, 4, 5] # 插入元素 numbers = [1, 5] numbers[1:1] = [2, 3, 4] # 在索引1位置插入 print(numbers) # [1, 2, 3, 4, 5] # 替换为不同长度的序列 numbers = [1, 2, 3, 4, 5] numbers[1:4] = [100] # 3个元素替换为1个元素 print(numbers) # [1, 100, 5] 5.3 排序操作 # sort() - 原地排序 numbers = [3, 1, 4, 1, 5, 9, 2, 6] numbers.sort() print(numbers) # [1, 1, 2, 3, 4, 5, 6, 9] # sort(reverse=True) - 降序排序 numbers.sort(reverse=True) print(numbers) # [9, 6, 5, 4, 3, 2, 1, 1] # 按绝对值排序 numbers = [-3, 1, -4, 1, 5, -9, 2, 6] numbers.sort(key=abs) print(numbers) # [1, 1, 2, -3, -4, 5, 6, -9] # 按字符串长度排序 words = [\u0026#34;apple\u0026#34;, \u0026#34;pie\u0026#34;, \u0026#34;python\u0026#34;, \u0026#34;hi\u0026#34;] words.sort(key=len) print(words) # [\u0026#39;hi\u0026#39;, \u0026#39;pie\u0026#39;, \u0026#39;apple\u0026#39;, \u0026#39;python\u0026#39;] # sorted() - 返回排序后的新列表，原列表不变 numbers = [3, 1, 4, 1, 5, 9, 2, 6] sorted_numbers = sorted(numbers) print(numbers) # [3, 1, 4, 1, 5, 9, 2, 6] - 原列表不变 print(sorted_numbers) # [1, 1, 2, 3, 4, 5, 6, 9] - 新列表 5.4 反转操作 # reverse() - 原地反转 fruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;] fruits.reverse() print(fruits) # [\u0026#39;橙子\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;苹果\u0026#39;] # 使用切片反转（返回新列表） fruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;] reversed_fruits = fruits[::-1] print(fruits) # [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;] - 原列表不变 print(reversed_fruits) # [\u0026#39;橙子\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;苹果\u0026#39;] - 新列表 5.5 复制操作 original = [1, 2, 3, 4, 5] # 浅拷贝 - 三种方式效果相同 copy1 = original[:] copy2 = original.copy() copy3 = list(original) print(copy1) # [1, 2, 3, 4, 5] print(copy2) # [1, 2, 3, 4, 5] print(copy3) # [1, 2, 3, 4, 5] # 修改副本不影响原列表 copy1.append(6) print(original) # [1, 2, 3, 4, 5] - 原列表不变 print(copy1) # [1, 2, 3, 4, 5, 6] # 赋值语句 - 不会创建副本 alias = original alias.append(7) print(original) # [1, 2, 3, 4, 5, 7] - 原列表被修改！ 六、列表的常用技巧 6.1 列表解包（Unpacking） # 基本解包 a, b, c = [1, 2, 3] print(a, b, c) # 1 2 3 # 使用星号 * 收集剩余元素 first, *middle, last = [1, 2, 3, 4, 5] print(first) # 1 print(middle) # [2, 3, 4] print(last) # 5 # 交换变量 x, y = 10, 20 x, y = y, x # 无需临时变量交换 print(x, y) # 20 10 # 解包字符串 a, b, c = \u0026#34;ABC\u0026#34; print(a, b, c) # A B C 6.2 列表的比较运算 # 列表逐元素比较 print([1, 2, 3] \u0026lt; [1, 2, 4]) # True print([1, 2, 3] == [1, 2, 3]) # True print([1, 2, 3] \u0026lt; [1, 2, 3, 0]) # True（长度不同，前面的元素相同时，较短的更小） 6.3 列表的内存模型 # 理解列表的可变性与引用 a = [1, 2, 3] b = a # b 和 a 指向同一个列表对象 c = a[:] # c 是列表的副本 print(a is b) # True - 同一对象 print(a is c) # False - 不同对象 print(a == c) # True - 值相等 b.append(4) print(a) # [1, 2, 3, 4] - a 跟着变了 print(b) # [1, 2, 3, 4] - b 指向同一对象 print(c) # [1, 2, 3] - c 是副本，不受影响 6.4 嵌套列表 # 创建嵌套列表 matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] # 访问嵌套列表的元素 print(matrix[0]) # [1, 2, 3] - 第一行 print(matrix[0][1]) # 2 - 第一行第二列 # 修改元素 matrix[1][1] = 100 print(matrix[1]) # [4, 100, 6] # 创建 3x3 零矩阵 zero_matrix = [[0] * 3 for _ in range(3)] print(zero_matrix) # 注意：下面的方式是错误的 # wrong_matrix = [[0] * 3] * 3 # 三行指向同一对象！ 6.5 列表循环技巧 # 带索引的循环 fruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;] for index, fruit in enumerate(fruits): print(f\u0026#34;{index}: {fruit}\u0026#34;) # 反向遍历 for fruit in reversed(fruits): print(fruit) # 带索引的反向遍历 for index, fruit in enumerate(reversed(fruits)): print(f\u0026#34;{index}: {fruit}\u0026#34;) 七、列表的实战示例 7.1 学生成绩管理 # 创建一个学生成绩列表 scores = [] # 添加成绩 scores.append(95) scores.append(87) scores.append(92) scores.append(78) scores.append(88) # 计算平均分 average = sum(scores) / len(scores) print(f\u0026#34;学生数量: {len(scores)}\u0026#34;) print(f\u0026#34;最高分: {max(scores)}\u0026#34;) print(f\u0026#34;最低分: {min(scores)}\u0026#34;) print(f\u0026#34;平均分: {average:.2f}\u0026#34;) # 按降序排序 scores.sort(reverse=True) print(f\u0026#34;成绩排名: {scores}\u0026#34;) # 查找成绩 target = 88 if target in scores: position = scores.index(target) print(f\u0026#34;成绩 {target} 在第 {position + 1} 名\u0026#34;) 7.2 待办事项列表 # 待办事项列表 todos = [\u0026#34;完成作业\u0026#34;, \u0026#34;打扫房间\u0026#34;, \u0026#34;买菜\u0026#34;, \u0026#34;打电话\u0026#34;] # 添加新事项 todos.append(\u0026#34;整理衣柜\u0026#34;) todos.insert(0, \u0026#34;早起跑步\u0026#34;) # 完成事项（删除） completed = todos.pop(2) print(f\u0026#34;已完成: {completed}\u0026#34;) # 显示所有事项 print(\u0026#34;待办事项:\u0026#34;) for i, todo in enumerate(todos, 1): print(f\u0026#34; {i}. {todo}\u0026#34;) # 清空列表 todos.clear() print(f\u0026#34;所有事项已完成! 列表为空: {len(todos) == 0}\u0026#34;) 八、常见错误与注意事项 8.1 索引越界 fruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;] # print(fruits[5]) # IndexError: list index out of range 8.2 修改列表时遍历 # 错误：在遍历列表时修改列表 numbers = [1, 2, 3, 4, 5] for n in numbers: if n % 2 == 0: numbers.remove(n) print(numbers) # 结果不可预测！ # 正确做法：遍历副本 numbers = [1, 2, 3, 4, 5] for n in numbers[:]: # 遍历副本 if n % 2 == 0: numbers.remove(n) print(numbers) # [1, 3, 5] 8.3 列表与元组的选择 如果需要经常修改数据，使用列表 如果数据不希望被修改，使用元组 列表可以转换为元组：tuple(list)；元组可以转换为列表：list(tuple) 背诵版（核心要点） ┌─────────────────────────────────────────────────────────────┐ │ 列表增删改查 - 背诵版 │ ├─────────────────────────────────────────────────────────────┤ │ 【创建】 │ │ lst = [] / list() / list(range(5)) / [x*2 for x in range] │ │ │ │ 【查 - 查询】 │ │ lst[0] / lst[-1] 索引访问 │ │ lst[1:5:2] 切片访问 [起始:结束:步长] │ │ lst.index(x) 返回第一次出现的索引 │ │ lst.count(x) 元素出现次数 │ │ x in lst / x not in lst 成员判断 │ │ max(lst)/min(lst)/sum(lst) 最大/最小/总和 │ │ │ │ 【增 - 添加】 │ │ lst.append(x) 末尾追加单个元素 │ │ lst.extend(iterable) 末尾追加多个元素（可迭代） │ │ lst.insert(i, x) 在索引i处插入x │ │ lst \u0026#43; lst2 / lst \u0026#43;= lst2 拼接列表 │ │ │ │ 【删 - 删除】 │ │ lst.pop() / lst.pop(i) 删除并返回元素（默认末尾） │ │ lst.remove(x) 删除第一个匹配的值 │ │ lst.clear() 清空列表 │ │ del lst[i] / del lst[:] 删除元素/切片/变量 │ │ │ │ 【改 - 修改】 │ │ lst[i] = x 按索引修改 │ │ lst[1:3] = [x, y] 切片修改（可改变长度） │ │ lst.sort() / lst.sort(reverse=True, key=func) 原地排序 │ │ sorted(lst) 返回排序后的新列表 │ │ lst.reverse() 原地反转 │ │ lst[::-1] 返回反转后的新列表 │ │ │ │ 【复制】 │ │ lst.copy() / lst[:] / list(lst) 浅拷贝 │ │ new_lst = lst[:] 不影响原列表 │ └─────────────────────────────────────────────────────────────┘ 考前记忆（速记口诀） 【列表操作七字诀】 查：索引切片index数，max min sum要记住 增：append末尾加，extend批量扩，insert随意插 删：pop弹栈按位删，remove按值第一配，clear全部清空 改：直接赋值按位改，sort排序reverse倒 记：列表可变成引用，遍历修改用副本 测试题 一、选择题 下面哪个选项可以正确创建一个包含数字 1-5 的列表？\nA. list(1, 2, 3, 4, 5) B. [1, 2, 3, 4, 5] C. list(\u0026quot;12345\u0026quot;) D. list(range(1, 5)) 已知 lst = [10, 20, 30, 40, 50]，执行 lst.pop(2) 后，列表变为？\nA. [10, 20, 40, 50] B. [10, 20, 30, 40] C. [10, 20, 40, 50, 30] D. [30] 下列哪个方法可以删除列表中第一个匹配的值为 5 的元素？\nA. lst.pop(5) B. lst.remove(5) C. lst.delete(5) D. del lst[5] 执行 [1, 2, 3] + [4, 5, 6] 的结果是？\nA. [1, 2, 3, 4, 5, 6] B. [5, 7, 9] C. 10 D. [[1, 2, 3], [4, 5, 6]] 关于 append() 和 extend() 的区别，正确的是？\nA. 两者没有区别 B. append() 添加单个元素，extend() 添加可迭代对象的每个元素 C. extend() 添加单个元素，append() 添加每个元素 D. append() 返回新列表，extend() 返回 None lst = [3, 1, 4, 1, 5, 9, 2, 6]，lst.index(1) 返回？\nA. 1 B. 2 C. 3 D. 4 如何复制列表而不是创建引用？\nA. new = lst B. new = lst.copy() 或 new = lst[:] C. new = list(lst) 只有一个可以 D. 无法复制 fruits = [\u0026quot;苹果\u0026quot;, \u0026quot;香蕉\u0026quot;, \u0026quot;橙子\u0026quot;]，fruits[-1] 的值是？\nA. \u0026quot;苹果\u0026quot; B. \u0026quot;香蕉\u0026quot; C. \u0026quot;橙子\u0026quot; D. None 执行 [1, 2, 3, 4, 5][::-1] 的结果是？\nA. [1, 2, 3, 4, 5] B. [5, 4, 3, 2, 1] C. [0] D. [] lst = [3, 5, 2, 1, 4]，lst.sort() 后 lst 变为？\nA. [1, 2, 3, 4, 5] B. [5, 4, 3, 2, 1] C. None D. 报错 二、填空题 列表的索引从 _____ 开始（填数字）。\nlist(range(1, 10, 2)) 创建的列表是 _____ 。\n在列表末尾添加单个元素的方法是 _____ 。\n删除并返回列表末尾元素的方法是 _____ 。\n[\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;, \u0026quot;c\u0026quot;].count(\u0026quot;a\u0026quot;) 的结果是 _____ 。\n列表切片 lst[1:4] 包含的索引范围是 _____ 到 _____ （不包含）。\ndel lst[2:5] 的作用是 _____ 。\nlst.insert(0, x) 在列表的 _____ 位置插入元素。\n[1, 2, 3] * 2 的结果是 _____ 。\nlst.clear() 后，len(lst) 的值是 _____ 。\n三、编程题 写一个函数 remove_duplicates(lst)，去除列表中的重复元素，保持原有顺序。\n写一个函数 find_second_max(lst)，找出列表中第二大的元素。\n写一个函数 rotate_list(lst, k)，将列表循环右移 k 位。\n答案见下页\n测试题答案 选择题答案 题号 答案 解析 1 B [1, 2, 3, 4, 5] 是列表字面量，list(1,2,3,4,5) 语法错误 2 A pop(2) 删除索引2的元素 30，结果 [10, 20, 40, 50] 3 B remove() 删除第一个匹配的值；pop() 按索引 4 A + 运算符拼接列表生成新列表 5 B append(x) 把 x 当作一个元素添加，extend(x) 迭代 x 添加每个元素 6 A 数字 1 第一次出现在索引 1（第二个位置） 7 B .copy() 和 [:] 都是浅拷贝，= 是创建引用 8 C -1 表示最后一个元素 9 B [::-1] 是步长为 -1 的切片，表示反转 10 A sort() 默认升序排序 填空题答案 0（零） [1, 3, 5, 7, 9] append() pop() 1 1 到 3（包含索引1，不包含索引4） 删除索引2到4的元素（切片） 开头/第一个 [1, 2, 3, 1, 2, 3] 0 编程题答案 答案1：去除列表重复元素\ndef remove_duplicates(lst): \u0026#34;\u0026#34;\u0026#34;去除列表重复元素，保持顺序\u0026#34;\u0026#34;\u0026#34; seen = [] for item in lst: if item not in seen: seen.append(item) return seen # 测试 print(remove_duplicates([1, 3, 2, 1, 4, 3, 5])) # 输出: [1, 3, 2, 4, 5] 答案2：找出第二大的元素\ndef find_second_max(lst): \u0026#34;\u0026#34;\u0026#34;找出列表中第二大的元素\u0026#34;\u0026#34;\u0026#34; if len(lst) \u0026lt; 2: return None unique = list(set(lst)) # 去重 unique.sort(reverse=True) return unique[1] # 测试 print(find_second_max([5, 1, 4, 2, 3, 5, 4])) # 输出: 4 答案3：循环右移列表\ndef rotate_list(lst, k): \u0026#34;\u0026#34;\u0026#34;将列表循环右移 k 位\u0026#34;\u0026#34;\u0026#34; if len(lst) == 0: return [] k = k % len(lst) # 处理 k 大于列表长度的情况 return lst[-k:] + lst[:-k] # 测试 print(rotate_list([1, 2, 3, 4, 5], 2)) # 输出: [4, 5, 1, 2, 3] 课后练习建议\n手动实现列表的 index() 和 count() 方法 实现一个简单的栈数据结构（使用列表） 实现一个简单的队列数据结构（使用列表） 挑战：实现冒泡排序算法 本课程完结\n","description":"深入学习Python列表的创建、访问、添加、删除、修改和查询操作","permalink":"https://blog.uuworld.cn/python-course/python-day-13-list-operations/","summary":"\u003ch1 id=\"python-day-13---列表增删改查list-operations\"\u003ePython Day 13 - 列表增删改查（List Operations）\u003c/h1\u003e\n\u003ch2 id=\"课程概述\"\u003e课程概述\u003c/h2\u003e\n\u003cp\u003e本节课将深入学习 Python 列表（List）这一核心数据结构。列表是 Python 中最常用、最灵活的数据类型之一，它是有序的可变序列，可以存储任意类型的对象。本课程基于 \u003cstrong\u003ePython 3.11\u003c/strong\u003e 编写，所有示例均经过验证。\u003c/p\u003e\n\u003cp\u003e列表（List）类似于其他语言中的数组，但比传统数组更强大：数组只能存储相同类型的元素，而列表可以存储混合类型的元素。此外，列表的长度可以动态变化，这是列表与元组（Tuple）的根本区别。\u003c/p\u003e\n\u003ch2 id=\"一列表基础概念\"\u003e一、列表基础概念\u003c/h2\u003e\n\u003ch3 id=\"11-什么是列表\"\u003e1.1 什么是列表\u003c/h3\u003e\n\u003cp\u003e列表是一个\u003cstrong\u003e有序\u003c/strong\u003e的\u003cstrong\u003e可变\u003c/strong\u003e序列。列表中的每个元素都有一个明确的\u003cstrong\u003e索引\u003c/strong\u003e，从 0 开始计数（从左到右）。第一个元素的索引是 0，第二个是 1，以此类推。Python 也支持负索引，-1 表示最后一个元素，-2 表示倒数第二个，以此类推。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 列表的基本定义\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003efruits \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;苹果\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;香蕉\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;橙子\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;葡萄\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(fruits)          \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;苹果\u0026#39;, \u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;, \u0026#39;葡萄\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(type(fruits))    \u003cspan style=\"color:#75715e\"\u003e# \u0026lt;class \u0026#39;list\u0026#39;\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"12-列表的特点\"\u003e1.2 列表的特点\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e特点\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e有序性\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e元素按插入顺序存储，每个元素有固定的位置索引\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e可变性\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e可以在原地修改列表：添加、删除、替换元素\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e可存储任意类型\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e可以存储整数、浮点数、字符串、布尔值、甚至是另一个列表\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e动态增长\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e不需要预先声明大小，可以随时添加新元素\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e支持切片\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e可以通过切片操作获取列表的子集\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e可嵌套\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e列表可以包含列表，形成多层嵌套结构\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"13-列表的创建方式\"\u003e1.3 列表的创建方式\u003c/h3\u003e\n\u003cp\u003ePython 提供了多种创建列表的方法：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法1：使用方括号直接创建\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eempty_list \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enumbers \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emixed \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;hello\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3.14\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法2：使用 list() 构造函数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eanother_list \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e list()  \u003cspan style=\"color:#75715e\"\u003e# 空列表\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003echar_list \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e list(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Python\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;P\u0026#39;, \u0026#39;y\u0026#39;, \u0026#39;t\u0026#39;, \u0026#39;h\u0026#39;, \u0026#39;o\u0026#39;, \u0026#39;n\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003erange_list \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e list(range(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# [1, 2, 3, 4, 5, 6, 7, 8, 9]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法3：使用列表推导式（后续课程详讲）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esquares \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [x\u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e x \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e)]  \u003cspan style=\"color:#75715e\"\u003e# [1, 4, 9, 16, 25]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法4：使用 * 运算符重复列表\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ezeros \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003erepeated \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;A\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;A\u0026#39;, \u0026#39;A\u0026#39;, \u0026#39;A\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法5：使用 list.split() 从字符串分割\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esentence \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Python 是 一门 很 好 学 的 语言\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewords \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e sentence\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34; \u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;Python\u0026#39;, \u0026#39;是\u0026#39;, \u0026#39;一门\u0026#39;, \u0026#39;很\u0026#39;, \u0026#39;好\u0026#39;, \u0026#39;学\u0026#39;, \u0026#39;的\u0026#39;, \u0026#39;语言\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"二列表的查询操作查\"\u003e二、列表的查询操作（查）\u003c/h2\u003e\n\u003ch3 id=\"21-索引访问\"\u003e2.1 索引访问\u003c/h3\u003e\n\u003cp\u003e通过索引可以直接访问列表中的单个元素。索引的有效范围是 \u003ccode\u003e0\u003c/code\u003e 到 \u003ccode\u003elen(list)-1\u003c/code\u003e。如果索引超出范围，Python 会抛出 \u003ccode\u003eIndexError\u003c/code\u003e 异常。\u003c/p\u003e","tags":"Python, 列表, List, 数据结构","title":"Python Day 13 - 列表增删改查"},{"columns":"acp-course","content":"Day 13：容器服务ACK 本文基于阿里云ACP云计算工程师认证课程内容整理，涵盖容器与Docker技术原理、Kubernetes核心概念、容器服务ACK架构与操作配置，以及企业级DevOps最佳实践。\n一、容器与Docker技术原理 云计算应用架构演进 单体应用 → SOA架构 → 微服务架构 → 云原生架构 (垂直竖井) (服务化) (轻量容器) (容器\u0026#43;K8s\u0026#43;DevOps)云原生时代三驾马车：容器、微服务、DevOps\n为什么需要容器 容器是一种轻量级、可移植、自包含的软件打包技术，使应用程序可以在几乎任何地方以相同方式运行：\n一致性环境：开发、测试、生产环境完全一致 超快速启动：秒级启动，告别分钟级虚拟机 资源隔离：容器间相互隔离，互不影响 高效利用：不需要完整操作系统，容器密度远高于VM Docker核心特性 特性 说明 标准化 一次构建，到处运行，环境一致 高性能 容器直接运行在宿主机内核，无需硬件虚拟化 轻量级 共享宿主机内核，秒级启动，资源利用率高 隔离性 Linux Namespace实现进程级隔离 Docker vs 虚拟机 对比项 Docker容器 虚拟机 启动时间 秒级 分钟级 资源占用 共享宿主机内核，低 独立操作系统，高 隔离级别 进程级 硬件级 镜像大小 MB级 GB级 交付内容 应用+依赖 完整OS+应用 Docker核心组件 Docker架构 ├── Docker Client（客户端）← 用户交互界面 ├── Docker Daemon（服务端）← 守护进程 ├── Image（镜像）← 只读模板 ├── Container（容器）← 镜像运行实例 └── Registry（镜像仓库）← 镜像存储分发Build、Ship、Run 流程：\nBuild：构建镜像（Dockerfile → Image） Ship：推送到镜像仓库（Image → Registry） Run：从仓库拉取并运行（Registry → Container） 考试要点：Docker镜像是分层只读结构，容器是在镜像上加上一层可写层。Docker Hub是公共镜像仓库，阿里云ACR提供企业级私有镜像仓库。\n二、Kubernetes核心概念与架构 Kubernetes概述 Kubernetes（K8s） 是Google开源的容器编排引擎，是容器编排领域的事实标准，核心功能：\n服务发现与负载均衡：Service抽象统一入口 自动化容器装箱：Pod调度优化 存储编排：Volume挂载多种后端存储 自动恢复：自愈能力，容器故障自动重启 滚动更新与回滚：灰度发布支持 配置与密钥管理：ConfigMap、Secret 批量执行：Job、CronJob 水平伸缩：HPA自动扩缩容 Kubernetes核心对象 Pod 最小调度单位：Pod是K8s中能够创建和部署的最小单元 包含一个或多个容器：共享网络、存储资源 始终部署在同一节点：最小调度及资源单位 支持多种容器运行时，Docker是最流行的容器环境 Volume Pod中能被多个容器共享的磁盘目录 支持多种后端：本地存储、分布式存储（NAS/CPFS）、阿里云云盘/OSS Docker Volume与K8s Volume概念类似但更强大 Deployment 应用管理的最常见方式，定义一组Pod副本数、版本 通过控制器维持Pod数目，自动恢复失败的Pod 支持滚动更新、版本回滚 Service 为一组具有相同功能的容器应用提供统一入口地址 将请求负载分发到后端各个Pod 支持类型：ClusterIP、NodePort、LoadBalancer Namespace 集群内部的逻辑隔离，包括鉴权、资源管理 每个资源属于一个Namespace，同一NS内资源名唯一 不同NS可重名，用于多团队/多环境隔离 Kubernetes集群架构 ┌─────────────────────────────────────────────────┐ │ Kubernetes集群 │ │ ┌─────────────┐ ┌─────────────────┐ │ │ │ Master节点 │ │ Node节点 │ │ │ │ (管控面) │ │ (工作面) │ │ │ │ │ │ │ │ │ │ kube-apiserver │◄──────►│ kubelet │ │ │ │ kube-controller│ │ kube-proxy │ │ │ │ kube-scheduler │ │ Container Runtime│ │ │ │ etcd │ │ (Docker) │ │ │ └─────────────┘ └─────────────────┘ │ └─────────────────────────────────────────────────┘Master节点组件 组件 职责 kube-apiserver 集群HTTP REST API入口，集群控制唯一入口 kube-controller-manager 所有资源对象的自动化控制中心 kube-scheduler Pod资源对象的调度服务 etcd 分布式存储系统，保存集群所有状态 Node节点组件 组件 职责 kubelet 管理容器创建/删除/启停，与Master通信 kube-proxy 服务发现和负载均衡 Container Runtime 容器基础管理（接收kubelet指令） Kubernetes三大能力 能力 说明 调度 根据调度算法将Pod分配到最优节点 自愈 自动重启、重新调度、替换故障节点 弹性伸缩 HPA基于CPU/内存自动扩缩Pod数量 考试要点：Pod是K8s最小调度单位，始终部署在同一节点。Deployment管理Pod副本，支持滚动更新。Service通过Label Selector将请求分发到后端Pod。\n三、容器服务ACK架构与三种形态 ACK产品概述 容器服务ACK（Alibaba Cloud Container Service for Kubernetes） 提供高性能可伸缩的容器应用管理服务，支持企业级Kubernetes容器化应用的生命周期管理，是CNCF认证服务提供商。\n优势 说明 安全可控 端到端安全保障，支持主子账号和企业权限管理 简单易用 一键创建集群，一站式应用生命周期管理 高效可靠 海量容器秒级启动，阿里超大规模实战验证 认证合规 全球首批通过Kubernetes一致性验证 ACK三种产品形态 形态 特点 管理成本 适用场景 专有版Kubernetes 自行管理Master和Worker节点 高 需要细粒度控制基础设施 托管版Kubernetes Master托管，Worker自管理 中 免运维Master，高可用需求 Serverless Kubernetes 无需管理任何节点 低 直接启动应用，按量付费 托管版Kubernetes（推荐）：\n托管Master节点，kube-apiserver多实例部署 etcd三副本跨可用区部署，Region级高可用 托管组件包括kube-apiserver、kube-controller-manager、ack-scheduler和etcd ACK管控面持续监控，保障SLA，自动修复安全漏洞 ACK弹性伸缩体系 弹性伸缩分为两层，可分开使用也可结合：\n调度层弹性 资源层弹性 （修改调度容量） （弹出ECS/ECI补充容量） ↑ ↑ └────── 容量状态 ──┘ 层次 组件 说明 调度层 HPA（Horizontal Pod Autoscaler） 根据负载自动调整Pod副本数 资源层 集群弹性伸缩（Cluster Autoscaler） 扩容时自动弹出ECS/ECI ACK灰度发布 灰度发布（金丝雀发布）：新旧版本同时部署，自定义新版本流量比重，渐进式全量上线，支持快速回滚。\n考试要点：托管版ACK的Master节点由ACK托管，免费使用，仅收取Worker节点和其他资源费用。Serverless Kubernetes按容器实例使用量按秒计费。\n四、ACK操作配置与企业级最佳实践 ACK使用全流程 创建集群 → 部署应用（Deployment）→ 创建服务（Service）→ 配置路由（Ingress）→ 弹性伸缩配置 → 监控运维创建Kubernetes托管版集群 选择托管版（推荐），配置集群规格 选择地域和可用区 配置VPC网络（使用容器网络插件CNI） 选择Kubernetes版本 配置Master和Worker节点规格 部署无状态工作负载（Deployment） apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14 ports: - containerPort: 80 创建路由（Ingress）公开应用 配置路由规则 → 绑定域名 → 配置TLS证书 → 测试访问自动创建SLB公开应用 apiVersion: v1 kind: Service metadata: name: nginx-svc spec: type: LoadBalancer # 或 ClusterIP / NodePort selector: app: nginx ports: - port: 80 targetPort: 80 配置容器水平伸缩（HPA） # 基于CPU使用率自动扩缩容 kubectl autoscale deployment nginx-deployment \\ --cpu-percent=50 \\ --min=2 \\ --max=10 通过kubectl连接集群 # 配置集群凭证 kubectl config use-context \u0026lt;cluster-name\u0026gt; # 查看集群节点 kubectl get nodes # 查看Pod kubectl get pods -n \u0026lt;namespace\u0026gt; # 查看服务 kubectl get svc -n \u0026lt;namespace\u0026gt; 三大企业级应用场景 场景一：DevOps持续交付 代码提交 → Jenkins自动构建 → Docker镜像构建 → 推送到ACR → ACK自动部署 → 全流程自动化 环境一致性：容器不可变架构，确保Dev/Test/Prod一致 快速反馈：每次集成或交付实时反馈 场景二：微服务架构 微服务拆分部署，每个服务独立迭代 MSE（微服务引擎）提供治理能力 搭配：ACK + MSE + RDS + OSS 场景三：混合云架构 统一管理云上云下容器资源 业务高峰期云端快速扩容 云下开发测试，无缝发布到云上 ACK vs 自建Kubernetes 功能 ACK 自建K8s 集群创建 控制台一键创建，支持GPU/裸金属 手动部署 集群管理 提供容器优化OS镜像 自行维护 网络 阿里云VPC/ENI高性能插件 社区网络插件 存储 云盘/NAS/CPFS/OSS，CSI/FlexVolume驱动 自行集成 升级 一键升级，支持组件生命周期管理 手动运维 监控 Prometheus内置，大量Dashboard 自行搭建 SLA Pro版提供赔付保障 无保障 ACP认证核心知识点速查 容器三特性：轻量级、可移植、自包含 Docker核心：Image（只读模板）、Container（运行实例）、Registry（仓库） Kubernetes最小调度单位：Pod Deployment：管理无状态应用，维持Pod副本数，支持滚动更新 Service类型：ClusterIP（内部）、NodePort（节点端口）、LoadBalancer（云负载均衡） ACK三种形态：专有版（自管Master）、托管版（托管Master）、Serverless（不管节点） 弹性伸缩：HPA（Pod副本）+ Cluster Autoscaler（节点扩容） 灰度发布：新旧版本共存，流量比例控制，快速回滚 ACK托管Master优势：多可用区部署，etcd三副本，零运维 kubectl：K8s标准CLI，通过API Server管理集群 典型实验流程（沙箱环境） 创建容器集群 → 部署无状态Deployment → 创建路由Ingress → SLB服务公开应用 → 配置HPA弹性伸缩 → 压测验证弹性 → Prometheus监控 相关推荐：\nDay 8：阿里云弹性架构部署 Day 12：云数据库Redis缓存 阿里云ACK官方文档 ","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-13-acp-day-13-%E5%AE%B9%E5%99%A8%E6%9C%8D%E5%8A%A1ack/","summary":"\u003ch1 id=\"day-13容器服务ack\"\u003eDay 13：容器服务ACK\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e本文基于阿里云ACP云计算工程师认证课程内容整理，涵盖容器与Docker技术原理、Kubernetes核心概念、容器服务ACK架构与操作配置，以及企业级DevOps最佳实践。\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一容器与docker技术原理\"\u003e一、容器与Docker技术原理\u003c/h2\u003e\n\u003ch3 id=\"云计算应用架构演进\"\u003e云计算应用架构演进\u003c/h3\u003e\n单体应用 → SOA架构 → 微服务架构 → 云原生架构\n(垂直竖井)  (服务化)   (轻量容器)   (容器\u0026#43;K8s\u0026#43;DevOps)\u003cp\u003e\u003cstrong\u003e云原生时代三驾马车\u003c/strong\u003e：容器、微服务、DevOps\u003c/p\u003e\n\u003ch3 id=\"为什么需要容器\"\u003e为什么需要容器\u003c/h3\u003e\n\u003cp\u003e容器是一种\u003cstrong\u003e轻量级、可移植、自包含\u003c/strong\u003e的软件打包技术，使应用程序可以在几乎任何地方以相同方式运行：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e一致性环境\u003c/strong\u003e：开发、测试、生产环境完全一致\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e超快速启动\u003c/strong\u003e：秒级启动，告别分钟级虚拟机\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e资源隔离\u003c/strong\u003e：容器间相互隔离，互不影响\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e高效利用\u003c/strong\u003e：不需要完整操作系统，容器密度远高于VM\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"docker核心特性\"\u003eDocker核心特性\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e特性\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e标准化\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e一次构建，到处运行，环境一致\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e高性能\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e容器直接运行在宿主机内核，无需硬件虚拟化\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e轻量级\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e共享宿主机内核，秒级启动，资源利用率高\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e隔离性\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eLinux Namespace实现进程级隔离\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"docker-vs-虚拟机\"\u003eDocker vs 虚拟机\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e对比项\u003c/th\u003e\n          \u003cth\u003eDocker容器\u003c/th\u003e\n          \u003cth\u003e虚拟机\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e启动时间\u003c/td\u003e\n          \u003ctd\u003e秒级\u003c/td\u003e\n          \u003ctd\u003e分钟级\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e资源占用\u003c/td\u003e\n          \u003ctd\u003e共享宿主机内核，低\u003c/td\u003e\n          \u003ctd\u003e独立操作系统，高\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e隔离级别\u003c/td\u003e\n          \u003ctd\u003e进程级\u003c/td\u003e\n          \u003ctd\u003e硬件级\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e镜像大小\u003c/td\u003e\n          \u003ctd\u003eMB级\u003c/td\u003e\n          \u003ctd\u003eGB级\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e交付内容\u003c/td\u003e\n          \u003ctd\u003e应用+依赖\u003c/td\u003e\n          \u003ctd\u003e完整OS+应用\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"docker核心组件\"\u003eDocker核心组件\u003c/h3\u003e\nDocker架构\n├── Docker Client（客户端）← 用户交互界面\n├── Docker Daemon（服务端）← 守护进程\n├── Image（镜像）← 只读模板\n├── Container（容器）← 镜像运行实例\n└── Registry（镜像仓库）← 镜像存储分发\u003cp\u003e\u003cstrong\u003eBuild、Ship、Run\u003c/strong\u003e 流程：\u003c/p\u003e","tags":"Alibaba Cloud, Kubernetes, ACK, 容器, ACP, 云计算, DevOps","title":"Day 13: 容器服务ACK - ACP云计算工程师认证"},{"columns":"","content":"Python Day 14 - 列表推导式 enumerate zip 课程概述 本节课将深入学习 Python 中三个非常重要的高级特性：列表推导式（List Comprehension）、enumerate 函数和 zip 函数。这些特性可以让你的代码更加简洁、高效和 Pythonic。\n本课程基于 Python 3.11 编写，所有示例均经过验证。在 Python 3.11 中，这些特性都得到全面支持且运行效率进一步提升。\n列表推导式是 Python 最具特色的语法之一，它允许你用一行代码就创建一个完整的列表。enumerate 函数为可迭代对象添加了索引，而 zip 函数则可以将多个可迭代对象组合在一起。掌握这三个工具，将大大提高你的 Python 编程能力。\n一、列表推导式（List Comprehension） 1.1 什么是列表推导式 列表推导式是一种简洁、高效创建列表的方式。它的语法来自数学中的集合定义式（Set Builder Notation）。传统方式创建列表需要多行代码，而列表推导式可以用一行完成。\n# 传统方式：使用 for 循环创建列表 squares = [] for x in range(10): squares.append(x ** 2) print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # 列表推导式：一行完成 squares = [x ** 2 for x in range(10)] print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 1.2 列表推导式的基本语法 [表达式 for 变量 in 可迭代对象] 表达式：对 变量 进行操作的结果 for 变量 in 可迭代对象：从可迭代对象中遍历每个元素 # 基本示例 numbers = [1, 2, 3, 4, 5] doubled = [n * 2 for n in numbers] print(doubled) # [2, 4, 6, 8, 10] # 对字符串操作 words = [\u0026#34;hello\u0026#34;, \u0026#34;world\u0026#34;, \u0026#34;python\u0026#34;] upper_words = [w.upper() for w in words] print(upper_words) # [\u0026#39;HELLO\u0026#39;, \u0026#39;WORLD\u0026#39;, \u0026#39;PYTHON\u0026#39;] # 使用函数 import math radii = [1, 2, 3, 4, 5] areas = [math.pi * r ** 2 for r in radii] print(areas) # [3.14159..., 12.566..., 28.274..., 50.265..., 78.539...] 1.3 带条件的列表推导式 可以在列表推导式中添加 if 条件筛选元素。\n[表达式 for 变量 in 可迭代对象 if 条件] # 筛选偶数 numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] evens = [n for n in numbers if n % 2 == 0] print(evens) # [2, 4, 6, 8, 10] # 筛选长度大于3的单词 words = [\u0026#34;cat\u0026#34;, \u0026#34;elephant\u0026#34;, \u0026#34;dog\u0026#34;, \u0026#34;mouse\u0026#34;, \u0026#34;tiger\u0026#34;] long_words = [w for w in words if len(w) \u0026gt; 3] print(long_words) # [\u0026#39;elephant\u0026#39;, \u0026#39;mouse\u0026#39;, \u0026#39;tiger\u0026#39;] # 筛选数字 mixed = [1, \u0026#34;hello\u0026#34;, 2, \u0026#34;world\u0026#34;, 3, \u0026#34;python\u0026#34;, 4] numbers_only = [x for x in mixed if isinstance(x, int)] print(numbers_only) # [1, 2, 3, 4] # 筛选回文数 palindromes = [x for x in range(100, 200) if str(x) == str(x)[::-1]] print(palindromes) # [101, 111, 121, 131, 141, 151, 161, 171, 181, 191] 1.4 多重条件筛选 # 多个 if 条件（相当于 and） numbers = range(1, 51) divisible = [n for n in numbers if n % 3 == 0 if n % 5 == 0] print(divisible) # [15, 30, 45] # 与下面的写法等价 divisible = [n for n in numbers if n % 3 == 0 and n % 5 == 0] print(divisible) # [15, 30, 45] 1.5 带 else 的列表推导式（if-else 表达式） 当需要根据条件为元素赋予不同值时，需要把 if-else 表达式放在 for 之前。\n[表达式1 if 条件 else 表达式2 for 变量 in 可迭代对象] # 将奇数替换为 \u0026#34;奇数\u0026#34;，偶数保持不变 numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] transformed = [n if n % 2 == 0 else \u0026#34;奇数\u0026#34; for n in numbers] print(transformed) # [\u0026#39;奇数\u0026#39;, 2, \u0026#39;奇数\u0026#39;, 4, \u0026#39;奇数\u0026#39;, 6, \u0026#39;奇数\u0026#39;, 8, \u0026#39;奇数\u0026#39;, 10] # 将成绩转换为等级 scores = [45, 67, 89, 92, 55, 78] grades = [\u0026#34;不及格\u0026#34; if s \u0026lt; 60 else \u0026#34;及格\u0026#34; if s \u0026lt; 80 else \u0026#34;优秀\u0026#34; for s in scores] print(grades) # [\u0026#39;不及格\u0026#39;, \u0026#39;及格\u0026#39;, \u0026#39;优秀\u0026#39;, \u0026#39;优秀\u0026#39;, \u0026#39;不及格\u0026#39;, \u0026#39;及格\u0026#39;] # 分类单词 words = [\u0026#34;Apple\u0026#34;, \u0026#34;ant\u0026#34;, \u0026#34;BANANA\u0026#34;, \u0026#34;Cat\u0026#34;, \u0026#34;dog\u0026#34;] categorized = [w.upper() if w[0].islower() else w.lower() for w in words] print(categorized) # [\u0026#39;APPLE\u0026#39;, \u0026#39;ANT\u0026#39;, \u0026#39;banana\u0026#39;, \u0026#39;CAT\u0026#39;, \u0026#39;DOG\u0026#39;] 1.6 双重循环列表推导式 [表达式 for 变量1 in 可迭代对象1 for 变量2 in 可迭代对象2] # 生成坐标点 points = [(x, y) for x in range(3) for y in range(3)] print(points) # [(0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)] # flatten 嵌套列表（方法1） matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] flat = [num for row in matrix for num in row] print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9] # 生成所有可能的组合 letters = [\u0026#39;A\u0026#39;, \u0026#39;B\u0026#39;, \u0026#39;C\u0026#39;] numbers = [1, 2] combinations = [f\u0026#34;{l}{n}\u0026#34; for l in letters for n in numbers] print(combinations) # [\u0026#39;A1\u0026#39;, \u0026#39;A2\u0026#39;, \u0026#39;B1\u0026#39;, \u0026#39;B2\u0026#39;, \u0026#39;C1\u0026#39;, \u0026#39;C2\u0026#39;] # 三重循环 combinations = [a + b + c for a in \u0026#39;AB\u0026#39; for b in \u0026#39;12\u0026#39; for c in \u0026#39;xy\u0026#39;] print(combinations) # [\u0026#39;A1x\u0026#39;, \u0026#39;A1y\u0026#39;, \u0026#39;A2x\u0026#39;, \u0026#39;A2y\u0026#39;, \u0026#39;B1x\u0026#39;, \u0026#39;B1y\u0026#39;, \u0026#39;B2x\u0026#39;, \u0026#39;B2y\u0026#39;] 1.7 嵌套列表推导式（矩阵转置） # 矩阵转置 matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] # 传统方式 transposed = [] for i in range(3): row = [] for j in range(3): row.append(matrix[j][i]) transposed.append(row) # 列表推导式 transposed = [[matrix[j][i] for j in range(3)] for i in range(3)] print(transposed) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]] 1.8 列表推导式 VS 循环的性能对比 import time # 测试数据量 n = 10000 # 方法1：for 循环 start = time.time() result1 = [] for x in range(n): result1.append(x ** 2) time1 = time.time() - start # 方法2：列表推导式 start = time.time() result2 = [x ** 2 for x in range(n)] time2 = time.time() - start print(f\u0026#34;for 循环耗时: {time1:.4f} 秒\u0026#34;) print(f\u0026#34;列表推导式耗时: {time2:.4f} 秒\u0026#34;) print(f\u0026#34;列表推导式比 for 循环快约 {time1/time2:.2f} 倍\u0026#34;) 二、enumerate 函数 2.1 enumerate 的基本用法 enumerate() 函数用于将一个可迭代对象组合为一个索引序列，同时返回索引和值。这在需要遍历列表并需要索引时非常有用。\nenumerate(iterable, start=0) iterable：可迭代对象 start：起始索引，默认为 0 返回一个 enumerate 对象（可迭代） # 基本用法 fruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;, \u0026#34;葡萄\u0026#34;] for index, fruit in enumerate(fruits): print(f\u0026#34;{index}: {fruit}\u0026#34;) # 输出: # 0: 苹果 # 1: 香蕉 # 2: 橙子 # 3: 葡萄 2.2 自定义起始索引 # 从 1 开始编号 fruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;, \u0026#34;葡萄\u0026#34;] for index, fruit in enumerate(fruits, start=1): print(f\u0026#34;{index}: {fruit}\u0026#34;) # 输出: # 1: 苹果 # 2: 香蕉 # 3: 橙子 # 4: 葡萄 2.3 enumerate 的返回值 fruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;] # enumerate 返回的是枚举对象 enum_obj = enumerate(fruits) print(enum_obj) # \u0026lt;enumerate object at 0x...\u0026gt; # 转换为列表 enum_list = list(enumerate(fruits)) print(enum_list) # [(0, \u0026#39;苹果\u0026#39;), (1, \u0026#39;香蕉\u0026#39;), (2, \u0026#39;橙子\u0026#39;)] # 使用 next() 逐个获取 enum_obj = enumerate(fruits) print(next(enum_obj)) # (0, \u0026#39;苹果\u0026#39;) print(next(enum_obj)) # (1, \u0026#39;香蕉\u0026#39;) print(next(enum_obj)) # (2, \u0026#39;橙子\u0026#39;) 2.4 enumerate 的实际应用 # 应用1：带行号显示文件内容 lines = [\u0026#34;第一行内容\u0026#34;, \u0026#34;第二行内容\u0026#34;, \u0026#34;第三行内容\u0026#34;] for line_num, line in enumerate(lines, 1): print(f\u0026#34;{line_num:3d} | {line}\u0026#34;) # 应用2：查找元素位置 numbers = [10, 25, 30, 45, 50, 65, 70] target = 30 for index, num in enumerate(numbers): if num == target: print(f\u0026#34;找到 {target} 在索引 {index} 位置\u0026#34;) break # 应用3：列表中元素出现的位置 words = [\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;apple\u0026#34;, \u0026#34;cherry\u0026#34;, \u0026#34;apple\u0026#34;] positions = [i for i, word in enumerate(words) if word == \u0026#34;apple\u0026#34;] print(f\u0026#34;\u0026#39;apple\u0026#39; 出现的位置: {positions}\u0026#34;) # [0, 2, 4] # 应用4：enumerate 与 zip 结合 names = [\u0026#34;张三\u0026#34;, \u0026#34;李四\u0026#34;, \u0026#34;王五\u0026#34;] scores = [85, 92, 88] for index, (name, score) in enumerate(zip(names, scores), 1): print(f\u0026#34;第{index}名: {name} - {score}分\u0026#34;) # 应用5：带条件筛选 numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] print(\u0026#34;偶数的索引:\u0026#34;, [i for i, n in enumerate(numbers) if n % 2 == 0]) 2.5 enumerate 的原理模拟 # 手动实现 enumerate 的功能 def my_enumerate(iterable, start=0): \u0026#34;\u0026#34;\u0026#34;模拟 enumerate 函数\u0026#34;\u0026#34;\u0026#34; n = start for item in iterable: yield n, item n += 1 # 测试 fruits = [\u0026#34;苹果\u0026#34;, \u0026#34;香蕉\u0026#34;, \u0026#34;橙子\u0026#34;] for index, fruit in my_enumerate(fruits, 1): print(f\u0026#34;{index}: {fruit}\u0026#34;) 三、zip 函数 3.1 zip 的基本用法 zip() 函数用于将多个可迭代对象并行打包成元组序列，返回一个 zip 对象。\nzip(*iterables, strict=False) *iterables：一个或多个可迭代对象 strict：Python 3.10+ 引入，如果为 True，则要求所有可迭代对象长度相同 返回一个 zip 对象 # 基本用法 names = [\u0026#34;张三\u0026#34;, \u0026#34;李四\u0026#34;, \u0026#34;王五\u0026#34;] ages = [25, 30, 28] # 打包成元组列表 zipped = list(zip(names, ages)) print(zipped) # [(\u0026#39;张三\u0026#39;, 25), (\u0026#39;李四\u0026#39;, 30), (\u0026#39;王五\u0026#39;, 28)] # 遍历并行数据 for name, age in zip(names, ages): print(f\u0026#34;{name} 的年龄是 {age}\u0026#34;) # 解压 zipped = [(\u0026#39;张三\u0026#39;, 25), (\u0026#39;李四\u0026#39;, 30), (\u0026#39;王五\u0026#39;, 28)] names, ages = zip(*zipped) print(names) # (\u0026#39;张三\u0026#39;, \u0026#39;李四\u0026#39;, \u0026#39;王五\u0026#39;) print(ages) # (25, 30, 28) 3.2 zip 处理多个可迭代对象 # 两个可迭代对象 a = [1, 2, 3] b = [4, 5, 6] print(list(zip(a, b))) # [(1, 4), (2, 5), (3, 6)] # 三个可迭代对象 x = [1, 2, 3] y = [4, 5, 6] z = [7, 8, 9] print(list(zip(x, y, z))) # [(1, 4, 7), (2, 5, 8), (3, 6, 9)] # 字符串也可以作为可迭代对象 name = \u0026#34;Python\u0026#34; numbers = [1, 2, 3, 4, 5, 6] print(list(zip(name, numbers))) # [(\u0026#39;P\u0026#39;, 1), (\u0026#39;y\u0026#39;, 2), (\u0026#39;t\u0026#39;, 3), (\u0026#39;h\u0026#39;, 4), (\u0026#39;o\u0026#39;, 5), (\u0026#39;n\u0026#39;, 6)] 3.3 处理不同长度的可迭代对象 # 默认行为：取最短长度 list1 = [1, 2, 3, 4, 5] list2 = [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] result = list(zip(list1, list2)) print(result) # [(1, \u0026#39;a\u0026#39;), (2, \u0026#39;b\u0026#39;), (3, \u0026#39;c\u0026#39;)] # Python 3.10+ strict 参数 list1 = [1, 2, 3, 4, 5] list2 = [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] # strict=False (默认) - 不报错，取最短 result = list(zip(list1, list2, strict=False)) print(result) # [(1, \u0026#39;a\u0026#39;), (2, \u0026#39;b\u0026#39;), (3, \u0026#39;c\u0026#39;)] # strict=True - 如果长度不同，抛出 ValueError # result = list(zip(list1, list2, strict=True)) # ValueError: zip() argument 2 is shorter than argument 1 # itertools.zip_longest - 取最长长度，不足用 None 填充 from itertools import zip_longest list1 = [1, 2, 3, 4, 5] list2 = [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] result = list(zip_longest(list1, list2, fillvalue=\u0026#39;x\u0026#39;)) print(result) # [(1, \u0026#39;a\u0026#39;), (2, \u0026#39;b\u0026#39;), (3, \u0026#39;c\u0026#39;), (4, \u0026#39;x\u0026#39;), (5, \u0026#39;x\u0026#39;)] 3.4 zip 的实际应用 # 应用1：创建字典 keys = [\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;, \u0026#39;city\u0026#39;] values = [\u0026#39;张三\u0026#39;, 25, \u0026#39;北京\u0026#39;] # 方法1：dict() 直接转换 d = dict(zip(keys, values)) print(d) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;} # 方法2：字典推导式 d = {k: v for k, v in zip(keys, values)} print(d) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;} # 应用2：同时遍历多个列表 names = [\u0026#34;张三\u0026#34;, \u0026#34;李四\u0026#34;, \u0026#34;王五\u0026#34;] math_scores = [85, 92, 78] eng_scores = [90, 88, 95] for name, math, eng in zip(names, math_scores, eng_scores): avg = (math + eng) / 2 print(f\u0026#34;{name}: 数学={math}, 英语={eng}, 平均={avg:.1f}\u0026#34;) # 应用3：矩阵转置（再次演示） matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] transposed = list(zip(*matrix)) print(transposed) # [(1, 4, 7), (2, 5, 8), (3, 6, 9)] # 应用4：分组 letters = [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;, \u0026#39;d\u0026#39;, \u0026#39;e\u0026#39;, \u0026#39;f\u0026#39;] for i, (a, b) in enumerate(zip(letters[::2], letters[1::2]), 1): print(f\u0026#34;第{i}组: {a}, {b}\u0026#34;) # 第1组: a, b # 第2组: c, d # 第3组: e, f # 应用5：解压缩（unzip） zipped = [(1, \u0026#39;a\u0026#39;), (2, \u0026#39;b\u0026#39;), (3, \u0026#39;c\u0026#39;)] numbers, letters = zip(*zipped) print(numbers) # (1, 2, 3) print(letters) # (\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;) 3.5 zip_longest（ itertools 模块） from itertools import zip_longest # 不同长度列表的组合 list1 = [1, 2, 3, 4, 5] list2 = [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] # 使用 zip_longest result = list(zip_longest(list1, list2, fillvalue=None)) print(result) # [(1, \u0026#39;a\u0026#39;), (2, \u0026#39;b\u0026#39;), (3, \u0026#39;c\u0026#39;), (4, None), (5, None)] # 实用场景：合并学生成绩（有的学生缺考） student_ids = [\u0026#39;S001\u0026#39;, \u0026#39;S002\u0026#39;, \u0026#39;S003\u0026#39;, \u0026#39;S004\u0026#39;] midterm_scores = [85, None, 92, 78] final_scores = [88, 95, None, 82] for sid, mid, final in zip_longest(student_ids, midterm_scores, final_scores, fillvalue=0): mid_display = mid if mid is not None else \u0026#34;缺考\u0026#34; final_display = final if final is not None else \u0026#34;缺考\u0026#34; print(f\u0026#34;{sid}: 期中={mid_display}, 期末={final_display}\u0026#34;) 四、三者的综合应用 4.1 enumerate + zip 组合 # 场景：打印学生成绩表，有序号 students = [\u0026#34;张三\u0026#34;, \u0026#34;李四\u0026#34;, \u0026#34;王五\u0026#34;, \u0026#34;赵六\u0026#34;] math_scores = [85, 92, 78, 88] eng_scores = [90, 88, 95, 76] print(\u0026#34;序号 | 姓名 | 数学 | 英语 | 总分\u0026#34;) print(\u0026#34;-\u0026#34; * 40) for index, (name, math, eng) in enumerate(zip(students, math_scores, eng_scores), 1): total = math + eng print(f\u0026#34;{index:3d} | {name:4s} | {math:3d} | {eng:3d} | {total:3d}\u0026#34;) 4.2 列表推导式 + enumerate # 找出列表中所有偶数的索引 numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] even_indices = [i for i, n in enumerate(numbers) if n % 2 == 0] print(f\u0026#34;偶数的索引: {even_indices}\u0026#34;) # [1, 3, 5, 7, 9] # 带原始值的转换 values = [\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;cherry\u0026#34;] indexed = [(i, v.upper()) for i, v in enumerate(values)] print(indexed) # [(0, \u0026#39;APPLE\u0026#39;), (1, \u0026#39;BANANA\u0026#39;), (2, \u0026#39;CHERRY\u0026#39;)] # 生成下拉选项 HTML options = [\u0026#34;北京\u0026#34;, \u0026#34;上海\u0026#34;, \u0026#34;广州\u0026#34;, \u0026#34;深圳\u0026#34;] html_options = \u0026#34;\\n\u0026#34;.join( f\u0026#39;\u0026lt;option value=\u0026#34;{i}\u0026#34;\u0026gt;{city}\u0026lt;/option\u0026gt;\u0026#39; for i, city in enumerate(options) ) print(html_options) 4.3 列表推导式 + zip # 合并两个列表，值相乘 list1 = [1, 2, 3, 4] list2 = [5, 6, 7, 8] product = [a * b for a, b in zip(list1, list2)] print(product) # [5, 12, 21, 32] # 计算每行的平均值 names = [\u0026#34;张三\u0026#34;, \u0026#34;李四\u0026#34;, \u0026#34;王五\u0026#34;] scores_math = [85, 92, 78] scores_eng = [90, 88, 95] scores_avg = [(m + e) / 2 for m, e in zip(scores_math, scores_eng)] print(dict(zip(names, scores_avg))) # {\u0026#39;张三\u0026#39;: 87.5, \u0026#39;李四\u0026#39;: 90.0, \u0026#39;王五\u0026#39;: 86.5} 4.4 enumerate + zip + 列表推导式 综合 # 场景：生成带序号的菜单 menu_items = [\u0026#34;宫保鸡丁\u0026#34;, \u0026#34;鱼香肉丝\u0026#34;, \u0026#34;麻婆豆腐\u0026#34;, \u0026#34;回锅肉\u0026#34;] prices = [38, 32, 28, 35] categories = [\u0026#34;热菜\u0026#34;, \u0026#34;热菜\u0026#34;, \u0026#34;热菜\u0026#34;, \u0026#34;热菜\u0026#34;] menu = [ f\u0026#34;{idx:2d}. [{cat}] {item:\u0026lt;10s} ¥{price:5.1f}\u0026#34; for idx, (item, price, cat) in enumerate( zip(menu_items, prices, categories), 1 ) ] for line in menu: print(line) # 输出: # 1. [热菜] 宫保鸡丁 ¥ 38.0 # 2. [热菜] 鱼香肉丝 ¥ 32.0 # 3. [热菜] 麻婆豆腐 ¥ 28.0 # 4. [热菜] 回锅肉 ¥ 35.0 4.5 实战：数据转换 # 将数据库查询结果转换为字典列表 raw_data = [ (\u0026#34;张三\u0026#34;, 25, \u0026#34;北京\u0026#34;), (\u0026#34;李四\u0026#34;, 30, \u0026#34;上海\u0026#34;), (\u0026#34;王五\u0026#34;, 28, \u0026#34;广州\u0026#34;), ] fields = [\u0026#34;name\u0026#34;, \u0026#34;age\u0026#34;, \u0026#34;city\u0026#34;] # 方法1：列表推导式 + zip result = [ {k: v for k, v in zip(fields, row)} for row in raw_data ] print(result) # [{\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;}, # {\u0026#39;name\u0026#39;: \u0026#39;李四\u0026#39;, \u0026#39;age\u0026#39;: 30, \u0026#39;city\u0026#39;: \u0026#39;上海\u0026#39;}, # {\u0026#39;name\u0026#39;: \u0026#39;王五\u0026#39;, \u0026#39;age\u0026#39;: 28, \u0026#39;city\u0026#39;: \u0026#39;广州\u0026#39;}] # 方法2：使用 enumerate result = [] for i, row in enumerate(raw_data): item = {} for j, value in enumerate(row): item[fields[j]] = value result.append(item) print(result) 五、生成器表达式 5.1 生成器表达式 vs 列表推导式 生成器表达式与列表推导式语法类似，但使用圆括号，返回生成器对象而不是列表。\n# 列表推导式 - 返回列表 squares_list = [x ** 2 for x in range(10)] print(squares_list) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] print(type(squares_list)) # \u0026lt;class \u0026#39;list\u0026#39;\u0026gt; # 生成器表达式 - 返回生成器 squares_gen = (x ** 2 for x in range(10)) print(squares_gen) # \u0026lt;generator object \u0026lt;genexpr\u0026gt; at 0x...\u0026gt; print(list(squares_gen)) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 5.2 生成器的优势 生成器是惰性求值的，只有在迭代时才生成值，因此：\n节省内存：不需要一次性存储所有元素 适合大数据：可以处理无限序列或超大序列 import sys # 列表 vs 生成器的内存占用 list_comp = [x ** 2 for x in range(10000)] gen_exp = (x ** 2 for x in range(10000)) print(f\u0026#34;列表大小: {sys.getsizeof(list_comp)} bytes\u0026#34;) # ~88KB print(f\u0026#34;生成器大小: {sys.getsizeof(gen_exp)} bytes\u0026#34;) # ~200 bytes # 生成器适合大数据处理 def process_large_file(filename): \u0026#34;\u0026#34;\u0026#34;模拟处理大文件\u0026#34;\u0026#34;\u0026#34; with open(filename, \u0026#39;r\u0026#39;) as f: # 使用生成器逐行处理，节省内存 lines = (line.strip() for line in f) for line in lines: # 处理每一行 pass # 斐波那契数列生成器 def fibonacci(n): \u0026#34;\u0026#34;\u0026#34;生成前 n 个斐波那契数\u0026#34;\u0026#34;\u0026#34; a, b = 0, 1 for _ in range(n): yield a a, b = b, a + b fibs = list(fibonacci(10)) print(fibs) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] 5.3 其他推导式 # 集合推导式 { x ** 2 for x in range(10) } # {0, 1, 4, 9, 16, 25, 36, 49, 64, 81} # 字典推导式 { x: x ** 2 for x in range(5) } # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} # 使用 zip 的字典推导式 keys = [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] values = [1, 2, 3] { k: v for k, v in zip(keys, values) } # {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 2, \u0026#39;c\u0026#39;: 3} # 嵌套推导式 matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] flatten = {x for row in matrix for x in row} # {1, 2, 3, 4, 5, 6, 7, 8, 9} 六、常见错误与最佳实践 6.1 常见错误 # 错误1：在列表推导式中使用变量赋值 # x = [i = i + 1 for i in range(5)] # 语法错误！ # 正确写法 result = [i + 1 for i in range(5)] # [1, 2, 3, 4, 5] # 错误2：if-else 位置混淆 numbers = [1, 2, 3, 4, 5] # 错误：表达式写前面了，但用的是 if 而不是 else # result = [n if n \u0026gt; 3 for n in numbers] # 语法错误！ # 正确：筛选用 if，变换用 if-else result1 = [n for n in numbers if n \u0026gt; 3] # [4, 5] - 筛选 result2 = [n if n \u0026gt; 3 else 0 for n in numbers] # [0, 0, 0, 4, 5] - 变换 # 错误3：过度使用列表推导式导致代码难懂 # 不推荐：过于复杂的列表推导式 # result = [[x for x in row if x \u0026gt; 0] for row in matrix if sum(row) \u0026gt; 10] # 推荐：分步处理 # positive_rows = [row for row in matrix if sum(row) \u0026gt; 10] # result = [[x for x in row if x \u0026gt; 0] for row in positive_rows] 6.2 最佳实践 # 1. 优先使用列表推导式而不是 for 循环 # 推荐 squares = [x ** 2 for x in range(10)] # 不推荐 squares = [] for x in range(10): squares.append(x ** 2) # 2. 简单筛选用 filter()，复杂逻辑用循环 numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 推荐：简单筛选 evens = [n for n in numbers if n % 2 == 0] # 3. 保持列表推导式简洁，复杂逻辑用循环 # 不推荐：过长的推导式 # result = [func(x, y, z) for x in list1 for y in list2 for z in list3 if condition(x, y)] # 推荐：使用循环或分步处理 # result = [] # for x in list1: # for y in list2: # for z in list3: # if condition(x, y): # result.append(func(x, y, z)) # 4. 注意空列表和空字符串的处理 word = \u0026#34;\u0026#34; # 不会报错 chars = [c for c in word] # [] print(chars) # [] 背诵版（核心要点） ┌─────────────────────────────────────────────────────────────┐ │ 列表推导式 / enumerate / zip - 背诵版 │ ├─────────────────────────────────────────────────────────────┤ │ 【列表推导式】 │ │ [expr for x in iterable] 基本形式 │ │ [expr for x in iterable if cond] 带筛选 │ │ [expr1 if cond else expr2 for x] 带分支变换 │ │ [x for x in a for y in b] 双重循环 │ │ [[x for x in row] for row in matrix] 嵌套推导式 │ │ │ │ 【enumerate】 │ │ for i, v in enumerate(seq, start=0) 基本遍历 │ │ list(enumerate(seq)) 转为列表 │ │ [i for i, v in enumerate(...) if...] 找索引 │ │ │ │ 【zip】 │ │ list(zip(seq1, seq2)) 打包成元组 │ │ *zip(*zipped) 解包 │ │ dict(zip(keys, values)) 创建字典 │ │ zip_longest(a, b, fillvalue=None) 长度不同时 │ │ │ │ 【生成器表达式】 │ │ (x for x in iterable) 惰性求值 │ └─────────────────────────────────────────────────────────────┘ 考前记忆（速记口诀） 【列表推导式七字诀】 列表推导一行完，表达式放最前面 for 变量 in 可迭代，if 条件放后面 if else 要注意，else 放在表达式位 双重循环内外层，嵌套列表用它对 【enumerate 速记】 enumerate 是枚举，索引值对一起出 start 参数调起始，zip 配合最威武 【zip 速记】 zip 就是拉链，合并多个可迭代 默认最短为准，zip_longest 补 None 星号 * 来解包，切片打包全靠它 测试题 一、选择题 下面哪个是合法的列表推导式？\nA. [x for x in range(5)] B. [x for x in range(5) if x \u0026gt; 2 if x \u0026lt; 4] C. [x if x \u0026gt; 2 for x in range(5)] D. A 和 B 都正确 enumerate([\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;, \u0026quot;c\u0026quot;]) 返回的结果是？\nA. [\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;, \u0026quot;c\u0026quot;] B. [(0, \u0026quot;a\u0026quot;), (1, \u0026quot;b\u0026quot;), (2, \u0026quot;c\u0026quot;)] C. {0: \u0026quot;a\u0026quot;, 1: \u0026quot;b\u0026quot;, 2: \u0026quot;c\u0026quot;} D. \u0026quot;abc\u0026quot; list(zip([1, 2], [\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;], [\u0026quot;甲\u0026quot;, \u0026quot;乙\u0026quot;])) 的结果是？\nA. [(1, 2), (\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;), (\u0026quot;甲\u0026quot;, \u0026quot;乙\u0026quot;)] B. [(1, \u0026quot;a\u0026quot;, \u0026quot;甲\u0026quot;), (2, \u0026quot;b\u0026quot;, \u0026quot;乙\u0026quot;)] C. [(1, \u0026quot;a\u0026quot;), (2, \u0026quot;b\u0026quot;), (\u0026quot;甲\u0026quot;, \u0026quot;乙\u0026quot;)] D. [(1, \u0026quot;a\u0026quot;, \u0026quot;甲\u0026quot;, 2, \u0026quot;b\u0026quot;, \u0026quot;乙\u0026quot;)] 列表推导式 [x ** 2 for x in range(5)] 的结果是？\nA. [0, 1, 4, 9, 16] B. [1, 4, 9, 16, 25] C. [0, 1, 4, 9, 16, 25] D. [1, 4, 9, 16] enumerate 函数的第二个参数用于设置什么？\nA. 步长 B. 起始索引 C. 结束索引 D. 元素个数 关于生成器表达式和列表推导式的区别，正确的是？\nA. 语法完全相同 B. 生成器用圆括号，列表推导式用方括号 C. 生成器返回列表 D. 列表推导式返回生成器 [*zip([1, 2], [\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;])] 的结果是？\nA. [(1, \u0026quot;a\u0026quot;), (2, \u0026quot;b\u0026quot;)] B. [[1, 2], [\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;]] C. [(1, 2), (\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;)] D. [[1, \u0026quot;a\u0026quot;], [2, \u0026quot;b\u0026quot;]] [x for x in range(10) if x % 2 == 0 if x \u0026gt; 4] 的结果是？\nA. [0, 2, 4, 6, 8] B. [6, 8] C. [5, 6, 7, 8, 9] D. [0, 2, 4] zip([1, 2, 3], [\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;]) 的结果长度是？\nA. 3 B. 2 C. 5 D. 6 {x: x**2 for x in range(3)} 的结果是？\nA. {0: 0, 1: 1, 2: 4} B. {0: 1, 1: 2, 2: 3} C. [0, 1, 4] D. {0: 0, 1: 1, 2: 2} 二、填空题 列表推导式的基本语法格式是 [_____ for 变量 in 可迭代对象]。\nenumerate 函数返回的是一个 _____ 对象。\nzip 函数将多个可迭代对象打包成 _____ 序列。\n在列表推导式中，if 条件 放在 for 循环的 _____ （前面/后面）。\n生成器表达式使用 _____ 括号，而列表推导式使用 _____ 括号。\nlist(zip(*[(1, 2), (3, 4)])) 的结果是 _____ 。\n要将 [\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;, \u0026quot;c\u0026quot;] 转为 [(0, \u0026quot;a\u0026quot;), (1, \u0026quot;b\u0026quot;), (2, \u0026quot;c\u0026quot;)]，应使用 _____ 函数。\n[*range(3)] 的结果是 _____ 。\n在 Python 3.10 中，zip() 函数的 _____ 参数要求所有可迭代对象长度相同。\n{x for x in \u0026quot;hello\u0026quot;} 的结果是 _____ （填具体值）。\n三、编程题 使用列表推导式生成一个 5x5 的单位矩阵（二维列表，对角线为1，其余为0）。\n使用 enumerate 和 zip 写一个函数 pair_sum(seq1, seq2)，返回两个序列对应位置元素之和的列表。\n使用列表推导式实现 flatten([[1, 2], [3, 4], [5, 6]])，将嵌套列表展平为 [1, 2, 3, 4, 5, 6]。\n使用 zip 实现一个函数 transpose(matrix)，将矩阵转置。\n答案见下页\n测试题答案 选择题答案 题号 答案 解析 1 D A 和 B 都是合法的列表推导式；C 语法错误（if 放前面需要 else） 2 B enumerate 返回索引-值对 3 B zip 并行打包三个列表 4 A range(5) 生成 0-4，平方后得到 5 B start 参数设置起始索引，默认为 0 6 B 圆括号 vs 方括号；生成器返回生成器对象 7 A * 解包 zip 结果，外层加 [] 转为列表 8 B 先筛选偶数 (0,2,4,6,8)，再筛选大于 4，结果 (6,8) 9 B zip 取最短长度，所以是 2 10 A 字典推导式，key 是 x，value 是 x² 填空题答案 表达式 enumerate 元组 后面 圆 / 方 [(1, 3), (2, 4)] enumerate [0, 1, 2] strict {\u0026lsquo;h\u0026rsquo;, \u0026rsquo;e\u0026rsquo;, \u0026rsquo;l\u0026rsquo;, \u0026lsquo;o\u0026rsquo;}（去重后的字符集合） 编程题答案 答案1：生成单位矩阵\n# 方法1：列表推导式 identity = [[1 if i == j else 0 for j in range(5)] for i in range(5)] for row in identity: print(row) # 方法2：利用列表特点 identity = [[0]*i + [1] + [0]*(5-i-1) for i in range(5)] 答案2：对位求和\ndef pair_sum(seq1, seq2): \u0026#34;\u0026#34;\u0026#34;对应位置元素求和\u0026#34;\u0026#34;\u0026#34; return [a + b for a, b in zip(seq1, seq2)] # 测试 print(pair_sum([1, 2, 3], [4, 5, 6])) # [5, 7, 9] print(pair_sum(\u0026#34;abc\u0026#34;, \u0026#34;123\u0026#34;)) # [\u0026#39;a1\u0026#39;, \u0026#39;b2\u0026#39;, \u0026#39;c3\u0026#39;] 答案3：展平嵌套列表\ndef flatten(nested_list): \u0026#34;\u0026#34;\u0026#34;将嵌套列表展平\u0026#34;\u0026#34;\u0026#34; return [item for sublist in nested_list for item in sublist] # 测试 print(flatten([[1, 2], [3, 4], [5, 6]])) # [1, 2, 3, 4, 5, 6] print(flatten([[1, 2, 3], [4, 5], [6, 7, 8, 9]])) # [1, 2, 3, 4, 5, 6, 7, 8, 9] 答案4：矩阵转置\ndef transpose(matrix): \u0026#34;\u0026#34;\u0026#34;矩阵转置\u0026#34;\u0026#34;\u0026#34; return [list(row) for row in zip(*matrix)] # 测试 matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] print(transpose(matrix)) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]] 课后练习建议 使用列表推导式实现冒泡排序 使用 enumerate 模拟 range(len(seq)) 的用法 使用 zip 实现一个简单的字典更新函数 挑战：实现一个生成器函数，生成指定范围内的所有质数 本课程完结\n","description":"深入学习Python列表推导式、enumerate和zip函数的高效用法","permalink":"https://blog.uuworld.cn/python-course/python-day-14-list-comprehension/","summary":"\u003ch1 id=\"python-day-14---列表推导式-enumerate-zip\"\u003ePython Day 14 - 列表推导式 enumerate zip\u003c/h1\u003e\n\u003ch2 id=\"课程概述\"\u003e课程概述\u003c/h2\u003e\n\u003cp\u003e本节课将深入学习 Python 中三个非常重要的高级特性：\u003cstrong\u003e列表推导式（List Comprehension）\u003c/strong\u003e、\u003cstrong\u003eenumerate 函数\u003c/strong\u003e和 \u003cstrong\u003ezip 函数\u003c/strong\u003e。这些特性可以让你的代码更加简洁、高效和 Pythonic。\u003c/p\u003e\n\u003cp\u003e本课程基于 \u003cstrong\u003ePython 3.11\u003c/strong\u003e 编写，所有示例均经过验证。在 Python 3.11 中，这些特性都得到全面支持且运行效率进一步提升。\u003c/p\u003e\n\u003cp\u003e列表推导式是 Python 最具特色的语法之一，它允许你用一行代码就创建一个完整的列表。enumerate 函数为可迭代对象添加了索引，而 zip 函数则可以将多个可迭代对象组合在一起。掌握这三个工具，将大大提高你的 Python 编程能力。\u003c/p\u003e\n\u003ch2 id=\"一列表推导式list-comprehension\"\u003e一、列表推导式（List Comprehension）\u003c/h2\u003e\n\u003ch3 id=\"11-什么是列表推导式\"\u003e1.1 什么是列表推导式\u003c/h3\u003e\n\u003cp\u003e列表推导式是一种简洁、高效创建列表的方式。它的语法来自数学中的集合定义式（Set Builder Notation）。传统方式创建列表需要多行代码，而列表推导式可以用一行完成。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 传统方式：使用 for 循环创建列表\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esquares \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e x \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    squares\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(x \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(squares)  \u003cspan style=\"color:#75715e\"\u003e# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 列表推导式：一行完成\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esquares \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [x \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e x \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e)]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(squares)  \u003cspan style=\"color:#75715e\"\u003e# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"12-列表推导式的基本语法\"\u003e1.2 列表推导式的基本语法\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[表达式 \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e 变量 \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e 可迭代对象]\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e表达式\u003c/strong\u003e：对 \u003ccode\u003e变量\u003c/code\u003e 进行操作的结果\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003efor 变量 in 可迭代对象\u003c/strong\u003e：从可迭代对象中遍历每个元素\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 基本示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enumbers \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edoubled \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [n \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e n \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e numbers]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(doubled)  \u003cspan style=\"color:#75715e\"\u003e# [2, 4, 6, 8, 10]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 对字符串操作\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewords \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;hello\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;world\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;python\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eupper_words \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [w\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eupper() \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e w \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e words]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(upper_words)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;HELLO\u0026#39;, \u0026#39;WORLD\u0026#39;, \u0026#39;PYTHON\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用函数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e math\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eradii \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eareas \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [math\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epi \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e r \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e r \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e radii]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(areas)  \u003cspan style=\"color:#75715e\"\u003e# [3.14159..., 12.566..., 28.274..., 50.265..., 78.539...]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"13-带条件的列表推导式\"\u003e1.3 带条件的列表推导式\u003c/h3\u003e\n\u003cp\u003e可以在列表推导式中添加 \u003ccode\u003eif\u003c/code\u003e 条件筛选元素。\u003c/p\u003e","tags":"Python, 列表推导式, enumerate, zip, 高阶函数","title":"Python Day 14 - 列表推导式 enumerate zip"},{"columns":"acp-course","content":" 来源：Notion ACP学习笔记 + 阿里云开发者社区 + 网络资料整理\n一、详细讲解 1.1 弹性伸缩概述 弹性伸缩（Auto Scaling）：根据业务负载自动调整计算资源（ECS 实例数量）的功能，实现\u0026quot;用多少扩多少，不用就缩回去\u0026quot;。\n为什么需要弹性伸缩：\n成本优化：波峰扩容、波谷缩容，避免资源浪费 应对突发流量：大促、活动等场景下自动承接流量 保证可用性：负载高时自动扩容，避免服务崩溃 减少人工干预：规则驱动，7×24 小时无人值守 1.2 阿里云弹性伸缩核心概念（重点） 伸缩组（Scaling Group） 伸缩组是弹性伸缩的核心管理单元，包含以下要素：\n要素 说明 最小实例数 伸缩组始终保持的最小实例数量 最大实例数 伸缩组允许扩容到的最大实例数量 期望实例数 伸缩组当前期望维持的实例数量 默认实例数 伸缩组创建时自动创建的实例数量 伸缩配置（Scaling Configuration） 定义创建新 ECS 实例的规格：\n实例规格（vCPU / 内存） 镜像（操作系统） 安全组 弹性网卡 实例存储 伸缩规则（Scaling Rule） 规则类型 说明 示例 简单规则 直接指定目标实例数或调整量 +1 台、-2 台、调整到 5 台 步进规则 按负载分层递进调整 CPU \u0026gt; 80% 时 +3 台，\u0026gt; 60% 时 +1 台 目标追踪规则 自动维持目标指标 保持平均 CPU 利用率在 60% 伸缩触发任务 触发方式 说明 定时任务 固定时间触发扩缩容（如每晚高峰期提前扩容） 云监控报警任务 指标阈值触发（CPU、内存、QPS 等） 周期任务 周期性重复触发（每天/每周定时） ⚠️ 重要：云监控报警任务是独立于伸缩组存在的，删除伸缩组不会删除报警任务！\n1.3 伸缩流程详解（重点） 自动扩容闭环链路 监控异常（CPU 90%） ↓ 云监控产生报警 ↓ 报警任务触发伸缩规则 ↓ 执行伸缩规则（\u0026#43;3 台） ↓ 从伸缩配置创建新 ECS ↓ 新 ECS 加入 SLB 服务器组 ↓ 流量自动分发到新实例 ↓ 负载下降，稳定在目标值自动缩容闭环链路 负载持续偏低（CPU \u0026lt; 30% 持续 10 分钟） ↓ 云监控产生缩容报警 ↓ 报警任务触发缩容规则 ↓ 移出非保护状态实例 ↓ 实例从 SLB 后端服务器组移除 ↓ 实例进入\u0026#34;节省状态\u0026#34;后释放 ↓ 计费停止1.4 伸缩组与负载均衡（SLB）联动 关键机制：\n伸缩组关联应用型负载均衡（ALB/CLB）的服务器组 扩容时：新建 ECS 自动加入 SLB 服务器组 缩容时：ECS 自动移出 SLB 服务器组 健康检查：SLB 持续检测后端 ECS 健康状态，不健康则自动移出 1.5 弹性伸缩注意事项（高频考点） 注意点 说明 冷却时间 伸缩完成后需要等待冷却时间（默认 300 秒）才能再次触发，避免震荡 实例保护 缩容时，被保护实例不会被移出，可手动取消保护 移出策略 缩容时按策略选择实例：最早创建 / 最新创建 / 最早配置生效 最小实例数 防止缩容过度，保证最小可用实例数 多伸缩规则冲突 同一时间多条规则取最大实例数 1.6 云监控 CloudMonitor 云监控是弹性伸缩的眼睛，提供以下监控能力：\n产品 监控指标 ECS CPU、内存、磁盘、网络 RDS QPS、连接数、CPU/内存利用率 Redis 内存使用率、命中率、QPS OSS 请求次数、流量、延迟 SLB 后端服务器健康状态、活跃连接数 报警通知方式：\n短信 邮件 钉钉机器人 Webhook API callback 1.7 运维实践 弹性架构标准模型 用户请求 ↓ ALB（应用型负载均衡）← 健康检查 ↓ 伸缩组管理的 ECS 集群 ← 自动扩缩 ↓ RDS（关系数据库） ↓ Redis（缓存层）← 弹性扩容不影响高可用设计原则 多可用区部署：伸缩组实例分布在多个可用区，单区故障不影响整体 最小实例数 ≥ 2：保证任何时候都有实例可用 健康检查配置：SLB 健康检查频率和阈值要合理 滚动升级：使用新伸缩配置时，滚动替换旧实例 二、背诵版（Night Before Exam） 弹性伸缩四要素 伸缩组 = 容器，伸缩配置 = 模板，伸缩规则 = 动作，触发任务 = 条件\n扩容闭环 监控报警 → 触发规则 → 创建 ECS → 加入 SLB → 承接流量 → 负载下降\n缩容闭环 负载低 → 触发缩容 → 移出 SLB → 进入保护 → 节省状态 → 释放实例\n报警任务独立性 报警任务是独立的，删除伸缩组不会删除报警任务！这是高频考点！\n关键数字 冷却时间默认 300 秒 / 最小实例数保障下限 / 最大实例数控制上限\n三、速记版（考前 5 分钟回忆） ✅ 弹性伸缩 = 自动调整 ECS 数量 ✅ 伸缩组 = 管理单元（含最小/最大/期望实例数） ✅ 伸缩配置 = 创建新 ECS 的模板（规格、镜像、安全组） ✅ 伸缩规则 = 具体动作（\u0026#43;1/-1/调整到N） ✅ 定时任务 = 固定时间触发 ✅ 云监控报警任务 = 指标阈值触发 ⚠️独立于伸缩组 ✅ 扩容闭环：监控→报警→规则→创建ECS→加入SLB→承接流量 ✅ 冷却时间 = 300秒（默认）= 防止震荡 ✅ 实例保护 = 缩容时不移出 ✅ 移出策略 = 最早创建优先移出（默认） ✅ ALB \u0026#43; AS = 最佳拍档，新实例自动加入SLB ✅ 多可用区 = 单区故障不崩溃 四、测试练习题 单选题 1. 阿里云弹性伸缩的伸缩组中，\u0026ldquo;最大实例数\u0026quot;的作用是？\nA. 保证最小可用实例数 B. 控制扩容上限，防止费用超支 ✅ C. 定义实例规格 D. 设置健康检查阈值 答案：B\n解析：最大实例数控制扩容上限，防止突发流量导致费用失控。\n2. 以下关于云监控报警任务的说法，正确的是？\nA. 删除伸缩组会自动删除关联的报警任务 B. 报警任务独立于伸缩组存在 ✅ C. 报警任务只能触发扩容，不能触发缩容 D. 报警任务和定时任务不能同时配置 答案：B\n解析：这是高频考点！云监控报警任务是独立资源，删除伸缩组不会删除报警任务。\n3. 弹性伸缩的扩容闭环中，新建 ECS 加入 SLB 之前需要完成什么？\nA. 格式化磁盘 B. 安装监控 Agent C. 配置安全组规则 D. 健康检查通过后加入 ✅ 答案：D\n解析：SLB 健康检查通过后，新 ECS 才会正式加入后端服务器组开始承载流量。\n4. 伸缩组的冷却时间（Cooldown）的默认值为？\nA. 60 秒 B. 180 秒 C. 300 秒 ✅ D. 600 秒 答案：C\n解析：默认冷却时间 300 秒（5 分钟），防止频繁扩缩震荡。\n5. 关于伸缩规则的\u0026quot;目标追踪规则\u0026rdquo;，以下描述正确的是？\nA. 需要手动指定调整数量 B. 自动维持指定指标的目标值 ✅ C. 只能追踪 CPU 指标 D. 不需要关联伸缩组 答案：B\n解析：目标追踪规则自动计算需要的实例数量，以维持目标指标（如 CPU 60%）。\n6. 缩容时，移出实例的默认策略是？\nA. 最新创建的实例优先移出 B. 最早创建的实例优先移出 ✅ C. 随机移出 D. 最大规格实例优先移出 答案：B\n解析：默认移出策略是\u0026quot;最早创建\u0026quot;（Oldest Instance）。\n多选题 7. 弹性伸缩的触发任务包括？\nA. 定时任务 ✅ B. 云监控报警任务 ✅ C. 周期任务 ✅ D. 手动触发 ✅ 答案：A、B、C、D\n解析：所有触发方式均支持。\n8. 弹性架构中，ALB（应用型负载均衡）和 AS（弹性伸缩）联动的关键点包括？\nA. 扩容时新 ECS 自动加入 ALB 服务器组 ✅ B. 缩容时 ECS 自动从 ALB 移出 ✅ C. ALB 提供后端 ECS 的健康检查 ✅ D. AS 可以替代 ALB 实现流量分发 答案：A、B、C\n解析：AS 和 ALB 是配合关系，不是替代关系。\n判断题 9. 只要配置了伸缩规则，弹性伸缩就会自动工作，不需要任何触发条件。\nA. 正确 B. 错误 ✅ 答案：B\n解析：伸缩规则需要被触发（定时任务/报警任务）才能执行。\n10. 开启了实例保护功能的 ECS，在缩容时不会被移出。\nA. 正确 ✅ B. 错误 答案：A\n解析：实例保护状态下，缩容规则不会选择该实例移出。\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-14-day14-%E5%BC%B9%E6%80%A7%E4%BC%B8%E7%BC%A9-%E4%BA%91%E6%9E%B6%E6%9E%84%E8%BF%90%E7%BB%B4/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：Notion ACP学习笔记 + 阿里云开发者社区 + 网络资料整理\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-弹性伸缩概述\"\u003e1.1 弹性伸缩概述\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e弹性伸缩（Auto Scaling）\u003c/strong\u003e：根据业务负载自动调整计算资源（ECS 实例数量）的功能，实现\u0026quot;用多少扩多少，不用就缩回去\u0026quot;。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e为什么需要弹性伸缩\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e成本优化\u003c/strong\u003e：波峰扩容、波谷缩容，避免资源浪费\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e应对突发流量\u003c/strong\u003e：大促、活动等场景下自动承接流量\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e保证可用性\u003c/strong\u003e：负载高时自动扩容，避免服务崩溃\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e减少人工干预\u003c/strong\u003e：规则驱动，7×24 小时无人值守\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"12-阿里云弹性伸缩核心概念重点\"\u003e1.2 阿里云弹性伸缩核心概念（重点）\u003c/h3\u003e\n\u003ch4 id=\"伸缩组scaling-group\"\u003e伸缩组（Scaling Group）\u003c/h4\u003e\n\u003cp\u003e伸缩组是弹性伸缩的核心管理单元，包含以下要素：\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e要素\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e最小实例数\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e伸缩组始终保持的最小实例数量\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e最大实例数\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e伸缩组允许扩容到的最大实例数量\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e期望实例数\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e伸缩组当前期望维持的实例数量\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e默认实例数\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e伸缩组创建时自动创建的实例数量\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"伸缩配置scaling-configuration\"\u003e伸缩配置（Scaling Configuration）\u003c/h4\u003e\n\u003cp\u003e定义创建新 ECS 实例的规格：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e实例规格（vCPU / 内存）\u003c/li\u003e\n\u003cli\u003e镜像（操作系统）\u003c/li\u003e\n\u003cli\u003e安全组\u003c/li\u003e\n\u003cli\u003e弹性网卡\u003c/li\u003e\n\u003cli\u003e实例存储\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"伸缩规则scaling-rule\"\u003e伸缩规则（Scaling Rule）\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e规则类型\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n          \u003cth\u003e示例\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e简单规则\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e直接指定目标实例数或调整量\u003c/td\u003e\n          \u003ctd\u003e+1 台、-2 台、调整到 5 台\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e步进规则\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e按负载分层递进调整\u003c/td\u003e\n          \u003ctd\u003eCPU \u0026gt; 80% 时 +3 台，\u0026gt; 60% 时 +1 台\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e目标追踪规则\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e自动维持目标指标\u003c/td\u003e\n          \u003ctd\u003e保持平均 CPU 利用率在 60%\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"伸缩触发任务\"\u003e伸缩触发任务\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e触发方式\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e定时任务\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e固定时间触发扩缩容（如每晚高峰期提前扩容）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e云监控报警任务\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e指标阈值触发（CPU、内存、QPS 等）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e周期任务\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e周期性重复触发（每天/每周定时）\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cstrong\u003e⚠️ 重要\u003c/strong\u003e：\u003cstrong\u003e云监控报警任务是独立于伸缩组存在的，删除伸缩组不会删除报警任务！\u003c/strong\u003e\u003c/p\u003e","tags":"ACP, 阿里云, 弹性伸缩, 运维","title":"Day14 弹性伸缩 + 云架构运维"},{"columns":"","content":"Python Day 15 - 元组 unpacking namedtuple 课程概述 本节课将深入学习 Python 元组（Tuple）这一核心数据结构。元组与列表非常相似，都是有序的序列，但元组具有不可变性，这使得它在某些场景下比列表更安全和高效。\n本课程基于 Python 3.11 编写，所有示例均经过验证。我们将学习元组的基本操作、解包（Unpacking）特性以及 namedtuple 工厂函数的高級用法。\n元组在 Python 中无处不在：函数可以返回多个值、字符串格式化、字典的键必须是不可变对象、数据库记录等等。掌握元组是进阶 Python 编程的必经之路。\n一、元组基础概念 1.1 什么是元组 元组是 Python 中的一种有序、不可变的序列类型。使用圆括号 ( ) 来表示。\n# 元组的基本定义 empty_tuple = () single_tuple = (42,) # 注意：单个元素需要加逗号 multi_tuple = (1, 2, 3, 4, 5) print(type(empty_tuple)) # \u0026lt;class \u0026#39;tuple\u0026#39;\u0026gt; print(type(single_tuple)) # \u0026lt;class \u0026#39;tuple\u0026#39;\u0026gt; print(type(multi_tuple)) # \u0026lt;class \u0026#39;tuple\u0026#39;\u0026gt; 1.2 元组与列表的区别 特性 列表 元组 语法 [1, 2, 3] (1, 2, 3) 可变性 可变（Mutable） 不可变（Immutable） 性能 稍慢（需要维护额外结构） 稍快（更简单） 安全性 可修改，可能被意外改变 不可修改，更安全 用作字典键 否 是 常用场景 需要修改的数据 固定数据、多返回值 # 列表可变 list1 = [1, 2, 3] list1[0] = 100 print(list1) # [100, 2, 3] # 元组不可变 tuple1 = (1, 2, 3) # tuple1[0] = 100 # TypeError: \u0026#39;tuple\u0026#39; object does not support item assignment 1.3 元组的创建方式 # 方法1：使用圆括号 t1 = (1, 2, 3) # 方法2：使用 tuple() 构造函数 t2 = tuple() # 空元组 t3 = tuple([1, 2, 3]) # 从列表转换 t4 = tuple(\u0026#34;abc\u0026#34;) # 从字符串转换 t5 = tuple(range(5)) # 从 range 对象转换 # 方法3：单元素元组必须加逗号 single = (42,) # 正确 not_tuple = (42) # 只是整数 42，不是元组 # 方法4：打包（packing） packed = 1, 2, 3 # 不需要括号 print(packed) # (1, 2, 3) # 方法5：生成器推导式（注意：生成的是元组） gen_tuple = tuple(x ** 2 for x in range(5)) print(gen_tuple) # (0, 1, 4, 9, 16) 二、元组的基本操作 2.1 索引访问 元组支持与列表相同的索引访问方式，包括正索引和负索引。\nt = (0, 1, 2, 3, 4, 5) print(t[0]) # 0 print(t[-1]) # 5 print(t[2:5]) # (2, 3, 4) # 索引越界会报错 # print(t[10]) # IndexError: tuple index out of range 2.2 元组的拼接与重复 # 拼接 t1 = (1, 2, 3) t2 = (4, 5, 6) t3 = t1 + t2 print(t3) # (1, 2, 3, 4, 5, 6) # 重复 t4 = (1, 2) * 3 print(t4) # (1, 2, 1, 2, 1, 2) # 原元组不变（返回新元组） print(t1) # (1, 2, 3) 2.3 元组的查找方法 方法 说明 返回值 tuple.index(x) 返回元素 x 第一次出现的索引 int tuple.count(x) 返回元素 x 出现的次数 int x in tuple 检查元素是否在元组中 bool t = (1, 3, 5, 7, 3, 2, 3) print(t.index(3)) # 1 print(t.count(3)) # 3 print(5 in t) # True print(100 in t) # False 2.4 元组的方法（只有两个！） 元组是不可变的，所以只有 index() 和 count() 两个方法，不像列表有那么多增删改方法。\n# 元组的方法确实只有两个 t = (1, 2, 2, 3, 3, 3) print(dir(t)) # [\u0026#39;__add__\u0026#39;, \u0026#39;__class__\u0026#39;, \u0026#39;__contains__\u0026#39;, \u0026#39;__delattr__\u0026#39;, \u0026#39;__dir__\u0026#39;, # \u0026#39;__doc__\u0026#39;, \u0026#39;__eq__\u0026#39;, \u0026#39;__format__\u0026#39;, \u0026#39;__ge__\u0026#39;, \u0026#39;__getattribute__\u0026#39;, # \u0026#39;__getitem__\u0026#39;, \u0026#39;__getnewargs__\u0026#39;, \u0026#39;__gt__\u0026#39;, \u0026#39;__hash__\u0026#39;, \u0026#39;__init__\u0026#39;, # \u0026#39;__init_subclass__\u0026#39;, \u0026#39;__iter__\u0026#39;, \u0026#39;__le__\u0026#39;, \u0026#39;__len__\u0026#39;, \u0026#39;__lt__\u0026#39;, # \u0026#39;__mul__\u0026#39;, \u0026#39;__ne__\u0026#39;, \u0026#39;__new__\u0026#39;, \u0026#39;__reduce__\u0026#39;, \u0026#39;__reduce_ex__\u0026#39;, # \u0026#39;__repr__\u0026#39;, \u0026#39;__rmul__\u0026#39;, \u0026#39;__setattr__\u0026#39;, \u0026#39;__sizeof__\u0026#39;, \u0026#39;__str__\u0026#39;, # \u0026#39;__subclasshook__\u0026#39;] 三、元组解包（Unpacking） 3.1 基本解包 元组解包允许你将元组中的元素批量赋值给多个变量。\n# 基本解包 point = (10, 20) x, y = point print(f\u0026#34;x = {x}, y = {y}\u0026#34;) # x = 10, y = 20 # 多元素解包 person = (\u0026#34;张三\u0026#34;, 25, \u0026#34;北京\u0026#34;) name, age, city = person print(f\u0026#34;{name}, {age}岁, 住在{city}\u0026#34;) # 张三, 25岁, 住在北京 # 元素数量必须匹配 # a, b = (1, 2, 3) # ValueError: too many values to unpack # a, b, c, d = (1, 2) # ValueError: not enough values to unpack 3.2 使用星号 * 收集多余元素 Python 3 引入了星号表达式，允许解包时收集剩余元素。\n# 使用 * 收集多余元素 numbers = (1, 2, 3, 4, 5) first, *middle, last = numbers print(first) # 1 print(middle) # [2, 3, 4] print(last) # 5 # 第一个和最后一个，中间全部收集 first, *rest = (10, 20, 30, 40, 50) print(first) # 10 print(rest) # [20, 30, 40, 50] # * 在中间位置 *first, a, b = (1, 2, 3, 4, 5) print(first) # [1, 2, 3] print(a, b) # 4 5 # 可以丢弃不需要的值 data = (1, 2, 3, 4, 5) _, _, third, *_ = data print(third) # 3 # 解包字符串 a, b, c = \u0026#34;XYZ\u0026#34; print(a, b, c) # X Y Z 3.3 交换变量 元组解包最优雅的应用之一是无需临时变量即可交换两个变量的值。\n# 传统方式需要临时变量 a = 10 b = 20 temp = a a = b b = temp print(a, b) # 20 10 # 使用元组解包 a = 10 b = 20 a, b = b, a # 一行代码交换！ print(a, b) # 20 10 3.4 解包嵌套结构 # 嵌套元组的解包 nested = ((1, 2), (3, 4)) (a, b), (c, d) = nested print(a, b, c, d) # 1 2 3 4 # 列表嵌套 nested_list = [(1, 2), (3, 4), (5, 6)] for x, y in nested_list: print(f\u0026#34;{x} + {y} = {x + y}\u0026#34;) # 带星号的嵌套 data = (1, (2, 3, 4), 5) a, (b, *c), d = data print(a, b, c, d) # 1 2 [3, 4] 5 3.5 * 操作符的其他用法 # 函数参数解包 def func(a, b, c): print(a, b, c) args = (1, 2, 3) func(*args) # 1 2 3 kwargs = {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 2, \u0026#39;c\u0026#39;: 3} func(**kwargs) # 1 2 3 # 函数定义时的 *args def sum_all(*numbers): total = 0 for n in numbers: total += n return total print(sum_all(1, 2, 3, 4, 5)) # 15 # **kwargs def print_info(**info): for key, value in info.items(): print(f\u0026#34;{key}: {value}\u0026#34;) print_info(name=\u0026#34;张三\u0026#34;, age=25, city=\u0026#34;北京\u0026#34;) 四、元组在函数返回值中的应用 4.1 多返回值函数 Python 函数可以返回多个值（实际上是返回一个元组）。\ndef get_min_max(numbers): \u0026#34;\u0026#34;\u0026#34;返回最小值和最大值\u0026#34;\u0026#34;\u0026#34; return min(numbers), max(numbers) result = get_min_max([3, 1, 4, 1, 5, 9, 2, 6]) print(result) # (1, 9) print(type(result)) # \u0026lt;class \u0026#39;tuple\u0026#39;\u0026gt; # 解包接收 min_val, max_val = get_min_max([3, 1, 4, 1, 5, 9, 2, 6]) print(f\u0026#34;最小值: {min_val}, 最大值: {max_val}\u0026#34;) 4.2 返回多个值的函数设计 def divide(a, b): \u0026#34;\u0026#34;\u0026#34;返回商和余数\u0026#34;\u0026#34;\u0026#34; quotient = a // b remainder = a % b return quotient, remainder q, r = divide(17, 5) print(f\u0026#34;17 = 5 × {q} + {r}\u0026#34;) # 17 = 5 × 3 + 2 # 返回更多值 def stats(numbers): \u0026#34;\u0026#34;\u0026#34;返回统计信息元组\u0026#34;\u0026#34;\u0026#34; n = len(numbers) total = sum(numbers) avg = total / n minimum = min(numbers) maximum = max(numbers) return n, total, avg, minimum, maximum count, total, avg, min_val, max_val = stats([1, 2, 3, 4, 5]) print(f\u0026#34;计数={count}, 总和={total}, 平均={avg}, 最小={min_val}, 最大={max_val}\u0026#34;) 4.3 使用命名元组接收返回值 from collections import namedtuple # 定义命名元组类型 Result = namedtuple(\u0026#39;Result\u0026#39;, [\u0026#39;quotient\u0026#39;, \u0026#39;remainder\u0026#39;]) def divide(a, b): \u0026#34;\u0026#34;\u0026#34;返回命名元组\u0026#34;\u0026#34;\u0026#34; return Result(a // b, a % b) result = divide(17, 5) print(result) # Result(quotient=3, remainder=2) print(result.quotient) # 3 print(result.remainder) # 2 五、namedtuple 详解 5.1 什么是 namedtuple namedtuple 是 Python collections 模块中的一个工厂函数，用于创建类似元组但具有命名字段的类。\nfrom collections import namedtuple # 创建 namedtuple Point = namedtuple(\u0026#39;Point\u0026#39;, [\u0026#39;x\u0026#39;, \u0026#39;y\u0026#39;]) p = Point(10, 20) print(p) # Point(x=10, y=20) print(p.x) # 10 print(p.y) # 20 print(p[0]) # 10（仍可用索引访问） print(p[1]) # 20 5.2 namedtuple 的优势 from collections import namedtuple # 传统元组 - 通过索引访问 student = (\u0026#34;张三\u0026#34;, 25, \u0026#34;计算机科学\u0026#34;, 3.8) print(f\u0026#34;姓名: {student[0]}, GPA: {student[3]}\u0026#34;) # 不直观 # namedtuple - 通过字段名访问 Student = namedtuple(\u0026#39;Student\u0026#39;, [\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;, \u0026#39;major\u0026#39;, \u0026#39;gpa\u0026#39;]) s = Student(\u0026#34;张三\u0026#34;, 25, \u0026#34;计算机科学\u0026#34;, 3.8) print(f\u0026#34;姓名: {s.name}, GPA: {s.gpa}\u0026#34;) # 更直观！ 5.3 namedtuple 的创建方式 from collections import namedtuple # 方式1：字段名作为列表 Point = namedtuple(\u0026#39;Point\u0026#39;, [\u0026#39;x\u0026#39;, \u0026#39;y\u0026#39;]) # 方式2：字段名作为字符串（空格分隔） Point = namedtuple(\u0026#39;Point\u0026#39;, \u0026#39;x y\u0026#39;) # 方式3：使用 make() 方法从可迭代对象创建 data = [10, 20] p = Point._make(data) print(p) # Point(x=10, y=20) # 方式4：字段名验证（包含无效字符时） # Point = namedtuple(\u0026#39;Point\u0026#39;, [\u0026#39;x-coordinate\u0026#39;, \u0026#39;y-coordinate\u0026#39;]) # 错误！ Point = namedtuple(\u0026#39;Point\u0026#39;, [\u0026#39;x\u0026#39;, \u0026#39;y\u0026#39;]) # 正确 5.4 namedtuple 的方法 from collections import namedtuple Student = namedtuple(\u0026#39;Student\u0026#39;, [\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;, \u0026#39;major\u0026#39;, \u0026#39;gpa\u0026#39;]) # 创建实例 s1 = Student(\u0026#34;张三\u0026#34;, 25, \u0026#34;计算机科学\u0026#34;, 3.8) s2 = Student(\u0026#34;李四\u0026#34;, 22, \u0026#34;数学\u0026#34;, 3.5) # _make() - 从可迭代对象创建 data = {\u0026#34;name\u0026#34;: \u0026#34;王五\u0026#34;, \u0026#34;age\u0026#34;: 23, \u0026#34;major\u0026#34;: \u0026#34;物理\u0026#34;, \u0026#34;gpa\u0026#34;: 3.6} s3 = Student._make(data) print(s3) # Student(name=\u0026#39;王五\u0026#39;, age=23, major=\u0026#39;物理\u0026#39;, gpa=3.6) # _asdict() - 转换为有序字典 print(s1._asdict()) # OrderedDict([(\u0026#39;name\u0026#39;, \u0026#39;张三\u0026#39;), (\u0026#39;age\u0026#39;, 25), ...]) # _replace() - 创建修改后的副本（返回新实例） s1_modified = s1._replace(gpa=3.9, age=26) print(s1_modified) # Student(name=\u0026#39;张三\u0026#39;, age=26, major=\u0026#39;计算机科学\u0026#39;, gpa=3.9) print(s1) # 原实例不变！_replace 返回新实例 # _fields - 查看字段名 print(Student._fields) # (\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;, \u0026#39;major\u0026#39;, \u0026#39;gpa\u0026#39;) # _field_defaults - Python 3.7+ 查看默认值 DefaultStudent = namedtuple(\u0026#39;DefaultStudent\u0026#39;, [\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;, \u0026#39;major\u0026#39;, \u0026#39;gpa\u0026#39;], defaults=[\u0026#39;\u0026#39;, 0, \u0026#39;\u0026#39;, 0.0]) print(DefaultStudent._field_defaults) # {\u0026#39;gpa\u0026#39;: 0.0} 5.5 namedtuple 与字典互转 from collections import namedtuple Person = namedtuple(\u0026#39;Person\u0026#39;, [\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;, \u0026#39;city\u0026#39;]) # namedtuple -\u0026gt; dict p = Person(\u0026#34;张三\u0026#34;, 25, \u0026#34;北京\u0026#34;) d = p._asdict() print(d) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;} # dict -\u0026gt; namedtuple d = {\u0026#39;name\u0026#39;: \u0026#39;李四\u0026#39;, \u0026#39;age\u0026#39;: 30, \u0026#39;city\u0026#39;: \u0026#39;上海\u0026#39;} p = Person(**d) # 使用 ** 解包字典 print(p) # Person(name=\u0026#39;李四\u0026#39;, age=30, city=\u0026#39;上海\u0026#39;) 5.6 namedtuple 的实际应用 from collections import namedtuple # 应用1：表示数据库记录 Record = namedtuple(\u0026#39;Record\u0026#39;, [\u0026#39;id\u0026#39;, \u0026#39;name\u0026#39;, \u0026#39;email\u0026#39;, \u0026#39;phone\u0026#39;]) records = [ Record(1, \u0026#34;张三\u0026#34;, \u0026#34;zhang@example.com\u0026#34;, \u0026#34;13800138000\u0026#34;), Record(2, \u0026#34;李四\u0026#34;, \u0026#34;li@example.com\u0026#34;, \u0026#34;13900139000\u0026#34;), ] # 应用2：表示几何图形 Point = namedtuple(\u0026#39;Point\u0026#39;, [\u0026#39;x\u0026#39;, \u0026#39;y\u0026#39;]) Rectangle = namedtuple(\u0026#39;Rectangle\u0026#39;, [\u0026#39;width\u0026#39;, \u0026#39;height\u0026#39;]) def area(rect): return rect.width * rect.height r = Rectangle(10, 5) print(f\u0026#34;矩形面积: {area(r)}\u0026#34;) # 应用3：返回多个值的替代方案 Result = namedtuple(\u0026#39;Result\u0026#39;, [\u0026#39;value\u0026#39;, \u0026#39;status\u0026#39;, \u0026#39;message\u0026#39;]) def divide(a, b): if b == 0: return Result(None, False, \u0026#34;除数不能为零\u0026#34;) return Result(a / b, True, \u0026#34;成功\u0026#34;) result = divide(10, 2) if result.status: print(f\u0026#34;结果是: {result.value}\u0026#34;) else: print(f\u0026#34;错误: {result.message}\u0026#34;) 六、元组的不可变性与注意事项 6.1 不可变性详解 元组的不可变性指的是元组本身的元素引用不能改变，但如果元组包含可变对象（如列表），那些可变对象本身是可以修改的。\n# 尝试修改元组元素会报错 t = (1, 2, 3) # t[0] = 100 # TypeError # 但如果元组包含可变对象 t = (1, [2, 3], 4) print(t) # (1, [2, 3], 4) # 可以修改元组中的列表 t[1].append(100) print(t) # (1, [2, 3, 100], 4) # 注意：这样修改不会改变元组的\u0026#34;身份\u0026#34; print(id(t)) # 不变 6.2 元组作为字典键 由于元组是不可变的，它们可以用作字典的键，而列表不行。\n# 元组作为字典键 d = {} d[(1, 2)] = \u0026#34;点A\u0026#34; d[(3, 4)] = \u0026#34;点B\u0026#34; print(d) # {(1, 2): \u0026#39;点A\u0026#39;, (3, 4): \u0026#39;点B\u0026#39;} # 列表不能作为字典键 # d[[1, 2]] = \u0026#34;test\u0026#34; # TypeError: unhashable type: \u0026#39;list\u0026#39; # 元组中包含列表也不能作为键 # d[(1, [2, 3])] = \u0026#34;test\u0026#34; # TypeError 6.3 元组与集合 元组可以放入集合（Set）中，而列表不行。\n# 元组可以加入集合 s = {(1, 2), (3, 4), (5, 6)} print(s) # {(1, 2), (3, 4), (5, 6)} # 列表不能加入集合 # s = {[1, 2], [3, 4]} # TypeError: unhashable type: \u0026#39;list\u0026#39; 七、元组的性能优势 7.1 内存占用对比 import sys # 列表 vs 元组的内存占用 list1 = [1, 2, 3, 4, 5] tuple1 = (1, 2, 3, 4, 5) print(f\u0026#34;列表大小: {sys.getsizeof(list1)} bytes\u0026#34;) print(f\u0026#34;元组大小: {sys.getsizeof(tuple1)} bytes\u0026#34;) # 元组通常比列表占用更少的内存 7.2 操作性能对比 import time n = 10000000 # 列表创建 start = time.time() list1 = [i for i in range(n)] list_time = time.time() - start # 元组创建 start = time.time() tuple1 = tuple(i for i in range(n)) tuple_time = time.time() - start print(f\u0026#34;列表创建耗时: {list_time:.4f}s\u0026#34;) print(f\u0026#34;元组创建耗时: {tuple_time:.4f}s\u0026#34;) 八、元组的实战示例 8.1 坐标系统 from collections import namedtuple import math Point = namedtuple(\u0026#39;Point\u0026#39;, [\u0026#39;x\u0026#39;, \u0026#39;y\u0026#39;]) def distance(p1, p2): \u0026#34;\u0026#34;\u0026#34;计算两点间距离\u0026#34;\u0026#34;\u0026#34; return math.sqrt((p1.x - p2.x)**2 + (p1.y - p2.y)**2) p1 = Point(0, 0) p2 = Point(3, 4) print(f\u0026#34;距离: {distance(p1, p2)}\u0026#34;) # 5.0 8.2 CSV 数据处理 from collections import namedtuple # 假设 CSV 数据 csv_data = [ \u0026#34;张三,25,计算机科学,3.8\u0026#34;, \u0026#34;李四,22,数学,3.5\u0026#34;, \u0026#34;王五,23,物理,3.6\u0026#34;, ] Student = namedtuple(\u0026#39;Student\u0026#39;, [\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;, \u0026#39;major\u0026#39;, \u0026#39;gpa\u0026#39;]) students = [] for line in csv_data: fields = line.split(\u0026#39;,\u0026#39;) s = Student(*fields) # 解包字段 students.append(s) for s in students: print(f\u0026#34;{s.name}: {s.major}, GPA={s.gpa}\u0026#34;) 背诵版（核心要点） ┌─────────────────────────────────────────────────────────────┐ │ 元组 - 背诵版 │ ├─────────────────────────────────────────────────────────────┤ │ 【创建】 │ │ () / tuple() / (1,) / (1,2,3) / 1,2,3 │ │ tuple([1,2,3]) / tuple(\u0026#34;abc\u0026#34;) / tuple(range(5)) │ │ │ │ 【特点】 │ │ 有序、不可变、可哈希（可用作字典键） │ │ 只有 index() 和 count() 两个方法 │ │ │ │ 【解包】 │ │ a, b, c = (1, 2, 3) 基本解包 │ │ first, *rest, last = t 星号收集 │ │ a, b = b, a 交换变量 │ │ *_, middle, *_ = t 丢弃不需要的值 │ │ │ │ 【namedtuple】 │ │ Point = namedtuple(\u0026#39;Point\u0026#39;, [\u0026#39;x\u0026#39;, \u0026#39;y\u0026#39;]) │ │ p = Point(10, 20) │ │ p._make(iterable) 从可迭代对象创建 │ │ p._asdict() 转为有序字典 │ │ p._replace(**kwargs) 创建修改后的副本 │ └─────────────────────────────────────────────────────────────┘ 考前记忆（速记口诀） 【元组七字诀】 圆括号里装元素，逗号分隔不可分 创建方式有多种，tuple 函数转换行 不可变是核心键，字典键来放元组 index count 两方法，查遍元组全靠它 【解包七字诀】 解包就是批量赋，左边变量右边数 星号加在谁身上，谁就收集剩余路 交换变量最简单，直接 a, b = b, a 嵌套解包要小心，结构对应才正确 【namedtuple 速记】 命名元组是升级，字段也能用名访问 _asdict() 转字典，_replace() 改副本 _make() 批量创建，_fields 看字段 比元组更直观，比类更轻量 测试题 一、选择题 下面哪个是创建元组的正确方式？\nA. [1, 2, 3] B. (1, 2, 3) C. {1, 2, 3} D. B 和 C 都正确 元组和列表的主要区别是？\nA. 元组是有序的，列表是无序的 B. 元组是不可变的，列表是可变的 C. 元组可以包含任意类型，列表只能包含同类型 D. 列表可以作字典键，元组不行 t = (1, 2, 3, 4, 5)，first, *middle, last = t 执行后，middle 的值是？\nA. 2 B. [2, 3, 4] C. (2, 3, 4) D. 3 哪个语句可以正确交换 a 和 b 的值？\nA. a = b, b = a B. a, b = b, a C. temp = a; a = b; b = temp D. B 和 C 都正确 namedtuple 创建后，以下哪个操作会改变原对象？\nA. p.x = 10 B. p._replace(x=10) C. p._asdict() D. B 和 C 都正确 下面哪个可以作为字典的键？\nA. [1, 2, 3] B. {1: 2} C. (1, 2, 3) D. A 和 B 都可以 t = (1, [2, 3], 4)，执行 t[1].append(5) 后，t 变为？\nA. (1, [2, 3], 4) B. (1, [2, 3, 5], 4) C. ((1, [2, 3], 4),) D. 报错 tuple(\u0026quot;Python\u0026quot;) 的结果是？\nA. ['P', 'y', 't', 'h', 'o', 'n'] B. ('Python',) C. ('P', 'y', 't', 'h', 'o', 'n') D. 'Python' Point = namedtuple('Point', 'x y')，以下哪个可以创建 Point 实例？\nA. Point(x=1, y=2) B. Point(1, 2) C. Point([1, 2]) D. A 和 B 都可以 关于元组的性能，正确的是？\nA. 元组比列表性能差 B. 元组比列表更节省内存 C. 元组支持更多方法 D. 列表的索引访问比元组快 二、填空题 单元素元组必须加 _____ 。\n元组有 _____ 个方法（填数字）。\nt = (1, 2, 3)，t * 2 的结果是 _____ 。\n在函数定义中，*args 接收的参数类型是 _____ 。\nnamedtuple 是 _____ 模块中的函数。\n_asdict() 方法返回的是 _____ 类型。\n_make() 方法的作用是从 _____ 创建 namedtuple 实例。\n*rest, last = (1, 2, 3, 4) 后，rest 的值是 _____ 。\n元组的主要特点是 _____ 性（填一个字）。\n(1, 2) + (3, 4) 的结果是 _____ 。\n三、编程题 写一个函数 swap_dict(d)，交换字典的所有键值对（值必须可哈希）。\n使用 namedtuple 定义一个 Rectangle，计算矩形面积和周长。\n写一个函数 unpack_coordinates(points)，接收形如 [(1,2), (3,4), (5,6)] 的列表，返回 (1,3,5) 和 (2,4,6) 两个元组。\n答案见下页\n测试题答案 选择题答案 题号 答案 解析 1 B (1, 2, 3) 是元组，[1, 2, 3] 是列表，{1, 2, 3} 是集合 2 B 元组不可变，列表可变；两者都是有序的 3 B 星号收集中间所有元素为列表 4 D A 只赋值不交换，B 和 C 都可以交换 5 C _replace() 返回新实例，_asdict() 返回字典，都不改原对象 6 C 列表和字典都是可变的，不能作字典键 7 B 元组本身不可变，但其中的列表可变 8 C tuple() 将字符串拆分为字符元组 9 D namedtuple 可以用位置参数或关键字参数创建 10 B 元组比列表更简单，内存占用更少 填空题答案 逗号（,） 2 (1, 2, 3, 1, 2, 3) 元组 collections OrderedDict 可迭代对象 [1, 2, 3] 不可变 (1, 2, 3, 4) 编程题答案 答案1：交换字典键值对\ndef swap_dict(d): \u0026#34;\u0026#34;\u0026#34;交换字典键值对\u0026#34;\u0026#34;\u0026#34; return {v: k for k, v in d.items()} # 测试 d = {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 2, \u0026#39;c\u0026#39;: 3} print(swap_dict(d)) # {1: \u0026#39;a\u0026#39;, 2: \u0026#39;b\u0026#39;, 3: \u0026#39;c\u0026#39;} 答案2：Rectangle namedtuple\nfrom collections import namedtuple Rectangle = namedtuple(\u0026#39;Rectangle\u0026#39;, [\u0026#39;width\u0026#39;, \u0026#39;height\u0026#39;]) def area(rect): return rect.width * rect.height def perimeter(rect): return 2 * (rect.width + rect.height) r = Rectangle(10, 5) print(f\u0026#34;面积: {area(r)}\u0026#34;) # 50 print(f\u0026#34;周长: {perimeter(r)}\u0026#34;) # 30 答案3：解包坐标\ndef unpack_coordinates(points): \u0026#34;\u0026#34;\u0026#34;解包坐标点列表\u0026#34;\u0026#34;\u0026#34; x_coords = tuple(p[0] for p in points) y_coords = tuple(p[1] for p in points) return x_coords, y_coords # 测试 points = [(1, 2), (3, 4), (5, 6)] x, y = unpack_coordinates(points) print(f\u0026#34;x 坐标: {x}\u0026#34;) # (1, 3, 5) print(f\u0026#34;y 坐标: {y}\u0026#34;) # (2, 4, 6) 本课程完结\n","description":"深入学习Python元组的基本操作、解包与namedtuple高级用法","permalink":"https://blog.uuworld.cn/python-course/python-day-15-tuple-basics/","summary":"\u003ch1 id=\"python-day-15---元组-unpacking-namedtuple\"\u003ePython Day 15 - 元组 unpacking namedtuple\u003c/h1\u003e\n\u003ch2 id=\"课程概述\"\u003e课程概述\u003c/h2\u003e\n\u003cp\u003e本节课将深入学习 Python 元组（Tuple）这一核心数据结构。元组与列表非常相似，都是有序的序列，但元组具有\u003cstrong\u003e不可变性\u003c/strong\u003e，这使得它在某些场景下比列表更安全和高效。\u003c/p\u003e\n\u003cp\u003e本课程基于 \u003cstrong\u003ePython 3.11\u003c/strong\u003e 编写，所有示例均经过验证。我们将学习元组的基本操作、解包（Unpacking）特性以及 \u003ccode\u003enamedtuple\u003c/code\u003e 工厂函数的高級用法。\u003c/p\u003e\n\u003cp\u003e元组在 Python 中无处不在：函数可以返回多个值、字符串格式化、字典的键必须是不可变对象、数据库记录等等。掌握元组是进阶 Python 编程的必经之路。\u003c/p\u003e\n\u003ch2 id=\"一元组基础概念\"\u003e一、元组基础概念\u003c/h2\u003e\n\u003ch3 id=\"11-什么是元组\"\u003e1.1 什么是元组\u003c/h3\u003e\n\u003cp\u003e元组是 Python 中的一种\u003cstrong\u003e有序\u003c/strong\u003e、\u003cstrong\u003e不可变\u003c/strong\u003e的序列类型。使用圆括号 \u003ccode\u003e( )\u003c/code\u003e 来表示。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 元组的基本定义\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eempty_tuple \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e ()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esingle_tuple \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e42\u003c/span\u003e,)  \u003cspan style=\"color:#75715e\"\u003e# 注意：单个元素需要加逗号\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emulti_tuple \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(type(empty_tuple))   \u003cspan style=\"color:#75715e\"\u003e# \u0026lt;class \u0026#39;tuple\u0026#39;\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(type(single_tuple))  \u003cspan style=\"color:#75715e\"\u003e# \u0026lt;class \u0026#39;tuple\u0026#39;\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(type(multi_tuple))   \u003cspan style=\"color:#75715e\"\u003e# \u0026lt;class \u0026#39;tuple\u0026#39;\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"12-元组与列表的区别\"\u003e1.2 元组与列表的区别\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e特性\u003c/th\u003e\n          \u003cth\u003e列表\u003c/th\u003e\n          \u003cth\u003e元组\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e语法\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e[1, 2, 3]\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e(1, 2, 3)\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e可变性\u003c/td\u003e\n          \u003ctd\u003e可变（Mutable）\u003c/td\u003e\n          \u003ctd\u003e不可变（Immutable）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e性能\u003c/td\u003e\n          \u003ctd\u003e稍慢（需要维护额外结构）\u003c/td\u003e\n          \u003ctd\u003e稍快（更简单）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e安全性\u003c/td\u003e\n          \u003ctd\u003e可修改，可能被意外改变\u003c/td\u003e\n          \u003ctd\u003e不可修改，更安全\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e用作字典键\u003c/td\u003e\n          \u003ctd\u003e否\u003c/td\u003e\n          \u003ctd\u003e是\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e常用场景\u003c/td\u003e\n          \u003ctd\u003e需要修改的数据\u003c/td\u003e\n          \u003ctd\u003e固定数据、多返回值\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 列表可变\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elist1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elist1[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(list1)  \u003cspan style=\"color:#75715e\"\u003e# [100, 2, 3]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 元组不可变\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etuple1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# tuple1[0] = 100  # TypeError: \u0026#39;tuple\u0026#39; object does not support item assignment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"13-元组的创建方式\"\u003e1.3 元组的创建方式\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法1：使用圆括号\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003et1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法2：使用 tuple() 构造函数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003et2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e tuple()      \u003cspan style=\"color:#75715e\"\u003e# 空元组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003et3 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e tuple([\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e])  \u003cspan style=\"color:#75715e\"\u003e# 从列表转换\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003et4 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e tuple(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;abc\u0026#34;\u003c/span\u003e)      \u003cspan style=\"color:#75715e\"\u003e# 从字符串转换\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003et5 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e tuple(range(\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e))   \u003cspan style=\"color:#75715e\"\u003e# 从 range 对象转换\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法3：单元素元组必须加逗号\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esingle \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e42\u003c/span\u003e,)  \u003cspan style=\"color:#75715e\"\u003e# 正确\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enot_tuple \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e42\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 只是整数 42，不是元组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法4：打包（packing）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epacked \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 不需要括号\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(packed)  \u003cspan style=\"color:#75715e\"\u003e# (1, 2, 3)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法5：生成器推导式（注意：生成的是元组）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egen_tuple \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e tuple(x \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e x \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(gen_tuple)  \u003cspan style=\"color:#75715e\"\u003e# (0, 1, 4, 9, 16)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"二元组的基本操作\"\u003e二、元组的基本操作\u003c/h2\u003e\n\u003ch3 id=\"21-索引访问\"\u003e2.1 索引访问\u003c/h3\u003e\n\u003cp\u003e元组支持与列表相同的索引访问方式，包括正索引和负索引。\u003c/p\u003e","tags":"Python, 元组, Tuple, unpacking, namedtuple","title":"Python Day 15 - 元组 unpacking namedtuple"},{"columns":"acp-course","content":"Day 15：企业应用服务（DNS/SSL/CDN） 本文基于阿里云ACP云计算工程师认证课程内容整理，涵盖企业网站访问全链路：DNS域名解析原理、云解析DNS配置、SSL证书管理，以及CDN内容分发网络原理、配置与最佳实践。\n一、企业应用访问全链路：DNS与域名系统 为什么需要域名 人类记忆域名（如www.aliyun.com）比IP地址（如119.75.217.109）容易得多。计算之间通过IP通信，但用户通过域名访问应用——这背后就是DNS（Domain Name System） 域名系统在起作用。\n用户浏览器输入域名 ↓ DNS服务器查询域名对应的IP地址 ↓ 返回IP地址 ↓ 浏览器根据IP发起HTTP/HTTPS请求 ↓ 服务器响应内容域名结构解析 以www.google.com为例：\n层级 名称 说明 顶级域名（TLD） .com 由ICANN管理 二级域名 google 注册人可自定义 子域名/三级域名 www 主机记录，指向Web服务器 常见子域名用途：\nmail.google.com → Gmail邮件服务 drive.google.com → Google Drive云存储 map.baidu.com → 百度地图 HTTP vs HTTPS 协议 端口 加密 安全性 HTTP 80 明文传输 低，存在中间人攻击风险 HTTPS 443 SSL/TLS加密 高，提供身份认证和隐私保护 HTTPS = HTTP + SSL，SSL证书在浏览器和网站之间建立加密通道。\nSSL加密原理 SSL（Secure Sockets Layer）采用公钥密码体制：\n网站向权威CA机构申请SSL证书（包含公钥和网站身份信息） 浏览器访问网站时，服务器发送证书 浏览器验证证书有效性，获取公钥 浏览器生成对称密钥，用公钥加密后发送 服务器用私钥解密，获取对称密钥 双方使用对称密钥加密通信 企业网站建设五步流程 域名注册认证 → 网站建设备案 → 配置域名解析 → 部署SSL证书 → 网站上线 考试要点：域名由ICANN统一管理，国内由CNNIC负责.cn域名。完整的域名至少包含顶级域名和二级域名两部分。SSL证书提供加密传输和身份认证双重功能。\n二、云解析DNS与数字证书管理服务 云解析DNS核心能力 云解析DNS 是阿里云提供的权威DNS解析管理服务，具备100%权威DNS解析可用性保障：\n能力 说明 全球节点覆盖 20个DNS集群节点，覆盖6大运营商及88个国家/地区 高性能 每秒承受过亿次DNS查询 智能解析 根据用户地理位置返回最优IP 高可用 99.99%解析可用性，首次解析5分钟生效 DNS解析记录类型 记录类型 用途 A记录 将域名指向IPv4地址 AAAA记录 将域名指向IPv6地址 CNAME记录 将域名指向另一个域名（别名） MX记录 邮件服务器记录 TXT记录 文本记录，常用于验证和SPF 显性URL/隐性URL 页面转发 智能DNS解析原理 传统DNS 智能DNS 不判断访问者来源 判断访问者来源（运营商/地理位置） 随机返回任一IP 返回最优IP 可能跨运营商访问，延迟高 就近访问，延迟低 示例：www.example.com配置联通、移动、电信三条A记录，智能DNS根据访问者线路返回对应IP。\nDNS Cache（DNS缓存代理） 无需DNS系统迁移，即可享受阿里DNS基础设施：\nDDoS缓解：缓存DNS响应，保护权威DNS服务器 访问加速：全球节点就近接入 服务备份：权威DNS异常时，缓存期内继续服务 成本节省：自建DNS场景节省带宽成本 DNS + 全局流量管理GTM DNS解析 \u0026#43; 健康检查 \u0026#43; 故障自动切换运营商多线接入场景：配置多个地址池，健康检查实时监测，故障时自动切换到备用地址池。\n数字证书管理服务 阿里云数字证书管理服务提供SSL证书和私有证书的全生命周期管理：\n功能 说明 证书申请 与CA机构直连，签发速度快 证书部署 支持CDN/SLB/WAF等15个云产品自动部署 证书托管 到期自动续费，避免证书过期 密钥保护 阿里云KMS加密存储私钥 SSL证书选型 证书类型 适用场景 认证强度 公信等级 DV域名型 个人网站 CA审核域名真实性 一般 OV企业型 企业网站 CA审核组织真实性 高 EV企业增强型 大型企业/金融机构 严格认证 最高 加密算法选型 算法 特点 RSA 应用最广泛，兼容性最好 ECC 更先进，加密速度快、效率高、服务器资源消耗低 SM2 国密算法，中国商用密码体系替代RSA 考试要点：云解析DNS提供100%权威DNS可用性保障。智能DNS根据访问者来源返回不同IP，减少解析延迟。证书私钥由阿里云KMS加密存储。\n三、CDN内容分发网络原理与阿里云CDN 为什么需要CDN 8秒定律：用户满意的网页打开时间在2秒以下，超过8秒会有30%用户放弃等待。\n造成访问延迟的根本原因：物理距离和跨运营商网络。\nCDN是什么 CDN（Content Delivery Network）内容分发网络：\n在现有互联网基础上建立并覆盖在承载网之上的分布式边缘节点集群 将源站资源缓存到全球加速节点 用户请求就近获取缓存资源，无需回源 解决跨地域、跨运营商的网络性能问题 CDN核心价值 全网覆盖：全球70+国家和地区，150Tbps+带宽储备 就近访问：智能调度到最优节点，减少延迟 减轻源站压力：缓存命中率高，减少回源带宽消耗 安全防护：集成DDoS防护、WAF等安全能力 CDN加速原理 用户请求 → DNS智能调度 → 最优CDN边缘节点 ↓ 节点缓存命中 → 直接返回 ↓（未命中） 回源获取 → 缓存 → 返回CDN产品矩阵 产品 定位 CDN 静态内容加速，图文/下载/视频 全站加速DCDN 静态+动态混合加速，TCP/UDP四层加速 安全加速SCDN 加速+安全，带100万QPS防护能力 PCDN P2P+CDN混合，成本更低 视频直播/PCDN 直播场景加速 CDN核心功能 功能 说明 Range回源 部分请求回源，减少回源流量，提高缓存命中率 HTTPS加速 客户端到CDN节点HTTPS加密 HTTP/3加速 基于QUIC协议，效果更快更优 页面优化 资源压缩、HTML优化、图片处理 访问控制 Referer防盗链、URL鉴权、IP黑白名单、UA黑白名单 考试要点：CDN通过将资源缓存到边缘节点实现就近访问，显著降低延迟。Referer是HTTP请求头的一部分，携带请求来源地址。URL鉴权比Referer防盗链安全性更高。\n四、CDN配置实践与企业级应用场景 CDN使用全流程 开通CDN服务 → 添加加速域名 → 配置源站 → 配置缓存过期规则 → 配置HTTPS → 配置访问控制 → 测试验证配置源站 阿里云CDN支持多种源站类型：\n源站类型 说明 OSS域名 阿里云对象存储，推荐作为静态资源源站 IP 业务服务器公网IP 源站域名 业务服务器域名 函数计算域名 阿里云FC 支持配置主备源站，设置优先级和权重实现负载均衡。\nHTTPS配置 客户端 → HTTPS（加密）→ CDN节点 → HTTPS（加密）→ 源站服务器CDN节点到源站服务器也需要支持HTTPS才能实现全链路加密。\n访问控制配置 Referer防盗链 通过HTTP请求头的Referer字段识别请求来源 配置黑名单/白名单，允许或拒绝访问 白名单匹配则返回资源，否则返回403 URL鉴权 更安全的防盗方式，适用于安全密级较高的文件：\n源站生成鉴权URL → 客户端使用鉴权URL请求 → CDN验证时间戳和签名 → 有效则放行IP黑白名单 限制或禁止特定IP访问，防止恶意IP盗刷和攻击。\nCDN典型应用场景 场景一：网页站点加速 推荐搭配：ECS \u0026#43; OSS \u0026#43; CDN 解决问题：流量激增、跨运营商访问、服务器负载过高 优势：降低源站带宽成本，毫秒级响应场景二：下载加速 适用MP4、FLV视频或单个文件\u0026gt;20MB的大文件下载场景：\n搭配OSS接入CDN，节约2/3回源带宽成本 支持Range回源，提高缓存命中率 场景三：视频点播 一站式音视频点播解决方案：\n媒体转码 + OSS存储 + CDN分发 + 消息服务 支持防盗链和URL鉴权，保护版权 95%+缓存命中率，毫秒级响应 DCDN vs SCDN vs PCDN 产品 核心特点 适用场景 DCDN 静态+动态混合加速，TCP/UDP四层加速，WebSocket 动静态混合业务 SCDN 100万QPS，频次控制+流量管理 防攻击、防盗刷 PCDN P2P+CDN，成本最低 视频点播、直播、大文件 ACP认证核心知识点速查 DNS作用：将域名转换为IP地址，提供域名解析服务 云解析DNS：100%权威DNS可用性，智能解析（按运营商/地理位置） DNS记录类型：A（IPv4）、CNAME（别名）、MX（邮件）、TXT HTTP端口80，HTTPS端口443 SSL证书类型：DV（域名型）、OV（企业型）、EV（增强型） CDN核心：就近获取缓存资源，减轻源站压力 CDN加速原理：DNS调度 → 边缘节点 → 缓存命中/回源 Referer防盗链：基于HTTP请求头来源识别 URL鉴权：比Referer更安全，支持时间戳和签名验证 Range回源：部分内容回源，提高缓存命中率 源站类型：OSS域名、IP、源站域名、函数计算 全站加速DCDN：支持动态加速，不只是静态缓存 企业应用服务综合架构 用户浏览器 ↓（域名解析） DNS智能解析 → 就近CDN节点 → 缓存资源/回源 → 源站服务器 ↓（HTTPS加密） SSL证书验证身份 相关推荐：\nDay 5：VPC专有网络与NAT网关 Day 6：对象存储OSS处理图片 阿里云CDN官方文档 ","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-15-acp-day-15-%E4%BC%81%E4%B8%9A%E5%BA%94%E7%94%A8%E6%9C%8D%E5%8A%A1-cdn/","summary":"\u003ch1 id=\"day-15企业应用服务dnssslcdn\"\u003eDay 15：企业应用服务（DNS/SSL/CDN）\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e本文基于阿里云ACP云计算工程师认证课程内容整理，涵盖企业网站访问全链路：DNS域名解析原理、云解析DNS配置、SSL证书管理，以及CDN内容分发网络原理、配置与最佳实践。\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一企业应用访问全链路dns与域名系统\"\u003e一、企业应用访问全链路：DNS与域名系统\u003c/h2\u003e\n\u003ch3 id=\"为什么需要域名\"\u003e为什么需要域名\u003c/h3\u003e\n\u003cp\u003e人类记忆\u003cstrong\u003e域名\u003c/strong\u003e（如\u003ccode\u003ewww.aliyun.com\u003c/code\u003e）比\u003cstrong\u003eIP地址\u003c/strong\u003e（如\u003ccode\u003e119.75.217.109\u003c/code\u003e）容易得多。计算之间通过IP通信，但用户通过域名访问应用——这背后就是\u003cstrong\u003eDNS（Domain Name System）\u003c/strong\u003e 域名系统在起作用。\u003c/p\u003e\n用户浏览器输入域名\n       ↓\nDNS服务器查询域名对应的IP地址\n       ↓\n返回IP地址\n       ↓\n浏览器根据IP发起HTTP/HTTPS请求\n       ↓\n服务器响应内容\u003ch3 id=\"域名结构解析\"\u003e域名结构解析\u003c/h3\u003e\n\u003cp\u003e以\u003ccode\u003ewww.google.com\u003c/code\u003e为例：\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e层级\u003c/th\u003e\n          \u003cth\u003e名称\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e顶级域名（TLD）\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e.com\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e由ICANN管理\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e二级域名\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003egoogle\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e注册人可自定义\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e子域名/三级域名\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ewww\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e主机记录，指向Web服务器\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e常见子域名用途：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003email.google.com\u003c/code\u003e → Gmail邮件服务\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edrive.google.com\u003c/code\u003e → Google Drive云存储\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emap.baidu.com\u003c/code\u003e → 百度地图\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"http-vs-https\"\u003eHTTP vs HTTPS\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e协议\u003c/th\u003e\n          \u003cth\u003e端口\u003c/th\u003e\n          \u003cth\u003e加密\u003c/th\u003e\n          \u003cth\u003e安全性\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eHTTP\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e80\u003c/td\u003e\n          \u003ctd\u003e明文传输\u003c/td\u003e\n          \u003ctd\u003e低，存在中间人攻击风险\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eHTTPS\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e443\u003c/td\u003e\n          \u003ctd\u003eSSL/TLS加密\u003c/td\u003e\n          \u003ctd\u003e高，提供身份认证和隐私保护\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cstrong\u003eHTTPS = HTTP + SSL\u003c/strong\u003e，SSL证书在浏览器和网站之间建立加密通道。\u003c/p\u003e\n\u003ch3 id=\"ssl加密原理\"\u003eSSL加密原理\u003c/h3\u003e\n\u003cp\u003eSSL（Secure Sockets Layer）采用\u003cstrong\u003e公钥密码体制\u003c/strong\u003e：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e网站向权威CA机构申请SSL证书（包含公钥和网站身份信息）\u003c/li\u003e\n\u003cli\u003e浏览器访问网站时，服务器发送证书\u003c/li\u003e\n\u003cli\u003e浏览器验证证书有效性，获取公钥\u003c/li\u003e\n\u003cli\u003e浏览器生成对称密钥，用公钥加密后发送\u003c/li\u003e\n\u003cli\u003e服务器用私钥解密，获取对称密钥\u003c/li\u003e\n\u003cli\u003e双方使用对称密钥加密通信\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"企业网站建设五步流程\"\u003e企业网站建设五步流程\u003c/h3\u003e\n域名注册认证 → 网站建设备案 → 配置域名解析 → 部署SSL证书 → 网站上线\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e考试要点\u003c/strong\u003e：域名由ICANN统一管理，国内由CNNIC负责.cn域名。完整的域名至少包含顶级域名和二级域名两部分。SSL证书提供加密传输和身份认证双重功能。\u003c/p\u003e","tags":"Alibaba Cloud, DNS, SSL证书, CDN, ACP, 云计算, 企业应用","title":"Day 15: 企业应用服务（DNS/SSL/CDN）- ACP云计算工程师认证"},{"columns":"","content":"Python Day 16 - 字典 CRUD get pop update setdefault 课程概述 本节课将深入学习 Python 字典（Dictionary）这一核心数据结构。字典是 Python 中最灵活的内置数据类型之一，它以**键值对（Key-Value）**的形式存储数据，通过键来访问值，具有极高的查询效率。\n本课程基于 Python 3.11 编写，所有示例均经过验证。我们将详细学习字典的 CRUD 操作（Create/创建、Read/读取、Update/更新、Delete/删除），以及 get、pop、update、setdefault 等重要方法。\n字典在 Python 中应用广泛：配置信息、JSON 数据、数据库记录映射、缓存系统、图结构等都用字典来实现。掌握字典是 Python 进阶的必经之路。\n一、字典基础概念 1.1 什么是字典 字典是 Python 中的一种无序、可变的键值对集合。每个键值对由键（Key）和值（Value）组成，用冒号 : 分隔，键值对之间用逗号 , 分隔，整个字典用花括号 { } 包围。\n# 字典的基本定义 empty_dict = {} person = { \u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25, \u0026#34;city\u0026#34;: \u0026#34;北京\u0026#34; } print(person) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;} print(type(person)) # \u0026lt;class \u0026#39;dict\u0026#39;\u0026gt; 1.2 字典的特点 特点 说明 键值对存储 数据以键值对形式存储，通过键访问值 键的唯一性 同一个字典中，键必须唯一，不能重复 键的可哈希性 键必须是不可变类型（字符串、数字、元组等） 值的任意性 值可以是任意类型（列表、字典等可变对象也可以） 无序性 Python 3.7+ 字典保持插入顺序（但不是传统意义上的有序） 高性能 键查找、添加、删除的时间复杂度为 O(1) 1.3 字典的创建方式 # 方法1：使用花括号 d1 = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25} # 方法2：使用 dict() 构造函数 d2 = dict() # 空字典 d3 = dict(name=\u0026#34;李四\u0026#34;, age=30) # 关键字参数 d4 = dict([(\u0026#34;name\u0026#34;, \u0026#34;王五\u0026#34;), (\u0026#34;age\u0026#34;, 28)]) # 可迭代对象 d5 = dict.fromkeys([\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;], 0) # 从键列表创建，默认值 # 方法3：字典推导式 d6 = {x: x ** 2 for x in range(5)} # 方法4：字典的复制 d7 = d1.copy() print(d1) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25} print(d2) # {} print(d3) # {\u0026#39;name\u0026#39;: \u0026#39;李四\u0026#39;, \u0026#39;age\u0026#39;: 30} print(d4) # {\u0026#39;name\u0026#39;: \u0026#39;王五\u0026#39;, \u0026#39;age\u0026#39;: 28} print(d5) # {\u0026#39;a\u0026#39;: 0, \u0026#39;b\u0026#39;: 0, \u0026#39;c\u0026#39;: 0} print(d6) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} 1.4 键的要求 # 合法的键类型（不可变类型） d = { \u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, # 字符串 1: \u0026#34;整数键\u0026#34;, # 整数 (1, 2): \u0026#34;元组键\u0026#34;, # 元组 3.14: \u0026#34;浮点数键\u0026#34;, # 浮点数 True: \u0026#34;布尔键\u0026#34;, # 布尔值（True=1, False=0，会覆盖！） } # 非法的键类型（可变类型） # d = {[1, 2]: \u0026#34;列表键\u0026#34;} # TypeError: unhashable type: \u0026#39;list\u0026#39; # d = {{\u0026#34;a\u0026#34;: 1}: \u0026#34;字典键\u0026#34;} # TypeError: unhashable type: \u0026#39;dict\u0026#39; # 键冲突：后面的值会覆盖前面的 d = {\u0026#34;a\u0026#34;: 1, \u0026#34;a\u0026#34;: 2, \u0026#34;a\u0026#34;: 3} print(d) # {\u0026#39;a\u0026#39;: 3} 二、字典的读取操作（Read） 2.1 通过键访问值 person = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25, \u0026#34;city\u0026#34;: \u0026#34;北京\u0026#34;} # 通过键访问值 print(person[\u0026#34;name\u0026#34;]) # 张三 print(person[\u0026#34;age\u0026#34;]) # 25 # 键不存在时，会抛出 KeyError # print(person[\u0026#34;gender\u0026#34;]) # KeyError: \u0026#39;gender\u0026#39; 2.2 get() 方法 - 安全访问 get() 方法是访问字典值的安全方式，当键不存在时返回默认值而不是抛出异常。\nperson = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25} # 基本用法 print(person.get(\u0026#34;name\u0026#34;)) # 张三 print(person.get(\u0026#34;gender\u0026#34;)) # None（键不存在） print(person.get(\u0026#34;gender\u0026#34;, \u0026#34;未知\u0026#34;)) # 未知（提供默认值） # 使用 get() 进行安全查找 def get_email(contacts, name): \u0026#34;\u0026#34;\u0026#34;安全的邮箱获取\u0026#34;\u0026#34;\u0026#34; contact = contacts.get(name, {}) return contact.get(\u0026#34;email\u0026#34;, \u0026#34;未提供邮箱\u0026#34;) contacts = { \u0026#34;张三\u0026#34;: {\u0026#34;phone\u0026#34;: \u0026#34;13800138000\u0026#34;, \u0026#34;email\u0026#34;: \u0026#34;zhang@example.com\u0026#34;}, \u0026#34;李四\u0026#34;: {\u0026#34;phone\u0026#34;: \u0026#34;13900139000\u0026#34;} } print(get_email(contacts, \u0026#34;张三\u0026#34;)) # zhang@example.com print(get_email(contacts, \u0026#34;王五\u0026#34;)) # 未提供邮箱 2.3 键的检测 person = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25} # in 操作符 - 检测键是否存在 print(\u0026#34;name\u0026#34; in person) # True print(\u0026#34;gender\u0026#34; in person) # False print(\u0026#34;name\u0026#34; not in person) # False # 使用 get() 进行条件判断 if person.get(\u0026#34;gender\u0026#34;): print(f\u0026#34;性别: {person[\u0026#39;gender\u0026#39;]}\u0026#34;) else: print(\u0026#34;性别未填写\u0026#34;) 2.4 keys()、values()、items() person = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25, \u0026#34;city\u0026#34;: \u0026#34;北京\u0026#34;} # keys() - 返回所有键 print(person.keys()) # dict_keys([\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;, \u0026#39;city\u0026#39;]) for key in person.keys(): print(key) # values() - 返回所有值 print(person.values()) # dict_values([\u0026#39;张三\u0026#39;, 25, \u0026#39;北京\u0026#39;]) for value in person.values(): print(value) # items() - 返回所有键值对 print(person.items()) # dict_items([(\u0026#39;name\u0026#39;, \u0026#39;张三\u0026#39;), (\u0026#39;age\u0026#39;, 25), (\u0026#39;city\u0026#39;, \u0026#39;北京\u0026#39;)]) for key, value in person.items(): print(f\u0026#34;{key}: {value}\u0026#34;) # 转换为列表 print(list(person.keys())) # [\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;, \u0026#39;city\u0026#39;] print(list(person.values())) # [\u0026#39;张三\u0026#39;, 25, \u0026#39;北京\u0026#39;] print(list(person.items())) # [(\u0026#39;name\u0026#39;, \u0026#39;张三\u0026#39;), (\u0026#39;age\u0026#39;, 25), (\u0026#39;city\u0026#39;, \u0026#39;北京\u0026#39;)] 三、字典的创建操作（Create） 3.1 直接添加键值对 person = {} # 直接添加键值对 person[\u0026#34;name\u0026#34;] = \u0026#34;张三\u0026#34; person[\u0026#34;age\u0026#34;] = 25 person[\u0026#34;city\u0026#34;] = \u0026#34;北京\u0026#34; print(person) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;} 3.2 setdefault() - 设置默认值 setdefault() 方法用于获取键的值，如果键不存在，则设置默认值并返回。\nperson = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25} # setdefault() - 键存在时返回原值，不存在时设置默认值 # 语法: dict.setdefault(key, default=None) # 键存在，返回原值 result = person.setdefault(\u0026#34;name\u0026#34;, \u0026#34;李四\u0026#34;) print(result) # 张三 print(person) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25} # 键不存在，设置默认值 result = person.setdefault(\u0026#34;city\u0026#34;, \u0026#34;上海\u0026#34;) print(result) # 上海 print(person) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;上海\u0026#39;} # 设置默认值为列表（常用技巧） data = {} data.setdefault(\u0026#34;items\u0026#34;, []).append(\u0026#34;apple\u0026#34;) data.setdefault(\u0026#34;items\u0026#34;, []).append(\u0026#34;banana\u0026#34;) data.setdefault(\u0026#34;items\u0026#34;, []).append(\u0026#34;cherry\u0026#34;) print(data) # {\u0026#39;items\u0026#39;: [\u0026#39;apple\u0026#39;, \u0026#39;banana\u0026#39;, \u0026#39;cherry\u0026#39;]} 3.3 使用 fromkeys() 批量创建 # fromkeys() - 使用给定的键创建字典，默认值为 None keys = [\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;] d1 = dict.fromkeys(keys) print(d1) # {\u0026#39;a\u0026#39;: None, \u0026#39;b\u0026#39;: None, \u0026#39;c\u0026#39;: None} # 指定默认值 d2 = dict.fromkeys(keys, 0) print(d2) # {\u0026#39;a\u0026#39;: 0, \u0026#39;b\u0026#39;: 0, \u0026#39;c\u0026#39;: 0} # 注意：默认值是同一个对象（浅拷贝问题） d3 = dict.fromkeys(keys, []) d3[\u0026#34;a\u0026#34;].append(1) print(d3) # {\u0026#39;a\u0026#39;: [1], \u0026#39;b\u0026#39;: [1], \u0026#39;c\u0026#39;: [1]} # 三个键共享同一个列表！ # 正确做法：使用字典推导式 d4 = {k: [] for k in keys} d4[\u0026#34;a\u0026#34;].append(1) print(d4) # {\u0026#39;a\u0026#39;: [1], \u0026#39;b\u0026#39;: [], \u0026#39;c\u0026#39;: []} 四、字典的更新操作（Update） 4.1 直接赋值更新 person = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25} # 直接修改已有键的值 person[\u0026#34;age\u0026#34;] = 26 print(person) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 26} # 添加新键值对 person[\u0026#34;city\u0026#34;] = \u0026#34;北京\u0026#34; print(person) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 26, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;} 4.2 update() 方法 - 批量更新 update() 方法用于批量更新字典，可以添加新键值对，也可以更新已有键的值。\nperson = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25} # update() - 用字典更新 person.update({\u0026#34;age\u0026#34;: 26, \u0026#34;city\u0026#34;: \u0026#34;北京\u0026#34;, \u0026#34;gender\u0026#34;: \u0026#34;男\u0026#34;}) print(person) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 26, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;, \u0026#39;gender\u0026#39;: \u0026#39;男\u0026#39;} # update() - 用关键字参数更新 person.update(age=27, city=\u0026#34;上海\u0026#34;) print(person) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 27, \u0026#39;city\u0026#39;: \u0026#39;上海\u0026#39;} # update() - 用可迭代对象更新 person.update([(\u0026#34;email\u0026#34;, \u0026#34;zhang@example.com\u0026#34;), (\u0026#34;phone\u0026#34;, \u0026#34;13800138000\u0026#34;)]) print(person) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 27, \u0026#39;city\u0026#39;: \u0026#39;上海\u0026#39;, \u0026#39;email\u0026#39;: \u0026#39;zhang@example.com\u0026#39;, \u0026#39;phone\u0026#39;: \u0026#39;13800138000\u0026#39;} # update() - 用两个可迭代对象配对更新（zip） keys = [\u0026#34;name\u0026#34;, \u0026#34;age\u0026#34;] values = [\u0026#34;李四\u0026#34;, 30] person.update(zip(keys, values)) print(person) # {\u0026#39;name\u0026#39;: \u0026#39;李四\u0026#39;, \u0026#39;age\u0026#39;: 30, ...} 4.3 合并字典（Python 3.9+） # Python 3.9+ 支持 | 和 |= 操作符 d1 = {\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2} d2 = {\u0026#34;b\u0026#34;: 3, \u0026#34;c\u0026#34;: 4} # | 操作符 - 合并字典（d2 的值会覆盖 d1 的） merged = d1 | d2 print(merged) # {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 3, \u0026#39;c\u0026#39;: 4} # |= 操作符 - 就地合并 d1 |= d2 print(d1) # {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 3, \u0026#39;c\u0026#39;: 4} # 注意：合并顺序 d1 = {\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2} d2 = {\u0026#34;b\u0026#34;: 3, \u0026#34;c\u0026#34;: 4} d3 = d2 | d1 # d1 的值会覆盖 d2 的 print(d3) # {\u0026#39;b\u0026#39;: 2, \u0026#39;c\u0026#39;: 4, \u0026#39;a\u0026#39;: 1} 4.4 update() 与 | 的对比 # update() - 会修改原字典，就地更新 d1 = {\u0026#34;a\u0026#34;: 1} d1.update({\u0026#34;b\u0026#34;: 2}) print(d1) # {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 2} # | - 不修改原字典，返回新的合并字典 d1 = {\u0026#34;a\u0026#34;: 1} d2 = {\u0026#34;b\u0026#34;: 2} d3 = d1 | d2 print(d1) # {\u0026#39;a\u0026#39;: 1}（不变） print(d2) # {\u0026#39;b\u0026#39;: 2}（不变） print(d3) # {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 2} 五、字典的删除操作（Delete） 5.1 pop() - 按键删除 pop() 方法删除指定键的键值对，并返回被删除的值。\nperson = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25, \u0026#34;city\u0026#34;: \u0026#34;北京\u0026#34;, \u0026#34;gender\u0026#34;: \u0026#34;男\u0026#34;} # pop(key) - 删除指定键，返回值 name = person.pop(\u0026#34;name\u0026#34;) print(name) # 张三 print(person) # {\u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;, \u0026#39;gender\u0026#39;: \u0026#39;男\u0026#39;} # pop(key, default) - 键不存在时返回默认值 age = person.pop(\u0026#34;age\u0026#34;, None) print(age) # 25 missing = person.pop(\u0026#34;height\u0026#34;, \u0026#34;未知\u0026#34;) print(missing) # 未知 # pop() 在空字典上会报错（除非提供默认值） # person.pop(\u0026#34;key\u0026#34;) # KeyError（键不存在且无默认值） 5.2 popitem() - 删除最后一个键值对 popitem() 方法删除并返回字典中的最后一个键值对（Python 3.7+ 保证有序）。\nperson = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25, \u0026#34;city\u0026#34;: \u0026#34;北京\u0026#34;} # popitem() - 删除并返回最后一个键值对 key, value = person.popitem() print(f\u0026#34;删除: ({key}, {value})\u0026#34;) # (\u0026#39;city\u0026#39;, \u0026#39;北京\u0026#39;) print(person) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25} # 连续 popitem while person: key, value = person.popitem() print(f\u0026#34;删除: {key} = {value}\u0026#34;) # 输出: # 删除: age = 25 # 删除: name = 张三 # popitem() 在空字典上会报错 # {}.popitem() # KeyError: dictionary is empty 5.3 del 语句 - 按键删除 person = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25, \u0026#34;city\u0026#34;: \u0026#34;北京\u0026#34;} # del 按键删除 del person[\u0026#34;age\u0026#34;] print(person) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;} # del 删除整个字典 # del person # print(person) # NameError: name \u0026#39;person\u0026#39; is not defined 5.4 clear() - 清空字典 person = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25, \u0026#34;city\u0026#34;: \u0026#34;北京\u0026#34;} person.clear() print(person) # {} 5.5 删除操作对比 方法 语法 返回值 特点 pop() d.pop(key) 返回被删除的值 按键删除，键不存在会报错 popitem() d.popitem() 返回被删除的键值对 删除最后一个（Python 3.7+） del del d[key] 无 按键删除 clear() d.clear() 无 清空所有键值对 六、字典的高级操作 6.1 字典推导式 # 字典推导式 - {key: value for ...} numbers = [1, 2, 3, 4, 5] # 基本用法 squares = {x: x ** 2 for x in numbers} print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25} # 带条件筛选 even_squares = {x: x ** 2 for x in numbers if x % 2 == 0} print(even_squares) # {2: 4, 4: 16} # 键值转换 old_dict = {\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2, \u0026#34;c\u0026#34;: 3} inverted = {v: k for k, v in old_dict.items()} print(inverted) # {1: \u0026#39;a\u0026#39;, 2: \u0026#39;b\u0026#39;, 3: \u0026#39;c\u0026#39;} # 两个列表配对 keys = [\u0026#34;name\u0026#34;, \u0026#34;age\u0026#34;, \u0026#34;city\u0026#34;] values = [\u0026#34;张三\u0026#34;, 25, \u0026#34;北京\u0026#34;] d = {k: v for k, v in zip(keys, values)} print(d) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;} 6.2 字典的复制 # 浅拷贝 - 三种方式 d1 = {\u0026#34;a\u0026#34;: [1, 2, 3], \u0026#34;b\u0026#34;: 2} d2 = d1.copy() d3 = dict(d1) d4 = {**d1} print(d1 == d2) # True print(d1 is d2) # False # 浅拷贝的问题：嵌套对象共享引用 d2 = d1.copy() d2[\u0026#34;a\u0026#34;].append(4) print(d1[\u0026#34;a\u0026#34;]) # [1, 2, 3, 4] - 原字典也被改了！ # 深拷贝 import copy d3 = copy.deepcopy(d1) d3[\u0026#34;a\u0026#34;].append(5) print(d1[\u0026#34;a\u0026#34;]) # [1, 2, 3, 4] - 原字典不受影响 6.3 字典的嵌套 # 字典的嵌套 - 字典的值可以是另一个字典 students = { \u0026#34;张三\u0026#34;: {\u0026#34;age\u0026#34;: 25, \u0026#34;score\u0026#34;: 85}, \u0026#34;李四\u0026#34;: {\u0026#34;age\u0026#34;: 22, \u0026#34;score\u0026#34;: 92}, \u0026#34;王五\u0026#34;: {\u0026#34;age\u0026#34;: 23, \u0026#34;score\u0026#34;: 78} } # 访问嵌套字典 print(students[\u0026#34;张三\u0026#34;][\u0026#34;score\u0026#34;]) # 85 # 修改嵌套字典 students[\u0026#34;张三\u0026#34;][\u0026#34;score\u0026#34;] = 90 print(students[\u0026#34;张三\u0026#34;]) # {\u0026#39;age\u0026#39;: 25, \u0026#39;score\u0026#39;: 90} # 添加新字段 students[\u0026#34;李四\u0026#34;][\u0026#34;grade\u0026#34;] = \u0026#34;A\u0026#34; print(students[\u0026#34;李四\u0026#34;]) # {\u0026#39;age\u0026#39;: 22, \u0026#39;score\u0026#39;: 92, \u0026#39;grade\u0026#39;: \u0026#39;A\u0026#39;} # 使用 setdefault() 安全添加 students.setdefault(\u0026#34;赵六\u0026#34;, {\u0026#34;age\u0026#34;: 21, \u0026#34;score\u0026#34;: 88}) 6.4 defaultdict - 默认值字典 defaultdict 是 collections 模块中的一个字典子类，可以为不存在的键提供默认值。\nfrom collections import defaultdict # 创建 defaultdict，指定默认值类型 dd = defaultdict(int) # 默认值是 0 print(dd[\u0026#34;missing\u0026#34;]) # 0 print(dd) # defaultdict(\u0026lt;class \u0026#39;int\u0026#39;\u0026gt;, {\u0026#39;missing\u0026#39;: 0}) # 统计计数 words = [\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;apple\u0026#34;, \u0026#34;cherry\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;apple\u0026#34;] counter = defaultdict(int) for word in words: counter[word] += 1 print(dict(counter)) # {\u0026#39;apple\u0026#39;: 3, \u0026#39;banana\u0026#39;: 2, \u0026#39;cherry\u0026#39;: 1} # defaultdict(list) - 自动创建列表 dd_list = defaultdict(list) dd_list[\u0026#34;fruits\u0026#34;].append(\u0026#34;apple\u0026#34;) dd_list[\u0026#34;fruits\u0026#34;].append(\u0026#34;banana\u0026#34;) dd_list[\u0026#34;vegetables\u0026#34;].append(\u0026#34;carrot\u0026#34;) print(dict(dd_list)) # {\u0026#39;fruits\u0026#39;: [\u0026#39;apple\u0026#39;, \u0026#39;banana\u0026#39;], \u0026#39;vegetables\u0026#39;: [\u0026#39;carrot\u0026#39;]} # defaultdict(set) - 自动创建集合 dd_set = defaultdict(set) dd_set[\u0026#34;colors\u0026#34;].add(\u0026#34;red\u0026#34;) dd_set[\u0026#34;colors\u0026#34;].add(\u0026#34;blue\u0026#34;) print(dict(dd_set)) # {\u0026#39;colors\u0026#39;: {\u0026#39;red\u0026#39;, \u0026#39;blue\u0026#39;}} 6.5 Counter - 计数器 Counter 是 collections 模块中的一个字典子类，专门用于计数。\nfrom collections import Counter # 基本用法 cnt = Counter([\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;apple\u0026#34;, \u0026#34;cherry\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;apple\u0026#34;]) print(cnt) # Counter({\u0026#39;apple\u0026#39;: 3, \u0026#39;banana\u0026#39;: 2, \u0026#39;cherry\u0026#39;: 1}) # 统计字符串 cnt = Counter(\u0026#34;hello world\u0026#34;) print(cnt) # Counter({\u0026#39;l\u0026#39;: 3, \u0026#39;o\u0026#39;: 2, \u0026#39;h\u0026#39;: 1, \u0026#39;e\u0026#39;: 1, \u0026#39; \u0026#39;: 1, \u0026#39;w\u0026#39;: 1, \u0026#39;r\u0026#39;: 1, \u0026#39;d\u0026#39;: 1}) # most_common() - 返回最常见的元素 cnt = Counter([\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;apple\u0026#34;, \u0026#34;cherry\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;apple\u0026#34;]) print(cnt.most_common(2)) # [(\u0026#39;apple\u0026#39;, 3), (\u0026#39;banana\u0026#39;, 2)] # 计数操作 cnt = Counter(a=3, b=2, c=1) print(cnt + cnt) # Counter({\u0026#39;a\u0026#39;: 6, \u0026#39;b\u0026#39;: 4, \u0026#39;c\u0026#39;: 2}) print(cnt - cnt) # Counter() - 空 Counter # 字典操作 cnt1 = Counter(a=3, b=1) cnt2 = Counter(a=1, b=2) print(cnt1 \u0026amp; cnt2) # 交集 - 取较小值: Counter({\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 1}) print(cnt1 | cnt2) # 并集 - 取较大值: Counter({\u0026#39;a\u0026#39;: 3, \u0026#39;b\u0026#39;: 2}) 七、字典的实战示例 7.1 学生成绩管理系统 # 学生成绩管理系统 students = { \u0026#34;张三\u0026#34;: {\u0026#34;math\u0026#34;: 85, \u0026#34;english\u0026#34;: 92, \u0026#34;chinese\u0026#34;: 88}, \u0026#34;李四\u0026#34;: {\u0026#34;math\u0026#34;: 92, \u0026#34;english\u0026#34;: 78, \u0026#34;chinese\u0026#34;: 95}, \u0026#34;王五\u0026#34;: {\u0026#34;math\u0026#34;: 78, \u0026#34;english\u0026#34;: 85, \u0026#34;chinese\u0026#34;: 82}, } # 计算每个学生的平均分 def calc_average(scores): return sum(scores.values()) / len(scores) for name, scores in students.items(): avg = calc_average(scores) print(f\u0026#34;{name}: 平均分 = {avg:.1f}\u0026#34;) # 找出最高分科目和最低分科目 for name, scores in students.items(): max_subject = max(scores, key=scores.get) min_subject = min(scores, key=scores.get) print(f\u0026#34;{name}: 最高分科目 = {max_subject}({scores[max_subject]}), 最低分科目 = {min_subject}({scores[min_subject]})\u0026#34;) 7.2 词频统计 from collections import Counter import re text = \u0026#34;\u0026#34;\u0026#34; Python is a powerful programming language. Python is easy to learn. Python has a clean syntax. Python is widely used in data science. \u0026#34;\u0026#34;\u0026#34; # 清洗文本并统计词频 words = re.findall(r\u0026#39;\\w+\u0026#39;, text.lower()) counter = Counter(words) print(\u0026#34;词频统计:\u0026#34;) for word, count in counter.most_common(): print(f\u0026#34; {word}: {count}\u0026#34;) print(f\u0026#34;\\n总词汇数: {len(words)}\u0026#34;) print(f\u0026#34;不同词汇数: {len(counter)}\u0026#34;) 7.3 配置管理 # 模拟配置管理 default_config = { \u0026#34;debug\u0026#34;: False, \u0026#34;log_level\u0026#34;: \u0026#34;INFO\u0026#34;, \u0026#34;max_connections\u0026#34;: 100, \u0026#34;timeout\u0026#34;: 30, } user_config = { \u0026#34;debug\u0026#34;: True, \u0026#34;log_level\u0026#34;: \u0026#34;DEBUG\u0026#34;, } # 合并配置（用户配置覆盖默认配置） config = {**default_config, **user_config} print(config) # {\u0026#39;debug\u0026#39;: True, \u0026#39;log_level\u0026#39;: \u0026#39;DEBUG\u0026#39;, \u0026#39;max_connections\u0026#39;: 100, \u0026#39;timeout\u0026#39;: 30} 背诵版（核心要点） ┌─────────────────────────────────────────────────────────────┐ │ 字典 CRUD - 背诵版 │ ├─────────────────────────────────────────────────────────────┤ │ 【创建】 │ │ {} / dict() / dict(a=1) / dict([(1,2)]) / {x:y for x in} │ │ dict.fromkeys(keys, default) / d.copy() │ │ │ │ 【Read - 读取】 │ │ d[key] 键访问（键不存在报 KeyError） │ │ d.get(key, default) 安全访问（键不存在返回默认值） │ │ key in d / key not in d 键存在检测 │ │ d.keys() / d.values() / d.items() 键/值/键值对视图 │ │ │ │ 【Create - 创建/添加】 │ │ d[key] = value 添加/修改单个键值对 │ │ d.setdefault(k, v) 键不存在时设置默认值 │ │ d.update({k: v}) 批量添加/修改 │ │ │ │ 【Update - 更新】 │ │ d[key] = value 修改已有键的值 │ │ d.update(other_dict) 用字典更新 │ │ d.update(k=v) 用关键字参数更新 │ │ d1 | d2 Python 3.9\u0026#43; 合并 │ │ │ │ 【Delete - 删除】 │ │ d.pop(key) 删除键值对，返回值 │ │ d.pop(key, default) 键不存在返回默认值 │ │ d.popitem() 删除并返回最后一个键值对 │ │ del d[key] 按键删除 │ │ d.clear() 清空字典 │ └─────────────────────────────────────────────────────────────┘ 考前记忆（速记口诀） 【字典操作七字诀】 创建使用花括号，键值对来用冒号 get 安全访问王，键不存在返回 None setdefault 找键忙，不存在就设默认值 update 批量更新，pop 按键删除返回 popitem 删除尾巴，clear 清空全部 【字典方法记忆】 keys values items，三个视图要看清 get 读取最安全，setdefault 默认值 update 批量更新，pop 删除返回值 popitem 删末尾，copy 复制防共享 测试题 一、选择题 下面哪个可以正确创建一个空字典？\nA. [] B. {} C. () D. set() d.get(\u0026quot;name\u0026quot;, \u0026quot;未知\u0026quot;) 的作用是？\nA. 获取 \u0026ldquo;name\u0026rdquo; 键的值，如果不存在返回 \u0026ldquo;未知\u0026rdquo; B. 设置 \u0026ldquo;name\u0026rdquo; 键的默认值为 \u0026ldquo;未知\u0026rdquo; C. 删除 \u0026ldquo;name\u0026rdquo; 键 D. 返回所有键 d.setdefault(\u0026quot;age\u0026quot;, 25) 与 d[\u0026quot;age\u0026quot;] = 25 的区别是？\nA. 两者完全相同 B. setdefault 只在键不存在时设置 C. setdefault 只在键存在时返回 D. 后者会覆盖已存在的值 pop() 和 popitem() 的区别是？\nA. 两者完全相同 B. pop 按键删除，popitem 删除最后一个 C. pop 删除最后一个，popitem 按键删除 D. pop 返回键，popitem 返回值 update() 方法可以接受什么参数？\nA. 只能接受字典 B. 只能接受关键字参数 C. 可以接受字典、关键字参数或可迭代对象 D. 不能接受任何参数 dict.fromkeys([\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;], []) 的结果是？\nA. {\u0026quot;a\u0026quot;: [], \u0026quot;b\u0026quot;: []} B. {\u0026quot;a\u0026quot;: None, \u0026quot;b\u0026quot;: None} C. {\u0026quot;a\u0026quot;: \u0026quot;[]\u0026quot;, \u0026quot;b\u0026quot;: \u0026quot;[]\u0026quot;} D. 报错 Python 3.9+ 中，d1 | d2 的结果是？\nA. 修改 d1 B. 修改 d2 C. 返回新的合并字典 D. 返回布尔值 defaultdict 是哪个模块的类？\nA. sys B. collections C. itertools D. functools 字典的值可以是以下哪种类型？\nA. 列表 B. 字典 C. 集合 D. 以上都可以 d.keys() 返回的是什么类型？\nA. list B. tuple C. dict_keys D. set 二、填空题 字典的键必须是 _____ 类型（不可变/可变）。\npop() 方法删除键值对后返回 _____ 。\nsetdefault() 在键存在时返回 _____ （原值/默认值）。\nupdate() 方法可以接受的关键字参数语法是 d.update(**____)。\npopitem() 删除的是字典的 _____ 键值对（第一个/最后一个）。\nPython 3.7+ 保证字典保持 _____ 顺序。\nCounter 用于 _____ （计数/排序）。\n字典的浅拷贝方法有：copy()、dict(d)、_____ d。\nlen(d) 返回字典的 _____ 个数。\nd.clear() 后，字典变为 _____ 。\n三、编程题 写一个函数 merge_dicts(*dicts)，合并多个字典，键冲突时后面的覆盖前面的。\n写一个函数 invert_dict(d)，将字典的键值互换（值必须可哈希）。\n使用 defaultdict 实现一个函数 group_by_key(items, key_func)，按 key_func 分组 items。\n答案见下页\n测试题答案 选择题答案 题号 答案 解析 1 B {} 创建空字典，[] 创建空列表，set() 创建空集合 2 A get(key, default) 安全访问，键不存在返回默认值 3 B setdefault 只在键不存在时设置，已存在则返回原值 4 B pop 按键删除，popitem 删除最后一个（Python 3.7+） 5 C update() 非常灵活，可接受字典、关键字参数、可迭代对象 6 A fromkeys 用默认值创建，但注意共享引用问题 7 C ` 8 B defaultdict 在 collections 模块中 9 D 字典的值可以是任意类型，包括可变类型 10 C keys() 返回 dict_keys 视图对象 填空题答案 不可变 被删除的值 原值 字典 最后一个 插入 计数 {**d}（字典解包） 键值对 空字典 {} 编程题答案 答案1：合并多个字典\ndef merge_dicts(*dicts): \u0026#34;\u0026#34;\u0026#34;合并多个字典，键冲突时后面的覆盖前面的\u0026#34;\u0026#34;\u0026#34; result = {} for d in dicts: result.update(d) return result # 测试 d1 = {\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2} d2 = {\u0026#34;b\u0026#34;: 3, \u0026#34;c\u0026#34;: 4} d3 = {\u0026#34;c\u0026#34;: 5, \u0026#34;d\u0026#34;: 6} print(merge_dicts(d1, d2, d3)) # {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 3, \u0026#39;c\u0026#39;: 5, \u0026#39;d\u0026#39;: 6} 答案2：反转字典\ndef invert_dict(d): \u0026#34;\u0026#34;\u0026#34;将字典的键值互换\u0026#34;\u0026#34;\u0026#34; return {v: k for k, v in d.items()} # 测试 d = {\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2, \u0026#34;c\u0026#34;: 3} print(invert_dict(d)) # {1: \u0026#39;a\u0026#39;, 2: \u0026#39;b\u0026#39;, 3: \u0026#39;c\u0026#39;} # 如果值有重复会丢失数据 # d = {\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 1} # print(invert_dict(d)) # {1: \u0026#39;a\u0026#39;} - b 的值被丢弃 答案3：使用 defaultdict 分组\nfrom collections import defaultdict def group_by_key(items, key_func): \u0026#34;\u0026#34;\u0026#34;按 key_func 分组 items\u0026#34;\u0026#34;\u0026#34; groups = defaultdict(list) for item in items: key = key_func(item) groups[key].append(item) return dict(groups) # 测试 words = [\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;apricot\u0026#34;, \u0026#34;blueberry\u0026#34;, \u0026#34;cherry\u0026#34;] groups = group_by_key(words, lambda w: w[0]) print(groups) # {\u0026#39;a\u0026#39;: [\u0026#39;apple\u0026#39;, \u0026#39;apricot\u0026#39;], \u0026#39;b\u0026#39;: [\u0026#39;banana\u0026#39;, \u0026#39;blueberry\u0026#39;], \u0026#39;c\u0026#39;: [\u0026#39;cherry\u0026#39;]} 本课程完结\n","description":"深入学习Python字典的创建、读取、更新、删除等核心操作","permalink":"https://blog.uuworld.cn/python-course/python-day-16-dict-operations/","summary":"\u003ch1 id=\"python-day-16---字典-crud-get-pop-update-setdefault\"\u003ePython Day 16 - 字典 CRUD get pop update setdefault\u003c/h1\u003e\n\u003ch2 id=\"课程概述\"\u003e课程概述\u003c/h2\u003e\n\u003cp\u003e本节课将深入学习 Python 字典（Dictionary）这一核心数据结构。字典是 Python 中最灵活的内置数据类型之一，它以**键值对（Key-Value）**的形式存储数据，通过键来访问值，具有极高的查询效率。\u003c/p\u003e\n\u003cp\u003e本课程基于 \u003cstrong\u003ePython 3.11\u003c/strong\u003e 编写，所有示例均经过验证。我们将详细学习字典的 CRUD 操作（Create/创建、Read/读取、Update/更新、Delete/删除），以及 \u003ccode\u003eget\u003c/code\u003e、\u003ccode\u003epop\u003c/code\u003e、\u003ccode\u003eupdate\u003c/code\u003e、\u003ccode\u003esetdefault\u003c/code\u003e 等重要方法。\u003c/p\u003e\n\u003cp\u003e字典在 Python 中应用广泛：配置信息、JSON 数据、数据库记录映射、缓存系统、图结构等都用字典来实现。掌握字典是 Python 进阶的必经之路。\u003c/p\u003e\n\u003ch2 id=\"一字典基础概念\"\u003e一、字典基础概念\u003c/h2\u003e\n\u003ch3 id=\"11-什么是字典\"\u003e1.1 什么是字典\u003c/h3\u003e\n\u003cp\u003e字典是 Python 中的一种\u003cstrong\u003e无序\u003c/strong\u003e、\u003cstrong\u003e可变\u003c/strong\u003e的\u003cstrong\u003e键值对\u003c/strong\u003e集合。每个键值对由键（Key）和值（Value）组成，用冒号 \u003ccode\u003e:\u003c/code\u003e 分隔，键值对之间用逗号 \u003ccode\u003e,\u003c/code\u003e 分隔，整个字典用花括号 \u003ccode\u003e{ }\u003c/code\u003e 包围。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 字典的基本定义\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eempty_dict \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eperson \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;age\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e25\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;city\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;北京\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(person)  \u003cspan style=\"color:#75715e\"\u003e# {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(type(person))  \u003cspan style=\"color:#75715e\"\u003e# \u0026lt;class \u0026#39;dict\u0026#39;\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"12-字典的特点\"\u003e1.2 字典的特点\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e特点\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e键值对存储\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e数据以键值对形式存储，通过键访问值\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e键的唯一性\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e同一个字典中，键必须唯一，不能重复\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e键的可哈希性\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e键必须是不可变类型（字符串、数字、元组等）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e值的任意性\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e值可以是任意类型（列表、字典等可变对象也可以）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e无序性\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003ePython 3.7+ 字典保持插入顺序（但不是传统意义上的有序）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e高性能\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e键查找、添加、删除的时间复杂度为 O(1)\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"13-字典的创建方式\"\u003e1.3 字典的创建方式\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法1：使用花括号\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ed1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;age\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e25\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法2：使用 dict() 构造函数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ed2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e dict()  \u003cspan style=\"color:#75715e\"\u003e# 空字典\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ed3 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e dict(name\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;李四\u0026#34;\u003c/span\u003e, age\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 关键字参数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ed4 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e dict([(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;王五\u0026#34;\u003c/span\u003e), (\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;age\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e28\u003c/span\u003e)])  \u003cspan style=\"color:#75715e\"\u003e# 可迭代对象\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ed5 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e dict\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efromkeys([\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;b\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;c\u0026#34;\u003c/span\u003e], \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 从键列表创建，默认值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法3：字典推导式\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ed6 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {x: x \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e x \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e)}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方法4：字典的复制\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ed7 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e d1\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecopy()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(d1)  \u003cspan style=\"color:#75715e\"\u003e# {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(d2)  \u003cspan style=\"color:#75715e\"\u003e# {}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(d3)  \u003cspan style=\"color:#75715e\"\u003e# {\u0026#39;name\u0026#39;: \u0026#39;李四\u0026#39;, \u0026#39;age\u0026#39;: 30}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(d4)  \u003cspan style=\"color:#75715e\"\u003e# {\u0026#39;name\u0026#39;: \u0026#39;王五\u0026#39;, \u0026#39;age\u0026#39;: 28}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(d5)  \u003cspan style=\"color:#75715e\"\u003e# {\u0026#39;a\u0026#39;: 0, \u0026#39;b\u0026#39;: 0, \u0026#39;c\u0026#39;: 0}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(d6)  \u003cspan style=\"color:#75715e\"\u003e# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"14-键的要求\"\u003e1.4 键的要求\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 合法的键类型（不可变类型）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ed \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e,      \u003cspan style=\"color:#75715e\"\u003e# 字符串\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;整数键\u0026#34;\u003c/span\u003e,        \u003cspan style=\"color:#75715e\"\u003e# 整数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    (\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e): \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;元组键\u0026#34;\u003c/span\u003e,   \u003cspan style=\"color:#75715e\"\u003e# 元组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e3.14\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;浮点数键\u0026#34;\u003c/span\u003e,   \u003cspan style=\"color:#75715e\"\u003e# 浮点数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;布尔键\u0026#34;\u003c/span\u003e,     \u003cspan style=\"color:#75715e\"\u003e# 布尔值（True=1, False=0，会覆盖！）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 非法的键类型（可变类型）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# d = {[1, 2]: \u0026#34;列表键\u0026#34;}  # TypeError: unhashable type: \u0026#39;list\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# d = {{\u0026#34;a\u0026#34;: 1}: \u0026#34;字典键\u0026#34;}  # TypeError: unhashable type: \u0026#39;dict\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 键冲突：后面的值会覆盖前面的\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ed \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(d)  \u003cspan style=\"color:#75715e\"\u003e# {\u0026#39;a\u0026#39;: 3}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"二字典的读取操作read\"\u003e二、字典的读取操作（Read）\u003c/h2\u003e\n\u003ch3 id=\"21-通过键访问值\"\u003e2.1 通过键访问值\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eperson \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;age\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e25\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;city\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;北京\u0026#34;\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 通过键访问值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(person[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e])  \u003cspan style=\"color:#75715e\"\u003e# 张三\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(person[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;age\u0026#34;\u003c/span\u003e])   \u003cspan style=\"color:#75715e\"\u003e# 25\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 键不存在时，会抛出 KeyError\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# print(person[\u0026#34;gender\u0026#34;])  # KeyError: \u0026#39;gender\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"22-get-方法---安全访问\"\u003e2.2 get() 方法 - 安全访问\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003eget()\u003c/code\u003e 方法是访问字典值的安全方式，当键不存在时返回默认值而不是抛出异常。\u003c/p\u003e","tags":"Python, 字典, Dictionary, CRUD, CRUD操作","title":"Python Day 16 - 字典 CRUD get pop update setdefault"},{"columns":"acp-course","content":"阿里云安全概述 详细讲解 一、信息安全重大事件回顾 2017年勒索病毒大爆发 2017年5月12日，Windows敲诈勒索病毒大规模爆发，在全球大范围蔓延，感染用户主要集中在企业、高校等内网环境。此事件标志着网络攻击从技术炫耀转向利益驱动。\n2018年供应链攻击兴起 Memcache DDoS攻击：GitHub遭受1.35TB攻击，随后NETSCOUT确认1.7 Tbps反射放大攻击 GPON路由器漏洞：绕过验证漏洞(CVE-2018-10561)和命令注入漏洞(CVE-2018-10562)，十天内被僵尸网络利用传播 供应链攻击成为主要威胁形式 2019-2021年安全威胁持续升级 2019年\u0026quot;罗宾汉\u0026quot;勒索软件打瘫美国市政府，1万台电脑被入侵 2020年运维面板紧急安全更新，7.4.2版本存在严重漏洞 2021年国内多家银行、医疗机构感染incaseformat蠕虫病毒 二、信息安全基本概念 定义：涉及信息的保密性、完整性、可用性、真实性、可控性的相关技术和理论。\n本质：\n保护：系统的硬件、软件、数据 防止：系统和数据遭受破坏、更改、泄露 保证：系统连续可靠正常地运行，服务不中断 两个层面：\n技术层面：防止外部用户的非法入侵 管理层面：内部员工的教育和管理 三、云计算面临的安全威胁（CSA 12大威胁） 威胁类型 安全威胁 影响 可用性 DDoS攻击、僵尸网络 网站业务不可用 完整性 网站入侵、暴力破解 页面被篡改、植入后门 保密性 网站后门、数据库拖库 用户信息和敏感数据泄露 CSA 12大云计算安全威胁：\n数据泄露 2. 身份凭证不足 3. 不安全接口API 4. 系统漏洞 5. 账户劫持 6. 恶意内部人员 7. APT 8. 数据丢失 9. 尽职调查不足 10. 滥用云服务 11. DoS 12. 共享技术漏洞 四、阿里云安全体系 责任分担模型 云平台安全责任：云产品安全、虚拟化安全、硬件安全、物理安全 用户安全责任：用户账户安全、用户业务安全、用户应用安全、用户数据安全、用户基础安全 阿里云安全里程碑 2009年：飞天第一行代码，阿里云成立 2011年：推出\u0026quot;云盾\u0026quot;安全产品与服务 2017年：奥运会全球指定云服务商 2021年：发布108个云产品安全功能，服务超300万企业客户 安全能力 基础安全：DDoS防护、Web应用防火墙、云防火墙 业务安全：内容安全、实人认证、风险识别 数据与身份安全：数据安全中心、密钥管理、加密服务 云产品安全生命周期（SPLC） 安全左移，实现产品默认安全：立项→研发→测试→上线/变更→监控→应急响应\n背诵版 信息安全本质：\n保护：硬件、软件、数据 防止：破坏、更改、泄露 保证：连续可靠运行 两个层面：技术层面（防外部入侵）+ 管理层面（内部教育）\nCSA 12大威胁：数据泄露、凭证不足、不安全API、系统漏洞、账户劫持、恶意内部人员、APT、数据丢失、尽职调查不足、滥用云服务、DoS、共享技术漏洞\n阿里云安全责任分担：\n云平台：云产品安全、虚拟化安全、硬件安全、物理安全 用户：账户、业务、应用、数据、基础安全 阿里云里程碑：2009成立→2011云盾→2017奥运→2021服务300万客户\n速记版 信息安全 = 保硬件软件数据 + 防破坏更改泄露 + 保服务连续\n两层防护 = 技术防外 + 管理管内\nCSA威胁记忆：数据账户API漏洞，内外夹击APT，DoS共享最常见\n阿里云安全 = 平台负责底层 + 用户负责上层\n安全左移：立项→研发→测试→上线→监控→应急\n测试题 选择题 信息安全本质上不包含以下哪个方面？\nA. 保密性 B. 可用性 C. 完整性 D. 可移植性 CSA发布的12大云计算安全威胁中排名第一的是？\nA. 系统漏洞 B. 数据泄露 C. DDoS攻击 D. 账户劫持 阿里云安全体系中，用户不需要承担的安全责任是？\nA. 用户账户安全 B. 用户业务安全 C. 虚拟化安全 D. 用户数据安全 阿里云云盾安全产品与服务推出年份是？\nA. 2009年 B. 2011年 C. 2013年 D. 2017年 以下哪项不属于阿里云基础安全产品？\nA. DDoS防护 B. Web应用防火墙 C. 云防火墙 D. 风险识别 判断题 阿里云安全体系采用责任分担模型，云平台和用户各自承担相应安全责任。 2017年5月的勒索病毒只影响了欧洲地区，没有蔓延到亚洲。 阿里云是目前国内唯一云厂商整体安全能力获国际三大机构认可的。 云产品安全生命周期(SPLC)中，安全问题在监控阶段发现后才会进入应急响应。 阿里云每天成功分流约60亿次攻击。 答案 1.D | 2.B | 3.C | 4.B | 5.D\n6.√ | 7.× | 8.√ | 9.× | 10.√\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-16-acp-day-16-%E9%98%BF%E9%87%8C%E4%BA%91%E5%AE%89%E5%85%A8%E6%A6%82%E8%BF%B0/","summary":"\u003ch1 id=\"阿里云安全概述\"\u003e阿里云安全概述\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"一信息安全重大事件回顾\"\u003e一、信息安全重大事件回顾\u003c/h3\u003e\n\u003ch4 id=\"2017年勒索病毒大爆发\"\u003e2017年勒索病毒大爆发\u003c/h4\u003e\n\u003cp\u003e2017年5月12日，Windows敲诈勒索病毒大规模爆发，在全球大范围蔓延，感染用户主要集中在企业、高校等内网环境。此事件标志着网络攻击从技术炫耀转向利益驱动。\u003c/p\u003e\n\u003ch4 id=\"2018年供应链攻击兴起\"\u003e2018年供应链攻击兴起\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003eMemcache DDoS攻击：GitHub遭受1.35TB攻击，随后NETSCOUT确认1.7 Tbps反射放大攻击\u003c/li\u003e\n\u003cli\u003eGPON路由器漏洞：绕过验证漏洞(CVE-2018-10561)和命令注入漏洞(CVE-2018-10562)，十天内被僵尸网络利用传播\u003c/li\u003e\n\u003cli\u003e供应链攻击成为主要威胁形式\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"2019-2021年安全威胁持续升级\"\u003e2019-2021年安全威胁持续升级\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e2019年\u0026quot;罗宾汉\u0026quot;勒索软件打瘫美国市政府，1万台电脑被入侵\u003c/li\u003e\n\u003cli\u003e2020年运维面板紧急安全更新，7.4.2版本存在严重漏洞\u003c/li\u003e\n\u003cli\u003e2021年国内多家银行、医疗机构感染incaseformat蠕虫病毒\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"二信息安全基本概念\"\u003e二、信息安全基本概念\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e定义\u003c/strong\u003e：涉及信息的保密性、完整性、可用性、真实性、可控性的相关技术和理论。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e本质\u003c/strong\u003e：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e保护\u003c/strong\u003e：系统的硬件、软件、数据\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e防止\u003c/strong\u003e：系统和数据遭受破坏、更改、泄露\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e保证\u003c/strong\u003e：系统连续可靠正常地运行，服务不中断\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003e两个层面\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e技术层面\u003c/strong\u003e：防止外部用户的非法入侵\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e管理层面\u003c/strong\u003e：内部员工的教育和管理\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"三云计算面临的安全威胁csa-12大威胁\"\u003e三、云计算面临的安全威胁（CSA 12大威胁）\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e威胁类型\u003c/th\u003e\n          \u003cth\u003e安全威胁\u003c/th\u003e\n          \u003cth\u003e影响\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e可用性\u003c/td\u003e\n          \u003ctd\u003eDDoS攻击、僵尸网络\u003c/td\u003e\n          \u003ctd\u003e网站业务不可用\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e完整性\u003c/td\u003e\n          \u003ctd\u003e网站入侵、暴力破解\u003c/td\u003e\n          \u003ctd\u003e页面被篡改、植入后门\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e保密性\u003c/td\u003e\n          \u003ctd\u003e网站后门、数据库拖库\u003c/td\u003e\n          \u003ctd\u003e用户信息和敏感数据泄露\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cstrong\u003eCSA 12大云计算安全威胁\u003c/strong\u003e：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e数据泄露 2. 身份凭证不足 3. 不安全接口API 4. 系统漏洞 5. 账户劫持 6. 恶意内部人员 7. APT 8. 数据丢失 9. 尽职调查不足 10. 滥用云服务 11. DoS 12. 共享技术漏洞\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"四阿里云安全体系\"\u003e四、阿里云安全体系\u003c/h3\u003e\n\u003ch4 id=\"责任分担模型\"\u003e责任分担模型\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e云平台安全责任\u003c/strong\u003e：云产品安全、虚拟化安全、硬件安全、物理安全\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e用户安全责任\u003c/strong\u003e：用户账户安全、用户业务安全、用户应用安全、用户数据安全、用户基础安全\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"阿里云安全里程碑\"\u003e阿里云安全里程碑\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e2009年：飞天第一行代码，阿里云成立\u003c/li\u003e\n\u003cli\u003e2011年：推出\u0026quot;云盾\u0026quot;安全产品与服务\u003c/li\u003e\n\u003cli\u003e2017年：奥运会全球指定云服务商\u003c/li\u003e\n\u003cli\u003e2021年：发布108个云产品安全功能，服务超300万企业客户\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"安全能力\"\u003e安全能力\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e基础安全\u003c/strong\u003e：DDoS防护、Web应用防火墙、云防火墙\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e业务安全\u003c/strong\u003e：内容安全、实人认证、风险识别\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e数据与身份安全\u003c/strong\u003e：数据安全中心、密钥管理、加密服务\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"云产品安全生命周期splc\"\u003e云产品安全生命周期（SPLC）\u003c/h4\u003e\n\u003cp\u003e安全左移，实现产品默认安全：立项→研发→测试→上线/变更→监控→应急响应\u003c/p\u003e","tags":"","title":"Day16 阿里云安全概述"},{"columns":"python-course","content":" 来源：黑马程序员Python基础课程 + Python 3.11官方文档 + 网络资料整理\n一、详细讲解 1.1 字典遍历三种方式 Python 字典提供三个核心视图对象，用于遍历键、值或键值对：\nperson = {\u0026#34;name\u0026#34;: \u0026#34;小明\u0026#34;, \u0026#34;age\u0026#34;: 18, \u0026#34;city\u0026#34;: \u0026#34;北京\u0026#34;, \u0026#34;job\u0026#34;: \u0026#34;工程师\u0026#34;} # 遍历所有键（最常用） for key in person: print(f\u0026#34;{key}: {person[key]}\u0026#34;) # 遍历所有键（显式） for key in person.keys(): print(key) # 遍历所有值 for value in person.values(): print(value) # 遍历键值对（最推荐） for key, value in person.items(): print(f\u0026#34;{key}: {value}\u0026#34;) 输出：\nname: 小明 age: 18 city: 北京 job: 工程师 小明 18 北京 工程师 name: 小明 age: 18 city: 北京 job: 工程师1.2 items() 视图对象的高级用法 items() 返回的是视图对象，不是列表，具有内存高效的特点：\n# 并行遍历两个字典（按键对齐） dict1 = {\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2, \u0026#34;c\u0026#34;: 3} dict2 = {\u0026#34;a\u0026#34;: 10, \u0026#34;b\u0026#34;: 20, \u0026#34;c\u0026#34;: 30} for (k1, v1), (k2, v2) in zip(dict1.items(), dict2.items()): print(f\u0026#34;{k1}={v1}, {k2}={v2}, sum={v1+v2}\u0026#34;) # 判断键是否存在 if \u0026#34;name\u0026#34; in person.keys(): print(\u0026#34;有name键\u0026#34;) # 字典键值对数量 print(f\u0026#34;共 {len(person.items())} 个键值对\u0026#34;) 1.3 Python 3.9+ 字典合并运算符 Python 3.9 引入了两个新的字典运算符：\n# | 合并运算符（不修改原字典） dict1 = {\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2} dict2 = {\u0026#34;b\u0026#34;: 3, \u0026#34;c\u0026#34;: 4} merged = dict1 | dict2 print(merged) # {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 3, \u0026#39;c\u0026#39;: 4} 注意：dict2的值会覆盖dict1 # |= 就地合并运算符 dict1 |= dict2 print(dict1) # {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 3, \u0026#39;c\u0026#39;: 4} # 对比 update()（Python 3.5+） dict1 = {\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2} dict2 = {\u0026#34;b\u0026#34;: 3, \u0026#34;c\u0026#34;: 4} dict1.update(dict2) print(dict1) # {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 3, \u0026#39;c\u0026#39;: 4} 1.4 嵌套字典 字典的值可以是另一个字典，形成嵌套结构：\n# 嵌套字典：多个用户的信息 users = { \u0026#34;user1\u0026#34;: { \u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25, \u0026#34;skills\u0026#34;: [\u0026#34;Python\u0026#34;, \u0026#34;Java\u0026#34;] }, \u0026#34;user2\u0026#34;: { \u0026#34;name\u0026#34;: \u0026#34;李四\u0026#34;, \u0026#34;age\u0026#34;: 30, \u0026#34;skills\u0026#34;: [\u0026#34;Go\u0026#34;, \u0026#34;Rust\u0026#34;] } } # 访问嵌套数据 print(users[\u0026#34;user1\u0026#34;][\u0026#34;name\u0026#34;]) # 张三 print(users[\u0026#34;user2\u0026#34;][\u0026#34;skills\u0026#34;][0]) # Go # 遍历嵌套字典 for user_id, user_info in users.items(): print(f\u0026#34;\\n用户ID: {user_id}\u0026#34;) for key, value in user_info.items(): print(f\u0026#34; {key}: {value}\u0026#34;) # 添加新用户 users[\u0026#34;user3\u0026#34;] = { \u0026#34;name\u0026#34;: \u0026#34;王五\u0026#34;, \u0026#34;age\u0026#34;: 28, \u0026#34;skills\u0026#34;: [\u0026#34;Python\u0026#34;, \u0026#34;Go\u0026#34;] } # 修改嵌套值 users[\u0026#34;user1\u0026#34;][\u0026#34;age\u0026#34;] = 26 users[\u0026#34;user1\u0026#34;][\u0026#34;skills\u0026#34;].append(\u0026#34;Go\u0026#34;) 1.5 字典推导式 类似列表推导式，字典也有推导式语法：\n# 基本字典推导式 nums = [1, 2, 3, 4, 5] squares = {x: x**2 for x in nums} print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25} # 带条件的字典推导式 nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] even_squares = {x: x**2 for x in nums if x % 2 == 0} print(even_squares) # {2: 4, 4: 16, 6: 36, 8: 64, 10: 100} # 键值对互换（值必须可哈希） original = {\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2, \u0026#34;c\u0026#34;: 3} swapped = {v: k for k, v in original.items()} print(swapped) # {1: \u0026#39;a\u0026#39;, 2: \u0026#39;b\u0026#39;, 3: \u0026#39;c\u0026#39;} # 实际应用：从列表创建频率统计 words = [\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;apple\u0026#34;, \u0026#34;orange\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;apple\u0026#34;] word_freq = {word: words.count(word) for word in set(words)} print(word_freq) # {\u0026#39;apple\u0026#39;: 3, \u0026#39;banana\u0026#39;: 2, \u0026#39;orange\u0026#39;: 1} 1.6 setdefault() 方法 setdefault() 在键不存在时设置默认值，已存在则返回现有值：\n# 基本用法 person = {\u0026#34;name\u0026#34;: \u0026#34;小明\u0026#34;, \u0026#34;age\u0026#34;: 18} # 键不存在，设置默认值 job = person.setdefault(\u0026#34;job\u0026#34;, \u0026#34;工程师\u0026#34;) print(person) # {\u0026#39;name\u0026#39;: \u0026#39;小明\u0026#39;, \u0026#39;age\u0026#39;: 18, \u0026#39;job\u0026#39;: \u0026#39;工程师\u0026#39;} # 键已存在，返回现有值，不覆盖 result = person.setdefault(\u0026#34;name\u0026#34;, \u0026#34;老明\u0026#34;) print(person[\u0026#34;name\u0026#34;]) # 小明（未被修改） print(result) # 小明 # 实际应用：分组统计 groups = {} fruits = [(\u0026#34;红\u0026#34;, \u0026#34;苹果\u0026#34;), (\u0026#34;黄\u0026#34;, \u0026#34;香蕉\u0026#34;), (\u0026#34;红\u0026#34;, \u0026#34;草莓\u0026#34;), (\u0026#34;黄\u0026#34;, \u0026#34;橙子\u0026#34;)] for color, fruit in fruits: if color not in groups: groups[color] = [] groups[color].append(fruit) print(groups) # {\u0026#39;红\u0026#39;: [\u0026#39;苹果\u0026#39;, \u0026#39;草莓\u0026#39;], \u0026#39;黄\u0026#39;: [\u0026#39;香蕉\u0026#39;, \u0026#39;橙子\u0026#39;]} 二、背诵版 遍历 → for k,v in d.items() 键列表 → list(d.keys()) 值列表 → list(d.values()) 合并 → d1 | d2（Python 3.9\u0026#43;） 就地合并 → d1 |= d2 嵌套访问 → dict[nested][key] 字典推导式 → {k:v for k,v in d.items() if condition} setdefault → 键不存在设默认值，已存在返回现有值 三、考前记忆 方法/操作 说明 返回值 d.keys() 所有键 dict_keys 视图 d.values() 所有值 dict_values 视图 d.items() 所有键值对 dict_items 视图 d.get(k, default) 安全访问，不报错 值或默认值 d.setdefault(k, v) 键不存在设默认值 现有值或新值 d1 | d2 合并（Python 3.9+） 新字典 d1 |= d2 就地合并 None {k:v for k,v in d.items()} 字典推导式 字典 四、测试题 1. 单选题： 以下哪个方法能安全获取字典中不存在的键而不报错？\nA. d[\u0026quot;key\u0026quot;] B. d.get(\u0026quot;key\u0026quot;) C. d[\u0026quot;key\u0026quot;] = None D. d.key 2. 单选题： Python 3.9 中，{\u0026quot;a\u0026quot;:1} | {\u0026quot;a\u0026quot;:2} 的结果是？\nA. {\u0026quot;a\u0026quot;:1} B. {\u0026quot;a\u0026quot;:2} C. {\u0026quot;a\u0026quot;:1, \u0026quot;a\u0026quot;:2}（报错） D. {\u0026quot;a\u0026quot;:[1,2]} 3. 判断题： d.items() 返回的是一个列表，可以直接用索引访问。\n4. 填空题： 遍历字典所有键值对，应使用 for ______ in d.items()。\n5. 填空题： 将两个字典合并且不修改原字典，应使用运算符 ______。\n6. 简答题： 比较 d.update(other) 和 d |= other 的区别。\n7. 代码题： 写出以下数据的字典推导式： 原始列表：[1, 2, 3, 4, 5] 要求：生成字典，键为数字，值为该数字的立方（仅偶数）\nB（get() 访问不存在的键返回 None，不报错） B（| 运算符中，右边字典的值会覆盖左边的） ×（items() 返回视图对象，不是列表） key, value（或 k, v） |（管道运算符） update() 和 |= 都用于合并字典，但 |= 是 Python 3.9+ 的新语法，两者效果相似但 |= 更简洁。 nums = [1, 2, 3, 4, 5] cubes = {x: x**3 for x in nums if x % 2 == 0} print(cubes) # {2: 8, 4: 64} ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-17-dict-traversal/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：黑马程序员Python基础课程 + Python 3.11官方文档 + 网络资料整理\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-字典遍历三种方式\"\u003e1.1 字典遍历三种方式\u003c/h3\u003e\n\u003cp\u003ePython 字典提供三个核心视图对象，用于遍历键、值或键值对：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eperson \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;小明\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;age\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e18\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;city\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;北京\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;job\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;工程师\u0026#34;\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 遍历所有键（最常用）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e key \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e person:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ekey\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eperson[key]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 遍历所有键（显式）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e key \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e person\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ekeys():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(key)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 遍历所有值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e value \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e person\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003evalues():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(value)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 遍历键值对（最推荐）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e key, value \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e person\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eitems():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ekey\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003evalue\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e输出：\u003c/strong\u003e\u003c/p\u003e\nname: 小明\nage: 18\ncity: 北京\njob: 工程师\n小明\n18\n北京\n工程师\nname: 小明\nage: 18\ncity: 北京\njob: 工程师\u003ch3 id=\"12-items-视图对象的高级用法\"\u003e1.2 items() 视图对象的高级用法\u003c/h3\u003e\n\u003cp\u003eitems() 返回的是视图对象，不是列表，具有内存高效的特点：\u003c/p\u003e","tags":"Python, 编程, 字典","title":"Day17 字典遍历与嵌套"},{"columns":"acp-course","content":"网络安全 详细讲解 一、阿里云DDoS防护 DDoS攻击介绍 分布式拒绝服务（Distributed Denial of Service，简称DDoS）将多台计算机联合起来作为攻击平台，通过远程连接利用恶意程序，对一个或多个目标发起DDoS攻击，消耗目标服务器性能或网络带宽，从而造成服务器无法正常地提供服务。\nDDoS危害：\n重大经济损失 数据泄露 恶意竞争 常见DDoS攻击类型 类型 攻击方式 畸形报文 Frag Flood、Smurf、Stream Flood、Land Flood等 传输层DDoS Syn Flood、Ack Flood、UDP Flood、ICMP Request Flood等 DNS DDoS DNS Query Flood、权威服务器攻击、Local服务器攻击等 连接型DDoS TCP慢速连接、Loic、Hoic、Slowloris等 Web应用层DDoS HTTP Get Flood、HTTP Post Flood、CC攻击 阿里云DDoS防护产品线 产品 特点 适用场景 DDoS原生防护基础版 免费提供最大5Gbps防护 基础防护 DDoS原生防护企业版 透明防护，一键添加 需要多IP防护 DDoS高防 Tbps级防护，全协议防护 网站、游戏、金融 游戏盾 专防TCP协议CC攻击 游戏行业 DDoS原生防护工作原理 直接为阿里云公网IP资产提升DDoS攻击防御能力 主要提供三层和四层流量型攻击防御 超出清洗阈值后自动触发流量清洗 通过旁路部署方式建设DDoS攻击检测及清洗系统 DDoS高防工作原理 支持DNS解析和IP直接指向两种引流方式 正常访问流量通过端口协议转发返回源站 恶意攻击流量在高防流量清洗中心过滤 二、Web应用防火墙（WAF） WAF背景 传统WAF痛点：\n80%用不上 50%无法应用复杂业务 30%误报机率大 无专人后续运维 产品升级慢、流程复杂 阿里云WAF核心能力 0day漏洞防护：自动防御补丁规则 Web应用防护：防御OWASP常见威胁 CC防护：拦截恶意肉鸡请求 业务风控：防刷、防爬、防撞库 WAF工作原理 浏览器输入域名访问 DNS服务器解析到WAF集群地址 访问流量到达WAF防护集群进行清洗 干净流量根据域名回源到真实服务器 响应内容回到WAF进行双向检测 WAF产品优势 10年以上网络安全经验 集成大数据能力 防御CC攻击和爬虫攻击 5分钟内部署和激活 无需安装软硬件或调整路由 三、云防火墙 云防火墙定位 业界首款Saa化防火墙，云原生的云上边界网络安全防护产品，是业务上云的第一道网络防线。\n四大核心能力 全网流量可视可控：实时展示资产情况、流量趋势 漏洞实时防护：同步网络侧可被攻击的漏洞 失陷止血防护：结合情报智能发现挖矿等失陷资产 一键开启：秒级接入，即刻防御 技术原理 东西向流量控制模块：利用安全组对主机间交互流量控制 南北向流量控制模块：互联网到主机间的访问控制 产品功能 精细化访问控制 资产暴露管理 安全正向代理 入侵检测与防御IPS 主动外连检测与封禁 网络日志审计 背诵版 DDoS攻击类型：\n畸形报文：Frag Flood、Smurf、Land Flood 传输层：Syn Flood、UDP Flood、Ack Flood DNS：Query Flood、权威服务器攻击 连接型：Slowloris、Pyloris Web层：HTTP Get/Post Flood、CC 阿里云DDoS防护产品：\n原生防护基础版：免费5Gbps 原生防护企业版：透明防护 DDoS高防：Tbps级防护 游戏盾：专防TCP CC WAF核心能力：0day防护 + Web防护 + CC防护 + 业务风控\n云防火墙四大能力：全网流量可视 + 漏洞实时防护 + 失陷止血 + 一键开启\nWAF工作原理：DNS解析→WAF集群→清洗→回源→双向检测\n速记版 DDoS攻击 = 多机联合 + 耗尽资源 + 服务不可\nDDoS防护产品线：基础免费、企业透明、高防Tbps、游戏盾专防TCP\nWAF = 网站必备 + 0day/Web/CC/风控\n云防火墙 = SaaS化 + 东西南北向控制 + IPS/日志审计\nWAF原理：域名→WAF集群→清洗→回源→双向检测\n测试题 选择题 以下哪种不属于DDoS攻击类型？\nA. Syn Flood B. XSS攻击 C. UDP Flood D. HTTP Get Flood 阿里云DDoS原生防护基础版提供多少Gbps免费防护？\nA. 1Gbps B. 3Gbps C. 5Gbps D. 10Gbps WAF的中文名称是？\nA. Web应用防火墙 B. 网络防火墙 C. 分布式防火墙 D. 应用代理防火墙 云防火墙是业界首款什么类型的防火墙？\nA. 硬件防火墙 B. 软件防火墙 C. SaaS化防火墙 D. 下一代防火墙 WAF工作流程中，DNS解析后域名指向什么？\nA. 源站服务器 B. WAF集群地址 C. 负载均衡器 D. CDN节点 判断题 DDoS攻击可以将多台计算机联合起来作为攻击平台。 游戏盾主要用于防护UDP协议的DDoS攻击。 阿里云WAF需要复杂的网络接入配置才能使用。 云防火墙的东西向流量控制主要用于实现互联网到主机的访问控制。 WAF的0day漏洞防护可以自动防御最新曝出的Web 0day漏洞。 答案 1.B | 2.C | 3.A | 4.C | 5.B\n6.√ | 7.× | 8.× | 9.× | 10.√\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-17-acp-day-17-%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/","summary":"\u003ch1 id=\"网络安全\"\u003e网络安全\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"一阿里云ddos防护\"\u003e一、阿里云DDoS防护\u003c/h3\u003e\n\u003ch4 id=\"ddos攻击介绍\"\u003eDDoS攻击介绍\u003c/h4\u003e\n\u003cp\u003e分布式拒绝服务（Distributed Denial of Service，简称DDoS）将多台计算机联合起来作为攻击平台，通过远程连接利用恶意程序，对一个或多个目标发起DDoS攻击，消耗目标服务器性能或网络带宽，从而造成服务器无法正常地提供服务。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDDoS危害\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e重大经济损失\u003c/li\u003e\n\u003cli\u003e数据泄露\u003c/li\u003e\n\u003cli\u003e恶意竞争\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"常见ddos攻击类型\"\u003e常见DDoS攻击类型\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e类型\u003c/th\u003e\n          \u003cth\u003e攻击方式\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e畸形报文\u003c/td\u003e\n          \u003ctd\u003eFrag Flood、Smurf、Stream Flood、Land Flood等\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e传输层DDoS\u003c/td\u003e\n          \u003ctd\u003eSyn Flood、Ack Flood、UDP Flood、ICMP Request Flood等\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDNS DDoS\u003c/td\u003e\n          \u003ctd\u003eDNS Query Flood、权威服务器攻击、Local服务器攻击等\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e连接型DDoS\u003c/td\u003e\n          \u003ctd\u003eTCP慢速连接、Loic、Hoic、Slowloris等\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eWeb应用层DDoS\u003c/td\u003e\n          \u003ctd\u003eHTTP Get Flood、HTTP Post Flood、CC攻击\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"阿里云ddos防护产品线\"\u003e阿里云DDoS防护产品线\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e产品\u003c/th\u003e\n          \u003cth\u003e特点\u003c/th\u003e\n          \u003cth\u003e适用场景\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDDoS原生防护基础版\u003c/td\u003e\n          \u003ctd\u003e免费提供最大5Gbps防护\u003c/td\u003e\n          \u003ctd\u003e基础防护\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDDoS原生防护企业版\u003c/td\u003e\n          \u003ctd\u003e透明防护，一键添加\u003c/td\u003e\n          \u003ctd\u003e需要多IP防护\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDDoS高防\u003c/td\u003e\n          \u003ctd\u003eTbps级防护，全协议防护\u003c/td\u003e\n          \u003ctd\u003e网站、游戏、金融\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e游戏盾\u003c/td\u003e\n          \u003ctd\u003e专防TCP协议CC攻击\u003c/td\u003e\n          \u003ctd\u003e游戏行业\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"ddos原生防护工作原理\"\u003eDDoS原生防护工作原理\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e直接为阿里云公网IP资产提升DDoS攻击防御能力\u003c/li\u003e\n\u003cli\u003e主要提供三层和四层流量型攻击防御\u003c/li\u003e\n\u003cli\u003e超出清洗阈值后自动触发流量清洗\u003c/li\u003e\n\u003cli\u003e通过旁路部署方式建设DDoS攻击检测及清洗系统\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"ddos高防工作原理\"\u003eDDoS高防工作原理\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e支持DNS解析和IP直接指向两种引流方式\u003c/li\u003e\n\u003cli\u003e正常访问流量通过端口协议转发返回源站\u003c/li\u003e\n\u003cli\u003e恶意攻击流量在高防流量清洗中心过滤\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"二web应用防火墙waf\"\u003e二、Web应用防火墙（WAF）\u003c/h3\u003e\n\u003ch4 id=\"waf背景\"\u003eWAF背景\u003c/h4\u003e\n\u003cp\u003e传统WAF痛点：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e80%用不上\u003c/li\u003e\n\u003cli\u003e50%无法应用复杂业务\u003c/li\u003e\n\u003cli\u003e30%误报机率大\u003c/li\u003e\n\u003cli\u003e无专人后续运维\u003c/li\u003e\n\u003cli\u003e产品升级慢、流程复杂\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"阿里云waf核心能力\"\u003e阿里云WAF核心能力\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e0day漏洞防护\u003c/strong\u003e：自动防御补丁规则\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eWeb应用防护\u003c/strong\u003e：防御OWASP常见威胁\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCC防护\u003c/strong\u003e：拦截恶意肉鸡请求\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e业务风控\u003c/strong\u003e：防刷、防爬、防撞库\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"waf工作原理\"\u003eWAF工作原理\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e浏览器输入域名访问\u003c/li\u003e\n\u003cli\u003eDNS服务器解析到WAF集群地址\u003c/li\u003e\n\u003cli\u003e访问流量到达WAF防护集群进行清洗\u003c/li\u003e\n\u003cli\u003e干净流量根据域名回源到真实服务器\u003c/li\u003e\n\u003cli\u003e响应内容回到WAF进行双向检测\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"waf产品优势\"\u003eWAF产品优势\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e10年以上网络安全经验\u003c/li\u003e\n\u003cli\u003e集成大数据能力\u003c/li\u003e\n\u003cli\u003e防御CC攻击和爬虫攻击\u003c/li\u003e\n\u003cli\u003e5分钟内部署和激活\u003c/li\u003e\n\u003cli\u003e无需安装软硬件或调整路由\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"三云防火墙\"\u003e三、云防火墙\u003c/h3\u003e\n\u003ch4 id=\"云防火墙定位\"\u003e云防火墙定位\u003c/h4\u003e\n\u003cp\u003e业界首款Saa化防火墙，云原生的云上边界网络安全防护产品，是业务上云的第一道网络防线。\u003c/p\u003e","tags":"","title":"Day17 网络安全"},{"columns":"python-course","content":" 来源：黑马程序员Python基础课程 + Python 3.11官方文档 + 网络资料整理\n一、详细讲解 1.1 字符串基本特性 Python 字符串是不可变序列（Immutable Sequence），所有修改操作都会返回新字符串：\ns = \u0026#34;Hello\u0026#34; # s[0] = \u0026#34;J\u0026#34; # TypeError: \u0026#39;str\u0026#39; object does not support item assignment # 正确做法：创建新字符串 s2 = \u0026#34;J\u0026#34; + s[1:] print(s2) # Jello # 字符串长度 print(len(\u0026#34;Hello\u0026#34;)) # 5 1.2 字符串索引与切片 s = \u0026#34;Python是最流行的编程语言\u0026#34; # 正向索引（从0开始） print(s[0]) # P print(s[7]) # 是 # 反向索引（从-1开始） print(s[-1]) # 言 print(s[-4]) # 编 # 切片 s[start:end:step] print(s[0:6]) # Python（不含end） print(s[7:10]) # 是最流 print(s[:6]) # Python（省略start=0） print(s[7:]) # 是最流行的编程语言（省略end=len） print(s[::2]) # Pto无流编言言（步长2） print(s[::-1]) # 言语言程编的行流最是（逆序） 1.3 常用字符串方法 查找与替换：\ns = \u0026#34;Hello World, Hello Python\u0026#34; # find/rindex：查找子串位置（找不到返回-1 或 抛异常） print(s.find(\u0026#34;World\u0026#34;)) # 6 print(s.find(\u0026#34;Java\u0026#34;)) # -1 print(s.rfind(\u0026#34;Hello\u0026#34;)) # 13（从右向左找） # count：统计出现次数 print(s.count(\u0026#34;Hello\u0026#34;)) # 2 # replace：替换（返回新字符串） s2 = s.replace(\u0026#34;Hello\u0026#34;, \u0026#34;Hi\u0026#34;) print(s2) # Hi World, Hi Python # partition/rpartition：分割为三部分 print(s.partition(\u0026#34;World\u0026#34;)) # (\u0026#39;Hello \u0026#39;, \u0026#39;World\u0026#39;, \u0026#39;, Hello Python\u0026#39;) print(s.rpartition(\u0026#34;Hello\u0026#34;)) # (\u0026#39;Hello World, \u0026#39;, \u0026#39;Hello\u0026#39;, \u0026#39; Python\u0026#39;) 大小写转换：\ns = \u0026#34;Hello World\u0026#34; print(s.upper()) # HELLO WORLD（全转大写） print(s.lower()) # hello world（全转小写） print(s.swapcase()) # hELLO wORLD（大写变小写，小写变大写） print(s.title()) # Hello World（每个词首字母大写） print(s.capitalize()) # Hello world（首字母大写，其余小写） 去空格与对齐：\ns = \u0026#34; Hello World \u0026#34; print(s.strip()) # Hello World（去除两端空格） print(s.lstrip()) # Hello World （去除左端） print(s.rstrip()) # Hello World（去除右端） # 去除指定字符 print(\u0026#34;!!Hello!!\u0026#34;.strip(\u0026#34;!\u0026#34;)) # Hello print(\u0026#34;abHelloab\u0026#34;.strip(\u0026#34;ab\u0026#34;)) # Hello # 填充对齐 print(\u0026#34;Hello\u0026#34;.ljust(10)) # Hello （左对齐，填充右空格） print(\u0026#34;Hello\u0026#34;.rjust(10)) # Hello（右对齐，填充左空格） print(\u0026#34;Hello\u0026#34;.center(10)) # Hello （居中对齐） print(\u0026#34;Hello\u0026#34;.zfill(10)) # 00000Hello（零填充） 判断方法（返回布尔值）：\nprint(\u0026#34;Hello123\u0026#34;.isalnum()) # True（字母或数字） print(\u0026#34;Hello\u0026#34;.isalpha()) # True（全是字母） print(\u0026#34;123\u0026#34;.isdigit()) # True（全是数字） print(\u0026#34;123\u0026#34;.isnumeric()) # True（Unicode数字） print(\u0026#34;123.5\u0026#34;.isdecimal()) # False（小数点） print(\u0026#34;hello\u0026#34;.islower()) # True（全小写） print(\u0026#34;HELLO\u0026#34;.isupper()) # True（全大写） print(\u0026#34;Hello World\u0026#34;.istitle()) # True（每个词首字母大写） print(\u0026#34; \u0026#34;.isspace()) # True（全是空格） print(\u0026#34;Hello\u0026#34;.startswith(\u0026#34;He\u0026#34;)) # True（以...开头） print(\u0026#34;Hello\u0026#34;.endswith(\u0026#34;lo\u0026#34;)) # True（以...结尾） 1.4 字符串分割与拼接 s = \u0026#34;apple, banana, orange, grape\u0026#34; # split：分割（返回列表） parts = s.split(\u0026#34;, \u0026#34;) print(parts) # [\u0026#39;apple\u0026#39;, \u0026#39;banana\u0026#39;, \u0026#39;orange\u0026#39;, \u0026#39;grape\u0026#39;] # rsplit：从右向左分割（maxsplit次） print(s.rsplit(\u0026#34;, \u0026#34;, 1)) # [\u0026#39;apple, banana, orange\u0026#39;, \u0026#39;grape\u0026#39;] # splitlines：按换行符分割 text = \u0026#34;Line1\\nLine2\\r\\nLine3\u0026#34; print(text.splitlines()) # [\u0026#39;Line1\u0026#39;, \u0026#39;Line2\u0026#39;, \u0026#39;Line3\u0026#39;] # partition/rpartition url = \u0026#34;https://blog.uuworld.cn\u0026#34; print(url.partition(\u0026#34;://\u0026#34;)) # (\u0026#39;https\u0026#39;, \u0026#39;://\u0026#39;, \u0026#39;blog.uuworld.cn\u0026#39;) # join：拼接（最常用） fruits = [\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;orange\u0026#34;] print(\u0026#34;, \u0026#34;.join(fruits)) # apple, banana, orange # 实际应用：文件路径拼接 import os path = os.path.join(\u0026#34;home\u0026#34;, \u0026#34;user\u0026#34;, \u0026#34;docs\u0026#34;, \u0026#34;file.txt\u0026#34;) print(path) # home/user/docs/file.txt 1.5 f-string 格式化（Python 3.6+，重点） name = \u0026#34;小明\u0026#34; age = 18 score = 95.567 # 基本用法 print(f\u0026#34;姓名：{name}，年龄：{age}\u0026#34;) # 输出：姓名：小明，年龄：18 # 表达式 print(f\u0026#34;10年后年龄：{age + 10}\u0026#34;) # 输出：10年后年龄：28 # 格式说明符 print(f\u0026#34;分数：{score:.2f}\u0026#34;) # 分数：95.57 print(f\u0026#34;分数：{score:8.2f}\u0026#34;) # 95.57（总宽度8右对齐） print(f\u0026#34;百分比：{0.856:.1%}\u0026#34;) # 百分比：85.6% print(f\u0026#34;科学计数：{1234567:.2e}\u0026#34;) # 1.23e+06 # Python 3.8+ 调试语法（重要！） x = 10 y = 20 print(f\u0026#34;{x=}, {y=}, {x+y=}\u0026#34;) # 输出：x=10, y=20, x+y=30 1.6 字符串编码 # 字符串与字节串转换 s = \u0026#34;Hello世界\u0026#34; b = s.encode(\u0026#34;utf-8\u0026#34;) # 字符串 -\u0026gt; 字节 print(b) # b\u0026#39;Hello\\xe4\\xb8\\x96\\xe7\\x95\\x8c\u0026#39; print(len(b)) # 13（UTF-8中文字占3字节） # 字节转回字符串 s2 = b.decode(\u0026#34;utf-8\u0026#34;) print(s2) # Hello世界 # ASCII 转数字 print(ord(\u0026#34;A\u0026#34;)) # 65 print(chr(65)) # A 二、背诵版 不可变 → 一切修改返回新字符串 切片 → s[start:end:step]，step负数逆序 strip()去空格 → lstrip/rstrip split()分割 → join()拼接 replace()替换 → count()统计 upper/lower/title → 大小写转换 f-string → f\u0026#34;{x=}\u0026#34; 调试语法（Python 3.8\u0026#43;） format → \u0026#34;{:.2f}\u0026#34;.format(x) encode → decode（UTF-8中文3字节） 三、考前记忆 方法 功能 示例结果 s.upper()/lower() 大小写 \u0026quot;Hello\u0026quot;.upper() → \u0026quot;HELLO\u0026quot; s.strip() 去两端空格 \u0026quot; hi \u0026quot;.strip() → \u0026quot;hi\u0026quot; s.split() 分割为列表 \u0026quot;a,b\u0026quot;.split(\u0026quot;,\u0026quot;) → [\u0026quot;a\u0026quot;,\u0026quot;b\u0026quot;] \u0026quot;,\u0026quot;.join(lst) 列表拼接 \u0026quot;,\u0026quot;.join([\u0026quot;a\u0026quot;,\u0026quot;b\u0026quot;]) → \u0026quot;a,b\u0026quot; s.find(sub) 查找位置 \u0026quot;abc\u0026quot;.find(\u0026quot;b\u0026quot;) → 1 s.replace() 替换 \u0026quot;aab\u0026quot;.replace(\u0026quot;a\u0026quot;,\u0026quot;c\u0026quot;) → \u0026quot;ccb\u0026quot; s[start:end] 切片 \u0026quot;hello\u0026quot;[1:4] → \u0026quot;ell\u0026quot; f\u0026quot;{x=}\u0026quot; 调试f串 x=10 → \u0026quot;x=10\u0026quot;（3.8+） 四、测试题 1. 单选题： \u0026quot;Hello\u0026quot;.replace(\u0026quot;l\u0026quot;, \u0026quot;x\u0026quot;) 的结果是？\nA. \u0026quot;Hexlo\u0026quot; B. \u0026quot;Hexxo\u0026quot; C. \u0026quot;Hello\u0026quot; D. 报错 2. 单选题： 关于字符串的说法，正确的是？\nA. 字符串可变，可以直接修改 B. \u0026quot;hello\u0026quot;[::-1] 得到 \u0026quot;olleh\u0026quot; C. split() 和 join() 作用相同 D. strip() 只去除左端空格 3. 判断题： Python 3.8 新增的 f\u0026quot;{x=}\u0026quot; 语法可以同时输出变量名和值。\n4. 填空题： \u0026quot;hello world\u0026quot;.split(\u0026quot;o\u0026quot;) 的结果是 ______。\n5. 简答题： 说明 s.find(\u0026quot;x\u0026quot;) 和 s.index(\u0026quot;x\u0026quot;) 的区别。\n6. 代码题： 用一句话统计字符串 \u0026quot;ababa\u0026quot; 中 \u0026quot;ab\u0026quot; 出现的次数。\nB（replace 替换所有匹配） B（[::-1] 步长-1 表示逆序） ✓ [\u0026quot;hell\u0026quot;, \u0026quot; w\u0026quot;, \u0026quot;rld\u0026quot;] find() 找不到返回 -1，不报错；index() 找不到会抛 ValueError 异常 \u0026quot;ababa\u0026quot;.count(\u0026quot;ab\u0026quot;) → 2 ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-18-string-operations/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：黑马程序员Python基础课程 + Python 3.11官方文档 + 网络资料整理\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-字符串基本特性\"\u003e1.1 字符串基本特性\u003c/h3\u003e\n\u003cp\u003ePython 字符串是\u003cstrong\u003e不可变序列\u003c/strong\u003e（Immutable Sequence），所有修改操作都会返回新字符串：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Hello\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# s[0] = \u0026#34;J\u0026#34;  # TypeError: \u0026#39;str\u0026#39; object does not support item assignment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 正确做法：创建新字符串\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;J\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e s[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e:]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s2)  \u003cspan style=\"color:#75715e\"\u003e# Jello\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 字符串长度\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(len(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Hello\u0026#34;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"12-字符串索引与切片\"\u003e1.2 字符串索引与切片\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Python是最流行的编程语言\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 正向索引（从0开始）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e])   \u003cspan style=\"color:#75715e\"\u003e# P\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s[\u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e])   \u003cspan style=\"color:#75715e\"\u003e# 是\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 反向索引（从-1开始）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s[\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e])  \u003cspan style=\"color:#75715e\"\u003e# 言\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s[\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e])  \u003cspan style=\"color:#75715e\"\u003e# 编\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 切片 s[start:end:step]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e])     \u003cspan style=\"color:#75715e\"\u003e# Python（不含end）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s[\u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e:\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e])     \u003cspan style=\"color:#75715e\"\u003e# 是最流\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s[:\u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e])       \u003cspan style=\"color:#75715e\"\u003e# Python（省略start=0）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s[\u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e:])       \u003cspan style=\"color:#75715e\"\u003e# 是最流行的编程语言（省略end=len）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s[::\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e])      \u003cspan style=\"color:#75715e\"\u003e# Pto无流编言言（步长2）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s[::\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e])     \u003cspan style=\"color:#75715e\"\u003e# 言语言程编的行流最是（逆序）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"13-常用字符串方法\"\u003e1.3 常用字符串方法\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e查找与替换：\u003c/strong\u003e\u003c/p\u003e","tags":"Python, 编程, 字符串","title":"Day18 字符串全解"},{"columns":"acp-course","content":"主机安全 详细讲解 一、主机安全困境 云环境面临的新安全问题 边界和责任越来越模糊：云的边界/安全责任（共担模型）越来越模糊 资产业务的多元化：用户资产涉及云上云下，类型越来越多元 安全威胁的预谋化：攻击方式从撒网式无差别扫描转向定向攻击 二、云安全中心介绍 云安全中心（态势感知）是集持续监测、深度防御、全面分析、快速响应能力于一体的云上安全管理平台。\n产品规格 版本 特点 免费版 基础免费安全防护服务 防病毒版 一键式病毒查杀，避免服务器被入侵 高级版 更轻松满足合规检查要求 企业版 服务器、容器环境的全面安全检测与防护能力 旗舰版 全面建立主机安全防御体系，防勒索防篡改 产品优势 稳定性：百万级服务器装机量，CPU使用率低于10% 统一安全管理：支持线下IDC及其他云平台统一管控 安全闭环能力：主动拦截病毒木马，漏洞扫描，一键修复 病毒云查杀：实时病毒检测和防护服务 全面攻击检测：250+威胁检测模型 产品架构 云安全中心构建涵盖网络层、主机层、应用层的安全纵深防护体系：\n网络层：流量镜像检测分析出入云平台的全部网络流量 应用层：扫描Web漏洞、检测Web攻击、分析应用层访问记录 主机层：实时检测主机资产，异常进程/端口/网络连接，漏洞扫描 三、安全预防功能 漏洞扫描与修复 Windows系统漏洞 Linux软件漏洞 Web-CMS漏洞 应用漏洞 应急漏洞 基线检查 检测操作系统和服务的弱口令、账号权限、身份鉴别、密码策略、访问控制、安全审计和入侵防范等安全配置。\n云平台配置检查 基于云平台安全实践，联动云产品能力形成安全闭环。\n四、主动防御功能 防勒索、防病毒 实时拦截已知勒索病毒、挖矿、蠕虫、DDoS等七类病毒。\n应用白名单 防止未经授权的应用异常启动，影响业务正常运行。\n防篡改 防止网站被植入涉恐涉政、暗链、后门等，保障网页正常。\n云蜜罐 云原生VPC黑洞功能：导流至蜜罐服务 通用主机探针方案：业务主机上部署Agent进行流量转发 丰富蜜罐服务：高低交互蜜罐，覆盖Web、数据库、系统服务等 五、威胁检测功能 安全告警类型 网页防篡改、进程异常行为、网站后门 异常登录、异常事件、敏感文件篡改 恶意进程（病毒云查杀）、异常网络连接 异常账号、应用入侵事件、容器集群异常 病毒云查杀能力 深度学习检测引擎：智能识别未知威胁 云沙箱：真实还原云上环境，监控恶意样本攻击行为 多引擎集成：集成中国及海外主流杀毒引擎 威胁情报检测：多维度检测异常进程和恶意行为 病毒类型：蠕虫病毒、挖矿程序、病毒型感染、勒索病毒、后门程序、木马程序、DDoS木马\n查杀优势 轻量：仅占用1% CPU、50MB内存 实时：获取进程启动日志，实时监控 统一管理：云安全中心控制台统一管控 六、容器安全 镜像漏洞扫描 支持深度漏洞扫描，提供漏洞修复方案。\n容器威胁检测 容器运行时刻及容器K8S威胁检测。\n容器防火墙 为容器环境提供访问控制策略的智能学习、告警、拦截的一体化网络防火墙服务。\n七、调查与响应 自动化攻击溯源 自动溯源攻击源和原因，快速响应。\n日志分析\u0026amp;审计 提供日志审计、分析能力，支持攻击追溯和合规。\n背诵版 云安全中心版本：免费→防病毒→高级→企业→旗舰版\n产品优势：稳定(百万装机/10%CPU) + 统一管理 + 安全闭环 + 病毒云查杀 + 250+检测模型\n三层纵深防护：网络层(流量镜像) + 应用层(Web漏洞) + 主机层(资产检测)\n漏洞类型：Windows/Linux系统漏洞、Web-CMS漏洞、应用漏洞、应急漏洞\n主动防御：防勒索 + 应用白名单 + 防篡改 + 云蜜罐\n病毒云查杀：深度学习 + 云沙箱 + 多引擎 + 威胁情报\n容器安全：镜像漏洞扫描 + 容器威胁检测 + 容器防火墙\n速记版 主机安全困境 = 边界模糊 + 资产多元 + 定向攻击\n云安全中心 = 持续监测 + 深度防御 + 全面分析 + 快速响应\n250+威胁检测模型 = 10阶段全链路覆盖\n病毒云查杀 = 深度学习 + 云沙箱 + 多引擎 + 情报\n容器安全三件套 = 镜像扫描 + 威胁检测 + 防火墙\n测试题 选择题 云安全中心支持几层的安全纵深防护体系？\nA. 1层 B. 2层 C. 3层 D. 4层 云安全中心免费版提供的防护能力是？\nA. 基础免费安全防护服务 B. 防病毒版 C. 高级版 D. 企业版 云安全中心Agent客户端CPU使用率低于多少？\nA. 5% B. 10% C. 15% D. 20% 以下哪项不属于云安全中心的主动防御功能？\nA. 防勒索 B. 应用白名单 C. 防篡改 D. 漏洞扫描 容器防火墙的主要功能是？\nA. 容器镜像存储 B. 容器网络访问控制策略的智能学习、告警、拦截 C. 容器日志收集 D. 容器性能监控 判断题 云安全中心支持对线下IDC及其他云平台的服务器进行统一安全管理。 云蜜罐是一种主动防御技术，可以诱骗攻击者。 云安全中心的防病毒版相比免费版增加了防勒索防篡改功能。 容器防火墙通过将容器中应用的命名空间、应用名称等信息整合为网络对象进行访问控制。 云安全中心支持对操作系统和数据库的弱口令进行检测。 答案 1.C | 2.A | 3.B | 4.D | 5.B\n6.√ | 7.√ | 8.× | 9.√ | 10.√\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-18-acp-day-18-%E4%B8%BB%E6%9C%BA%E5%AE%89%E5%85%A8/","summary":"\u003ch1 id=\"主机安全\"\u003e主机安全\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"一主机安全困境\"\u003e一、主机安全困境\u003c/h3\u003e\n\u003ch4 id=\"云环境面临的新安全问题\"\u003e云环境面临的新安全问题\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e边界和责任越来越模糊\u003c/strong\u003e：云的边界/安全责任（共担模型）越来越模糊\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e资产业务的多元化\u003c/strong\u003e：用户资产涉及云上云下，类型越来越多元\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e安全威胁的预谋化\u003c/strong\u003e：攻击方式从撒网式无差别扫描转向定向攻击\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"二云安全中心介绍\"\u003e二、云安全中心介绍\u003c/h3\u003e\n\u003cp\u003e云安全中心（态势感知）是集持续监测、深度防御、全面分析、快速响应能力于一体的云上安全管理平台。\u003c/p\u003e\n\u003ch4 id=\"产品规格\"\u003e产品规格\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e版本\u003c/th\u003e\n          \u003cth\u003e特点\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e免费版\u003c/td\u003e\n          \u003ctd\u003e基础免费安全防护服务\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e防病毒版\u003c/td\u003e\n          \u003ctd\u003e一键式病毒查杀，避免服务器被入侵\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e高级版\u003c/td\u003e\n          \u003ctd\u003e更轻松满足合规检查要求\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e企业版\u003c/td\u003e\n          \u003ctd\u003e服务器、容器环境的全面安全检测与防护能力\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e旗舰版\u003c/td\u003e\n          \u003ctd\u003e全面建立主机安全防御体系，防勒索防篡改\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"产品优势\"\u003e产品优势\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e稳定性\u003c/strong\u003e：百万级服务器装机量，CPU使用率低于10%\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e统一安全管理\u003c/strong\u003e：支持线下IDC及其他云平台统一管控\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e安全闭环能力\u003c/strong\u003e：主动拦截病毒木马，漏洞扫描，一键修复\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e病毒云查杀\u003c/strong\u003e：实时病毒检测和防护服务\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e全面攻击检测\u003c/strong\u003e：250+威胁检测模型\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"产品架构\"\u003e产品架构\u003c/h4\u003e\n\u003cp\u003e云安全中心构建涵盖网络层、主机层、应用层的安全纵深防护体系：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e网络层\u003c/strong\u003e：流量镜像检测分析出入云平台的全部网络流量\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e应用层\u003c/strong\u003e：扫描Web漏洞、检测Web攻击、分析应用层访问记录\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e主机层\u003c/strong\u003e：实时检测主机资产，异常进程/端口/网络连接，漏洞扫描\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"三安全预防功能\"\u003e三、安全预防功能\u003c/h3\u003e\n\u003ch4 id=\"漏洞扫描与修复\"\u003e漏洞扫描与修复\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eWindows系统漏洞\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLinux软件漏洞\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eWeb-CMS漏洞\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e应用漏洞\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e应急漏洞\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"基线检查\"\u003e基线检查\u003c/h4\u003e\n\u003cp\u003e检测操作系统和服务的弱口令、账号权限、身份鉴别、密码策略、访问控制、安全审计和入侵防范等安全配置。\u003c/p\u003e\n\u003ch4 id=\"云平台配置检查\"\u003e云平台配置检查\u003c/h4\u003e\n\u003cp\u003e基于云平台安全实践，联动云产品能力形成安全闭环。\u003c/p\u003e\n\u003ch3 id=\"四主动防御功能\"\u003e四、主动防御功能\u003c/h3\u003e\n\u003ch4 id=\"防勒索防病毒\"\u003e防勒索、防病毒\u003c/h4\u003e\n\u003cp\u003e实时拦截已知勒索病毒、挖矿、蠕虫、DDoS等七类病毒。\u003c/p\u003e\n\u003ch4 id=\"应用白名单\"\u003e应用白名单\u003c/h4\u003e\n\u003cp\u003e防止未经授权的应用异常启动，影响业务正常运行。\u003c/p\u003e\n\u003ch4 id=\"防篡改\"\u003e防篡改\u003c/h4\u003e\n\u003cp\u003e防止网站被植入涉恐涉政、暗链、后门等，保障网页正常。\u003c/p\u003e\n\u003ch4 id=\"云蜜罐\"\u003e云蜜罐\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e云原生VPC黑洞功能\u003c/strong\u003e：导流至蜜罐服务\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e通用主机探针方案\u003c/strong\u003e：业务主机上部署Agent进行流量转发\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e丰富蜜罐服务\u003c/strong\u003e：高低交互蜜罐，覆盖Web、数据库、系统服务等\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"五威胁检测功能\"\u003e五、威胁检测功能\u003c/h3\u003e\n\u003ch4 id=\"安全告警类型\"\u003e安全告警类型\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e网页防篡改、进程异常行为、网站后门\u003c/li\u003e\n\u003cli\u003e异常登录、异常事件、敏感文件篡改\u003c/li\u003e\n\u003cli\u003e恶意进程（病毒云查杀）、异常网络连接\u003c/li\u003e\n\u003cli\u003e异常账号、应用入侵事件、容器集群异常\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"病毒云查杀能力\"\u003e病毒云查杀能力\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e深度学习检测引擎\u003c/strong\u003e：智能识别未知威胁\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e云沙箱\u003c/strong\u003e：真实还原云上环境，监控恶意样本攻击行为\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e多引擎集成\u003c/strong\u003e：集成中国及海外主流杀毒引擎\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e威胁情报检测\u003c/strong\u003e：多维度检测异常进程和恶意行为\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e病毒类型\u003c/strong\u003e：蠕虫病毒、挖矿程序、病毒型感染、勒索病毒、后门程序、木马程序、DDoS木马\u003c/p\u003e\n\u003ch4 id=\"查杀优势\"\u003e查杀优势\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e轻量\u003c/strong\u003e：仅占用1% CPU、50MB内存\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e实时\u003c/strong\u003e：获取进程启动日志，实时监控\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e统一管理\u003c/strong\u003e：云安全中心控制台统一管控\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"六容器安全\"\u003e六、容器安全\u003c/h3\u003e\n\u003ch4 id=\"镜像漏洞扫描\"\u003e镜像漏洞扫描\u003c/h4\u003e\n\u003cp\u003e支持深度漏洞扫描，提供漏洞修复方案。\u003c/p\u003e","tags":"","title":"Day18 主机安全"},{"columns":"python-course","content":" 来源：黑马程序员Python基础课程 + Python 3.11官方文档 + 网络资料整理\n一、详细讲解 1.1 集合的基本特性 Python 集合（Set）是无序、不重复的可变容器：\n# 创建集合 s1 = {1, 2, 3, 4, 5} s2 = set([1, 2, 2, 3, 3, 4, 4]) # set()从列表创建，自动去重 print(s2) # {1, 2, 3, 4} # 创建空集合（不能用{}，那是dict） empty = set() print(type(empty)) # \u0026lt;class \u0026#39;set\u0026#39;\u0026gt; # 集合特点：无序 + 不重复 s = {3, 1, 4, 1, 5, 9, 2, 6} print(s) # {1, 2, 3, 4, 5, 6, 9}（顺序不确定） # 自动去重 nums = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] unique = set(nums) print(unique) # {1, 2, 3, 4} 1.2 集合的增删操作 s = {1, 2, 3} # 添加元素 s.add(4) # 添加一个元素 print(s) # {1, 2, 3, 4} s.add(2) # 已存在的元素，集合不变 print(s) # {1, 2, 3, 4} s.update([5, 6, 7]) # 批量添加（传入可迭代对象） print(s) # {1, 2, 3, 4, 5, 6, 7} # 删除元素 s.remove(3) # 删除指定元素，不存在则抛KeyError print(s) # {1, 2, 4, 5, 6, 7} s.discard(10) # 删除指定元素，不存在也不报错 print(s) # {1, 2, 4, 5, 6, 7} popped = s.pop() # 随机删除并返回一个元素 print(popped) # 1（通常删除第一个） print(s) # {2, 4, 5, 6, 7} s.clear() # 清空集合 print(s) # set() 1.3 集合运算（重点） A = {1, 2, 3, 4, 5} B = {4, 5, 6, 7, 8} # 交集：两个集合都有的元素 print(A \u0026amp; B) # {4, 5} print(A.intersection(B)) # {4, 5} # 并集：所有元素（去重） print(A | B) # {1, 2, 3, 4, 5, 6, 7, 8} print(A.union(B)) # {1, 2, 3, 4, 5, 6, 7, 8} # 差集：A有B没有的元素 print(A - B) # {1, 2, 3} print(A.difference(B)) # {1, 2, 3} # 对称差集：A和B互相没有的元素 print(A ^ B) # {1, 2, 3, 6, 7, 8} print(A.symmetric_difference(B)) # {1, 2, 3, 6, 7, 8} # 子集与超集 X = {1, 2, 3} Y = {1, 2, 3, 4, 5} print(X \u0026lt; Y) # True（X是Y的真子集） print(Y \u0026gt; X) # True（Y是X的真超集） print(X \u0026lt;= Y) # True（X是Y的子集，包含相等情况） print(Y \u0026gt;= X) # True（Y是X的超集） # 判断是否相交（无交集返回True） print(A.isdisjoint(B)) # False（有交集4,5） C = {10, 20} print(A.isdisjoint(C)) # True（无交集） 1.4 集合的成员测试 s = {1, 2, 3, 4, 5} print(3 in s) # True print(10 in s) # False print(3 not in s) # False # 集合成员测试比列表快很多（O(1) vs O(n)） 1.5 集合推导式 # 基本集合推导式 nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] evens = {x for x in nums if x % 2 == 0} print(evens) # {2, 4, 6, 8, 10} # 带计算的集合推导式 squares = {x**2 for x in range(1, 6)} print(squares) # {1, 4, 9, 16, 25} # 实际应用：从字符串提取不重复字符 text = \u0026#34;hello world\u0026#34; unique_chars = {c for c in text if c.isalpha()} print(unique_chars) # {\u0026#39;h\u0026#39;, \u0026#39;e\u0026#39;, \u0026#39;l\u0026#39;, \u0026#39;o\u0026#39;, \u0026#39;w\u0026#39;, \u0026#39;r\u0026#39;, \u0026#39;d\u0026#39;} 1.6 frozenset（不可变集合） frozenset 是不可变版本，创建后不能修改：\n# frozenset 创建 fs = frozenset([1, 2, 3, 4, 5]) print(fs) # frozenset({1, 2, 3, 4, 5}) # 支持集合运算（不修改原对象） A = frozenset([1, 2, 3]) B = frozenset([2, 3, 4]) print(A \u0026amp; B) # frozenset({2, 3}) print(A | B) # frozenset({1, 2, 3, 4}) # 可以作为字典的键 mapping = {frozenset([\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;]): \u0026#34;ab\u0026#34;, frozenset([\u0026#34;c\u0026#34;, \u0026#34;d\u0026#34;]): \u0026#34;cd\u0026#34;} print(mapping) # {frozenset({\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;}): \u0026#39;ab\u0026#39;, frozenset({\u0026#39;c\u0026#39;, \u0026#39;d\u0026#39;}): \u0026#39;cd\u0026#39;} 1.7 实际应用场景 # 场景1：列表去重（顺序可能改变） nums = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] unique = list(set(nums)) print(unique) # [1, 2, 3, 4] # 场景2：找出两个列表的共同元素 list1 = [1, 2, 3, 4, 5] list2 = [4, 5, 6, 7, 8] common = set(list1) \u0026amp; set(list2) print(list(common)) # [4, 5] # 场景3：排除重复元素 all_items = [1, 2, 3, 4, 5] exclude = {3, 4} filtered = [x for x in all_items if x not in exclude] print(filtered) # [1, 2, 5] 二、背诵版 集合特性 → 无序、不重复、可变 创建 → set()（不能用{}，那是dict） 去重 → set(列表) 添加 → add()单个 / update()批量 删除 → remove()抛异常 / discard()不抛 / pop()随机 交集 → A \u0026amp; B 或 A.intersection(B) 并集 → A | B 或 A.union(B) 差集 → A - B 或 A.difference(B) 对称差 → A ^ B 或 A.symmetric_difference(B) 子集 → A \u0026lt; B（A是B的真子集） frozenset → 不可变集合，可作字典键 三、考前记忆 操作/方法 说明 示例 set() 创建空集合 set() s.add(x) 添加元素 {1}.add(2) → {1,2} s.update(iter) 批量添加 {1}.update([2,3]) → {1,2,3} s.remove(x) 删除（不存在抛异常） — s.discard(x) 删除（不存在不报错） — A \u0026amp; B 交集 {1,2} \u0026amp; {2,3} → {2} A | B 并集 {1,2} | {2,3} → {1,2,3} A - B 差集 {1,2} - {2,3} → {1} A ^ B 对称差集 {1,2} ^ {2,3} → {1,3} A \u0026lt; B 真子集 {1} \u0026lt; {1,2} → True frozenset 不可变集合 可作字典键 四、测试题 1. 单选题： 以下哪个不是集合的特性？\nA. 无序 B. 不重复 C. 可变（可增删） D. 支持索引访问 2. 单选题： {1, 2, 3} \u0026amp; {2, 3, 4} 的结果是？\nA. {1, 2, 3, 4} B. {2, 3} C. {1, 4} D. {2} 3. 判断题： frozenset 可以作为字典的键。\n4. 填空题： 创建一个空集合应该用 ______（不能写 {}）。\n5. 简答题： 比较 remove() 和 discard() 的区别。\n6. 代码题： 找出列表 [1,2,3,4,5,6] 和 [4,5,6,7,8,9] 的并集（不重复元素）。\nD（集合无序，不支持索引访问） B（交集：两个集合都有的元素） ✓ set() remove() 删除不存在的元素会抛 KeyError，discard() 删除不存在的元素什么也不做（静默） a = [1, 2, 3, 4, 5, 6] b = [4, 5, 6, 7, 8, 9] union = set(a) | set(b) print(union) # {1, 2, 3, 4, 5, 6, 7, 8, 9} ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-19-set-operations/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：黑马程序员Python基础课程 + Python 3.11官方文档 + 网络资料整理\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-集合的基本特性\"\u003e1.1 集合的基本特性\u003c/h3\u003e\n\u003cp\u003ePython 集合（Set）是\u003cstrong\u003e无序、不重复\u003c/strong\u003e的可变容器：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 创建集合\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e set([\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e])  \u003cspan style=\"color:#75715e\"\u003e# set()从列表创建，自动去重\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s2)  \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 3, 4}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 创建空集合（不能用{}，那是dict）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eempty \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e set()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(type(empty))  \u003cspan style=\"color:#75715e\"\u003e# \u0026lt;class \u0026#39;set\u0026#39;\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 集合特点：无序 + 不重复\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e9\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s)  \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 3, 4, 5, 6, 9}（顺序不确定）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 自动去重\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enums \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eunique \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e set(nums)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(unique)  \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 3, 4}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"12-集合的增删操作\"\u003e1.2 集合的增删操作\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 添加元素\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eadd(\u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e)          \u003cspan style=\"color:#75715e\"\u003e# 添加一个元素\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s)           \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 3, 4}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eadd(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e)           \u003cspan style=\"color:#75715e\"\u003e# 已存在的元素，集合不变\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s)           \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 3, 4}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eupdate([\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e])  \u003cspan style=\"color:#75715e\"\u003e# 批量添加（传入可迭代对象）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s)              \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 3, 4, 5, 6, 7}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 删除元素\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eremove(\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e)          \u003cspan style=\"color:#75715e\"\u003e# 删除指定元素，不存在则抛KeyError\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s)              \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 4, 5, 6, 7}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ediscard(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e)        \u003cspan style=\"color:#75715e\"\u003e# 删除指定元素，不存在也不报错\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s)              \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 4, 5, 6, 7}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epopped \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e s\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epop()     \u003cspan style=\"color:#75715e\"\u003e# 随机删除并返回一个元素\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(popped)        \u003cspan style=\"color:#75715e\"\u003e# 1（通常删除第一个）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s)              \u003cspan style=\"color:#75715e\"\u003e# {2, 4, 5, 6, 7}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eclear()            \u003cspan style=\"color:#75715e\"\u003e# 清空集合\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(s)              \u003cspan style=\"color:#75715e\"\u003e# set()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"13-集合运算重点\"\u003e1.3 集合运算（重点）\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eA \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eB \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 交集：两个集合都有的元素\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(A \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003e B)               \u003cspan style=\"color:#75715e\"\u003e# {4, 5}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(A\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eintersection(B))    \u003cspan style=\"color:#75715e\"\u003e# {4, 5}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 并集：所有元素（去重）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(A \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e B)               \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 3, 4, 5, 6, 7, 8}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(A\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eunion(B))           \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 3, 4, 5, 6, 7, 8}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 差集：A有B没有的元素\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(A \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e B)               \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 3}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(A\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edifference(B))      \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 3}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 对称差集：A和B互相没有的元素\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(A \u003cspan style=\"color:#f92672\"\u003e^\u003c/span\u003e B)               \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 3, 6, 7, 8}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(A\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esymmetric_difference(B))  \u003cspan style=\"color:#75715e\"\u003e# {1, 2, 3, 6, 7, 8}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 子集与超集\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eX \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eY \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(X \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e Y)   \u003cspan style=\"color:#75715e\"\u003e# True（X是Y的真子集）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(Y \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e X)   \u003cspan style=\"color:#75715e\"\u003e# True（Y是X的真超集）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(X \u003cspan style=\"color:#f92672\"\u003e\u0026lt;=\u003c/span\u003e Y)  \u003cspan style=\"color:#75715e\"\u003e# True（X是Y的子集，包含相等情况）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(Y \u003cspan style=\"color:#f92672\"\u003e\u0026gt;=\u003c/span\u003e X)  \u003cspan style=\"color:#75715e\"\u003e# True（Y是X的超集）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 判断是否相交（无交集返回True）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(A\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eisdisjoint(B))  \u003cspan style=\"color:#75715e\"\u003e# False（有交集4,5）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eC \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(A\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eisdisjoint(C))  \u003cspan style=\"color:#75715e\"\u003e# True（无交集）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"14-集合的成员测试\"\u003e1.4 集合的成员测试\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003es \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e s)     \u003cspan style=\"color:#75715e\"\u003e# True\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e s)    \u003cspan style=\"color:#75715e\"\u003e# False\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e s) \u003cspan style=\"color:#75715e\"\u003e# False\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 集合成员测试比列表快很多（O(1) vs O(n)）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"15-集合推导式\"\u003e1.5 集合推导式\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 基本集合推导式\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enums \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e9\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eevens \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {x \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e x \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e nums \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e x \u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(evens)  \u003cspan style=\"color:#75715e\"\u003e# {2, 4, 6, 8, 10}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 带计算的集合推导式\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esquares \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {x\u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e x \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e)}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(squares)  \u003cspan style=\"color:#75715e\"\u003e# {1, 4, 9, 16, 25}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 实际应用：从字符串提取不重复字符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;hello world\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eunique_chars \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {c \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e c \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e text \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e c\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eisalpha()}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(unique_chars)  \u003cspan style=\"color:#75715e\"\u003e# {\u0026#39;h\u0026#39;, \u0026#39;e\u0026#39;, \u0026#39;l\u0026#39;, \u0026#39;o\u0026#39;, \u0026#39;w\u0026#39;, \u0026#39;r\u0026#39;, \u0026#39;d\u0026#39;}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"16-frozenset不可变集合\"\u003e1.6 frozenset（不可变集合）\u003c/h3\u003e\n\u003cp\u003efrozenset 是不可变版本，创建后不能修改：\u003c/p\u003e","tags":"Python, 编程, 集合","title":"Day19 集合操作全解"},{"columns":"acp-course","content":"数据安全 详细讲解 一、数据安全中心（DSC） 数据安全中心（Data Security Center，简称DSC）为客户提供敏感数据自动识别、分级分类、大数据安全审计与数据脱敏等数据安全能力。\n产品特点 合规性：满足等保2.0二级\u0026quot;安全审计\u0026quot;与三级\u0026quot;个人信息保护\u0026quot;要求 云原生：依托云原生优势，为云上数据源提供一体化保护 智能化：运用大数据和机器学习能力，智能识别敏感数据 可视化：提供敏感数据识别结果可视化能力 产品功能 免代理一键授权接入：侵入度低，无需登录应用程序 以敏感数据为中心的能力联动：异常行为告警自动关联敏感数据 数据安全态势可视化管理：以资产/用户/事件为中心的审计报表 数据域管理 支持企业管理员基于业务属性、组织架构、数据特征等维度对数据资产进行划分 将具有相同特征的数据资产划分到同一个数据域 数据梳理 敏感数据：客户资料、技术资料、个人信息等高价值数据 支持结构化数据、非结构化数据和大数据产品 内置超过200种文件类型、40+种敏感数据类型 安全审计 原生日志采集：自动建立与对应产品的数据采集链路 Agent采集：通过部署Agent转发日志给DSC审计服务器 数据脱敏 静态脱敏：使用脱敏算法对敏感数据进行遮盖、加密或替换 动态脱敏：直接脱敏指定数据，每次小于2MB 脱敏算法：哈希、洗牌、数据解密、遮盖、替换、加密、变换 数据泄露检测 异常行为识别：及时告警并一键止血 联动威胁情报：封禁恶意IP访问 联动敏感数据识别：从海量告警中快速锁定高危风险 数据明/暗水印：泄露事件溯源 二、密钥管理服务（KMS） 密钥管理服务KMS（Key Management Service）为应用提供符合国密要求的密钥服务及极简应用加解密服务。\n功能组件 组件 说明 密钥服务 密钥的全托管和保护，支撑云原生接口的极简数据加密和数字签名 凭据管家 凭据托管加密、定期轮转、安全分发、中心化管理 证书管家 高可用、高安全的密钥和证书托管能力，以及签名验签能力 专属KMS 专属于用户的云上私有密钥管理服务 托管密码机 硬件密码机（HSM）是执行密码运算、安全生成和存储密钥的硬件设备 合规：国密检测认证、FIPS认证 安全：硬件保护、密钥版本管理 易运维：按量计费、自动密钥轮转 密钥轮转 KMS中的CMK支持多个密钥版本 每一个密钥版本是独立生成的密钥 通过生成新密钥版本实现自动轮转 凭据管家 通用凭据：存储账号口令、访问密钥、OAuth密钥、API Key等 动态RDS凭据：应用程序无需配置静态数据库账号口令 动态RAM凭据：全自动定期轮换AccessKey 动态ECS凭据：托管ECS实例登录凭据 三、加密服务 加密服务基于国家密码局认证的硬件加密机，提供了云上数据加解密服务。\n加密机类型 类型 说明 通用服务器密码机 满足GM/T 0030要求，提供国际通用密码服务接口 金融数据密码机 满足GM/T 0045要求，用于金融支付领域 签名验签密码机 满足GM/T 0029要求，提供数字签名、验证签名运算 工作原理 通过云密码机产生加密密钥 使用加密密钥对应用数据明文进行加密产生密文 应用系统把密文数据存储到数据库 背诵版 数据安全中心DSC：敏感数据识别 + 分级分类 + 安全审计 + 数据脱敏\n产品特点：合规(等保2.0) + 云原生 + 智能化 + 可视化\n数据脱敏类型：静态脱敏 + 动态脱敏\nKMS组件：密钥服务 + 凭据管家 + 证书管家 + 专属KMS\n加密机类型：通用服务器密码机 + 金融数据密码机 + 签名验签密码机\n密钥版本：CMK支持多版本，互不相关，自动轮转\n动态凭据：RDS + RAM + ECS\n速记版 DSC = 敏感数据识别 + 审计 + 脱敏\nKMS = 密钥托管 + 极简加解密\n凭据管家 = 托管 + 轮转 + 分发 + 管理\n加密服务 = 国密认证 + 加解密 + 密钥管理\n三种密码机 = 通用 + 金融 + 签名验签\n测试题 选择题 数据安全中心DSC可以满足等保2.0几级的合规要求？\nA. 一级 B. 二级和三级 C. 四级 D. 五级 KMS凭据管家不支持哪种动态凭据？\nA. 动态RDS凭据 B. 动态RAM凭据 C. 动态ECS凭据 D. 动态OSS凭据 密钥管理服务KMS中，CMK支持多少个密钥版本？\nA. 1个 B. 2个 C. 多个 D. 不支持版本概念 以下哪种不是加密服务的云加密机类型？\nA. 通用服务器密码机 B. 金融数据密码机 C. 签名验签密码机 D. 分布式密码机 数据安全中心的数据脱敏每次动态脱敏的数据量限制是？\nA. 小于1MB B. 小于2MB C. 小于5MB D. 小于10MB 判断题 数据安全中心支持对OSS、RDS、MaxCompute等云产品进行敏感数据识别。 静态脱敏是将数据脱敏后保存到目标位置，动态脱敏是直接脱敏指定数据。 KMS的同一个CMK下的多个密钥版本在密码学上互不相关。 加密服务使用符合国家密码管理局要求的密码机，满足监管合规要求。 数据安全中心的原生日志采集模式存在额外采集费用。 答案 1.B | 2.D | 3.C | 4.D | 5.B\n6.√ | 7.√ | 8.√ | 9.√ | 10.√\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-19-acp-day-19-%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8/","summary":"\u003ch1 id=\"数据安全\"\u003e数据安全\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"一数据安全中心dsc\"\u003e一、数据安全中心（DSC）\u003c/h3\u003e\n\u003cp\u003e数据安全中心（Data Security Center，简称DSC）为客户提供敏感数据自动识别、分级分类、大数据安全审计与数据脱敏等数据安全能力。\u003c/p\u003e\n\u003ch4 id=\"产品特点\"\u003e产品特点\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e合规性\u003c/strong\u003e：满足等保2.0二级\u0026quot;安全审计\u0026quot;与三级\u0026quot;个人信息保护\u0026quot;要求\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e云原生\u003c/strong\u003e：依托云原生优势，为云上数据源提供一体化保护\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e智能化\u003c/strong\u003e：运用大数据和机器学习能力，智能识别敏感数据\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e可视化\u003c/strong\u003e：提供敏感数据识别结果可视化能力\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"产品功能\"\u003e产品功能\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e免代理一键授权接入\u003c/strong\u003e：侵入度低，无需登录应用程序\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e以敏感数据为中心的能力联动\u003c/strong\u003e：异常行为告警自动关联敏感数据\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e数据安全态势可视化管理\u003c/strong\u003e：以资产/用户/事件为中心的审计报表\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"数据域管理\"\u003e数据域管理\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e支持企业管理员基于业务属性、组织架构、数据特征等维度对数据资产进行划分\u003c/li\u003e\n\u003cli\u003e将具有相同特征的数据资产划分到同一个数据域\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"数据梳理\"\u003e数据梳理\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e敏感数据：客户资料、技术资料、个人信息等高价值数据\u003c/li\u003e\n\u003cli\u003e支持结构化数据、非结构化数据和大数据产品\u003c/li\u003e\n\u003cli\u003e内置超过200种文件类型、40+种敏感数据类型\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"安全审计\"\u003e安全审计\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e原生日志采集\u003c/strong\u003e：自动建立与对应产品的数据采集链路\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAgent采集\u003c/strong\u003e：通过部署Agent转发日志给DSC审计服务器\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"数据脱敏\"\u003e数据脱敏\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e静态脱敏\u003c/strong\u003e：使用脱敏算法对敏感数据进行遮盖、加密或替换\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e动态脱敏\u003c/strong\u003e：直接脱敏指定数据，每次小于2MB\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e脱敏算法\u003c/strong\u003e：哈希、洗牌、数据解密、遮盖、替换、加密、变换\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"数据泄露检测\"\u003e数据泄露检测\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e异常行为识别：及时告警并一键止血\u003c/li\u003e\n\u003cli\u003e联动威胁情报：封禁恶意IP访问\u003c/li\u003e\n\u003cli\u003e联动敏感数据识别：从海量告警中快速锁定高危风险\u003c/li\u003e\n\u003cli\u003e数据明/暗水印：泄露事件溯源\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"二密钥管理服务kms\"\u003e二、密钥管理服务（KMS）\u003c/h3\u003e\n\u003cp\u003e密钥管理服务KMS（Key Management Service）为应用提供符合国密要求的密钥服务及极简应用加解密服务。\u003c/p\u003e\n\u003ch4 id=\"功能组件\"\u003e功能组件\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e组件\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e密钥服务\u003c/td\u003e\n          \u003ctd\u003e密钥的全托管和保护，支撑云原生接口的极简数据加密和数字签名\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e凭据管家\u003c/td\u003e\n          \u003ctd\u003e凭据托管加密、定期轮转、安全分发、中心化管理\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e证书管家\u003c/td\u003e\n          \u003ctd\u003e高可用、高安全的密钥和证书托管能力，以及签名验签能力\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e专属KMS\u003c/td\u003e\n          \u003ctd\u003e专属于用户的云上私有密钥管理服务\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"托管密码机\"\u003e托管密码机\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e硬件密码机（HSM）是执行密码运算、安全生成和存储密钥的硬件设备\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e合规\u003c/strong\u003e：国密检测认证、FIPS认证\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e安全\u003c/strong\u003e：硬件保护、密钥版本管理\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e易运维\u003c/strong\u003e：按量计费、自动密钥轮转\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"密钥轮转\"\u003e密钥轮转\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003eKMS中的CMK支持多个密钥版本\u003c/li\u003e\n\u003cli\u003e每一个密钥版本是独立生成的密钥\u003c/li\u003e\n\u003cli\u003e通过生成新密钥版本实现自动轮转\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"凭据管家\"\u003e凭据管家\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e通用凭据\u003c/strong\u003e：存储账号口令、访问密钥、OAuth密钥、API Key等\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e动态RDS凭据\u003c/strong\u003e：应用程序无需配置静态数据库账号口令\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e动态RAM凭据\u003c/strong\u003e：全自动定期轮换AccessKey\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e动态ECS凭据\u003c/strong\u003e：托管ECS实例登录凭据\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"三加密服务\"\u003e三、加密服务\u003c/h3\u003e\n\u003cp\u003e加密服务基于国家密码局认证的硬件加密机，提供了云上数据加解密服务。\u003c/p\u003e\n\u003ch4 id=\"加密机类型\"\u003e加密机类型\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e类型\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e通用服务器密码机\u003c/td\u003e\n          \u003ctd\u003e满足GM/T 0030要求，提供国际通用密码服务接口\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e金融数据密码机\u003c/td\u003e\n          \u003ctd\u003e满足GM/T 0045要求，用于金融支付领域\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e签名验签密码机\u003c/td\u003e\n          \u003ctd\u003e满足GM/T 0029要求，提供数字签名、验证签名运算\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"工作原理\"\u003e工作原理\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e通过云密码机产生加密密钥\u003c/li\u003e\n\u003cli\u003e使用加密密钥对应用数据明文进行加密产生密文\u003c/li\u003e\n\u003cli\u003e应用系统把密文数据存储到数据库\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch2 id=\"背诵版\"\u003e背诵版\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e数据安全中心DSC\u003c/strong\u003e：敏感数据识别 + 分级分类 + 安全审计 + 数据脱敏\u003c/p\u003e","tags":"","title":"Day19 数据安全"},{"columns":"python-course","content":" 来源：黑马程序员Python基础课程 + 原创项目设计\n一、详细讲解 1.1 项目概述 名片管理系统是一个经典的 Python 入门综合项目，涉及：\n字典存储名片数据 无限循环 while True 实现菜单 函数封装增删改查操作 if-elif 多重分支处理用户选择 1.2 数据结构设计 # 名片数据结构（字典） card = { \u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;phone\u0026#34;: \u0026#34;13800138000\u0026#34;, \u0026#34;email\u0026#34;: \u0026#34;zhangsan@example.com\u0026#34;, \u0026#34;company\u0026#34;: \u0026#34;百度公司\u0026#34; } # 名片列表（所有名片存储在列表中） cards_list = [ {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;phone\u0026#34;: \u0026#34;13800138000\u0026#34;, \u0026#34;email\u0026#34;: \u0026#34;zhangsan@example.com\u0026#34;, \u0026#34;company\u0026#34;: \u0026#34;百度\u0026#34;}, {\u0026#34;name\u0026#34;: \u0026#34;李四\u0026#34;, \u0026#34;phone\u0026#34;: \u0026#34;13900139000\u0026#34;, \u0026#34;email\u0026#34;: \u0026#34;lisi@example.com\u0026#34;, \u0026#34;company\u0026#34;: \u0026#34;阿里\u0026#34;}, ] 1.3 核心函数实现 # ========== 1. 显示菜单 ========== def show_menu(): print(\u0026#34;=\u0026#34; * 50) print(\u0026#34; 名片管理系统 V1.0\u0026#34;) print(\u0026#34; 1. 新增名片\u0026#34;) print(\u0026#34; 2. 显示全部\u0026#34;) print(\u0026#34; 3. 搜索名片\u0026#34;) print(\u0026#34; 4. 修改名片\u0026#34;) print(\u0026#34; 5. 删除名片\u0026#34;) print(\u0026#34; 0. 退出系统\u0026#34;) print(\u0026#34;=\u0026#34; * 50) # ========== 2. 新增名片 ========== def add_card(cards): name = input(\u0026#34;请输入姓名：\u0026#34;) phone = input(\u0026#34;请输入电话：\u0026#34;) email = input(\u0026#34;请输入邮箱：\u0026#34;) company = input(\u0026#34;请输入公司：\u0026#34;) card = { \u0026#34;name\u0026#34;: name, \u0026#34;phone\u0026#34;: phone, \u0026#34;email\u0026#34;: email, \u0026#34;company\u0026#34;: company } cards.append(card) print(f\u0026#34;√ 名片「{name}」添加成功！\u0026#34;) # ========== 3. 显示全部名片 ========== def show_all(cards): if len(cards) == 0: print(\u0026#34;当前没有任何名片，请先添加！\u0026#34;) return print(f\u0026#34;共找到 {len(cards)} 张名片：\u0026#34;) print(\u0026#34;-\u0026#34; * 60) for card in cards: print(f\u0026#34;姓名：{card[\u0026#39;name\u0026#39;]}\u0026#34;) print(f\u0026#34;电话：{card[\u0026#39;phone\u0026#39;]}\u0026#34;) print(f\u0026#34;邮箱：{card[\u0026#39;email\u0026#39;]}\u0026#34;) print(f\u0026#34;公司：{card[\u0026#39;company\u0026#39;]}\u0026#34;) print(\u0026#34;-\u0026#34; * 60) # ========== 4. 搜索名片 ========== def search_card(cards): if len(cards) == 0: print(\u0026#34;当前没有任何名片！\u0026#34;) return None search_name = input(\u0026#34;请输入要搜索的姓名：\u0026#34;) results = [c for c in cards if c[\u0026#34;name\u0026#34;] == search_name] if results: print(f\u0026#34;找到 {len(results)} 张名片：\u0026#34;) for card in results: print(f\u0026#34; 姓名：{card[\u0026#39;name\u0026#39;]}，电话：{card[\u0026#39;phone\u0026#39;]}\u0026#34;) return results else: print(f\u0026#34;没有找到名为「{search_name}」的名片\u0026#34;) return None # ========== 5. 修改名片 ========== def modify_card(cards): if len(cards) == 0: print(\u0026#34;当前没有任何名片！\u0026#34;) return search_name = input(\u0026#34;请输入要修改的姓名：\u0026#34;) for card in cards: if card[\u0026#34;name\u0026#34;] == search_name: print(\u0026#34;请输入新的信息（直接回车保留原值）：\u0026#34;) new_phone = input(f\u0026#34;电话[{card[\u0026#39;phone\u0026#39;]}]：\u0026#34;) new_email = input(f\u0026#34;邮箱[{card[\u0026#39;email\u0026#39;]}]：\u0026#34;) new_company = input(f\u0026#34;公司[{card[\u0026#39;company\u0026#39;]}]：\u0026#34;) if new_phone: card[\u0026#34;phone\u0026#34;] = new_phone if new_email: card[\u0026#34;email\u0026#34;] = new_email if new_company: card[\u0026#34;company\u0026#34;] = new_company print(f\u0026#34;√ 名片「{search_name}」修改成功！\u0026#34;) return print(f\u0026#34;没有找到名为「{search_name}」的名片\u0026#34;) # ========== 6. 删除名片 ========== def delete_card(cards): if len(cards) == 0: print(\u0026#34;当前没有任何名片！\u0026#34;) return search_name = input(\u0026#34;请输入要删除的姓名：\u0026#34;) for i, card in enumerate(cards): if card[\u0026#34;name\u0026#34;] == search_name: confirm = input(f\u0026#34;确定删除名片「{search_name}」？(y/n)：\u0026#34;) if confirm.lower() == \u0026#34;y\u0026#34;: cards.pop(i) print(f\u0026#34;√ 名片「{search_name}」已删除！\u0026#34;) return print(f\u0026#34;没有找到名为「{search_name}」的名片\u0026#34;) 1.4 主程序循环 def main(): cards = [] # 存储所有名片的列表 while True: show_menu() user_choice = input(\u0026#34;请选择操作（0-5）：\u0026#34;) if user_choice == \u0026#34;1\u0026#34;: add_card(cards) elif user_choice == \u0026#34;2\u0026#34;: show_all(cards) elif user_choice == \u0026#34;3\u0026#34;: search_card(cards) elif user_choice == \u0026#34;4\u0026#34;: modify_card(cards) elif user_choice == \u0026#34;5\u0026#34;: delete_card(cards) elif user_choice == \u0026#34;0\u0026#34;: print(\u0026#34;感谢使用，再见！\u0026#34;) break else: print(\u0026#34;无效选择，请输入 0-5 之间的数字\u0026#34;) if __name__ == \u0026#34;__main__\u0026#34;: main() 1.5 运行效果示例 ================================================== 名片管理系统 V1.0 1. 新增名片 2. 显示全部 3. 搜索名片 4. 修改名片 5. 删除名片 0. 退出系统 ================================================== 请选择操作（0-5）：1 请输入姓名：张三 请输入电话：13800138000 请输入邮箱：zhangsan@example.com 请输入公司：百度公司 √ 名片「张三」添加成功！ 请选择操作（0-5）：2 共找到 1 张名片： ------------------------------------------------------------ 姓名：张三 电话：13800138000 邮箱：zhangsan@example.com 公司：百度公司 ------------------------------------------------------------ 请选择操作（0-5）：0 感谢使用，再见！1.6 模块化改进（进阶） 将代码拆分为多个文件：\n# cards_tools.py（工具模块） cards_db = [] # 全局名片列表 def add(name, phone, email, company): \u0026#34;\u0026#34;\u0026#34;新增名片\u0026#34;\u0026#34;\u0026#34; cards_db.append({ \u0026#34;name\u0026#34;: name, \u0026#34;phone\u0026#34;: phone, \u0026#34;email\u0026#34;: email, \u0026#34;company\u0026#34;: company }) def get_all(): \u0026#34;\u0026#34;\u0026#34;获取所有名片\u0026#34;\u0026#34;\u0026#34; return cards_db def find_by_name(name): \u0026#34;\u0026#34;\u0026#34;按姓名查找\u0026#34;\u0026#34;\u0026#34; return [c for c in cards_db if c[\u0026#34;name\u0026#34;] == name] def delete(name): \u0026#34;\u0026#34;\u0026#34;删除名片\u0026#34;\u0026#34;\u0026#34; for i, card in enumerate(cards_db): if card[\u0026#34;name\u0026#34;] == name: return cards_db.pop(i) return None # cards_main.py（主程序） from cards_tools import add, get_all, find_by_name, delete def main(): add(\u0026#34;张三\u0026#34;, \u0026#34;138\u0026#34;, \u0026#34;z@x.com\u0026#34;, \u0026#34;百度\u0026#34;) add(\u0026#34;李四\u0026#34;, \u0026#34;139\u0026#34;, \u0026#34;l@x.com\u0026#34;, \u0026#34;阿里\u0026#34;) for card in get_all(): print(card[\u0026#34;name\u0026#34;]) if __name__ == \u0026#34;__main__\u0026#34;: main() 二、背诵版 名片数据结构 → {\u0026#34;name\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;phone\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;email\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;company\u0026#34;: \u0026#34;\u0026#34;} 名片存储 → 列表 cards = [] 菜单循环 → while True \u0026#43; if-elif 处理选择 新增 → cards.append(字典) 删除 → cards.pop(index) 或 remove() 搜索 → [c for c in cards if c[\u0026#34;name\u0026#34;] == name] 修改 → 直接赋值或 input() 保留原值 退出 → break 三、考前记忆 概念 要点 数据结构 字典存单张名片，列表存所有名片 无限循环 while True + break 退出 用户交互 input() 输入 + print() 输出 搜索功能 列表推导式或 for 循环遍历 修改确认 删除旧数据 + append 新数据 模块化 函数封装 + import 分离代码 四、测试题 1. 单选题： 名片管理系统的名片数据结构是？\nA. 字符串 B. 列表 C. 字典 D. 集合 2. 单选题： 无限循环菜单通常用什么退出？\nA. exit() B. break C. continue D. return 3. 判断题： while True 构成的循环如果不加 break 会永远执行下去。\n4. 填空题： 删除列表中第 i 个元素用 ______ 方法。\n5. 简答题： 说明 while True 无限循环和 for i in range(n) 循环的区别及各自适用场景。\n6. 代码题： 在名片列表 cards = [{\u0026quot;name\u0026quot;:\u0026quot;张三\u0026quot;,\u0026quot;phone\u0026quot;:\u0026quot;138\u0026quot;},{\u0026quot;name\u0026quot;:\u0026quot;李四\u0026quot;,\u0026quot;phone\u0026quot;:\u0026quot;139\u0026quot;}] 中，查找并返回姓名为\u0026quot;李四\u0026quot;的名片，没有找到返回 None。\nC（字典存储单张名片的多维信息） B（break 跳出循环） ✓ pop(i) while True 适合不确定循环次数（菜单、等待用户输入），for 适合已知循环次数（遍历有限序列）。 def search_by_name(cards, name): for card in cards: if card[\u0026#34;name\u0026#34;] == name: return card return None result = search_by_name(cards, \u0026#34;李四\u0026#34;) print(result) # {\u0026#34;name\u0026#34;:\u0026#34;李四\u0026#34;,\u0026#34;phone\u0026#34;:\u0026#34;139\u0026#34;} ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-20-cards-project/","summary":"\u003cblockquote\u003e\n\u003cp\u003e来源：黑马程序员Python基础课程 + 原创项目设计\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一详细讲解\"\u003e一、详细讲解\u003c/h2\u003e\n\u003ch3 id=\"11-项目概述\"\u003e1.1 项目概述\u003c/h3\u003e\n\u003cp\u003e名片管理系统是一个经典的 Python 入门综合项目，涉及：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e字典存储名片数据\u003c/li\u003e\n\u003cli\u003e无限循环 \u003ccode\u003ewhile True\u003c/code\u003e 实现菜单\u003c/li\u003e\n\u003cli\u003e函数封装增删改查操作\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eif-elif\u003c/code\u003e 多重分支处理用户选择\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"12-数据结构设计\"\u003e1.2 数据结构设计\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 名片数据结构（字典）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecard \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;phone\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;13800138000\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;email\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;zhangsan@example.com\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;company\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;百度公司\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 名片列表（所有名片存储在列表中）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecards_list \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;phone\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;13800138000\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;email\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;zhangsan@example.com\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;company\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;百度\u0026#34;\u003c/span\u003e},\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;李四\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;phone\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;13900139000\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;email\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;lisi@example.com\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;company\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;阿里\u0026#34;\u003c/span\u003e},\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"13-核心函数实现\"\u003e1.3 核心函数实现\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ========== 1. 显示菜单 ==========\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eshow_menu\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;=\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  名片管理系统 V1.0\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  1. 新增名片\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  2. 显示全部\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  3. 搜索名片\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  4. 修改名片\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  5. 删除名片\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  0. 退出系统\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;=\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ========== 2. 新增名片 ==========\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eadd_card\u003c/span\u003e(cards):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    name \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e input(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;请输入姓名：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    phone \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e input(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;请输入电话：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    email \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e input(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;请输入邮箱：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    company \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e input(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;请输入公司：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    card \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: name,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;phone\u0026#34;\u003c/span\u003e: phone,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;email\u0026#34;\u003c/span\u003e: email,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;company\u0026#34;\u003c/span\u003e: company\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cards\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(card)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;√ 名片「\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e」添加成功！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ========== 3. 显示全部名片 ==========\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eshow_all\u003c/span\u003e(cards):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e len(cards) \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;当前没有任何名片，请先添加！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;共找到 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003elen(cards)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 张名片：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;-\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e60\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e card \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e cards:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;姓名：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecard[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;name\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;电话：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecard[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;phone\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;邮箱：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecard[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;email\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;公司：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecard[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;company\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;-\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e60\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ========== 4. 搜索名片 ==========\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003esearch_card\u003c/span\u003e(cards):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e len(cards) \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;当前没有任何名片！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    search_name \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e input(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;请输入要搜索的姓名：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    results \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [c \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e c \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e cards \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e c[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e search_name]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e results:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;找到 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003elen(results)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 张名片：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e card \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e results:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  姓名：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecard[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;name\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e，电话：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecard[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;phone\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e results\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;没有找到名为「\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003esearch_name\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e」的名片\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ========== 5. 修改名片 ==========\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emodify_card\u003c/span\u003e(cards):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e len(cards) \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;当前没有任何名片！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    search_name \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e input(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;请输入要修改的姓名：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e card \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e cards:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e card[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e search_name:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;请输入新的信息（直接回车保留原值）：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            new_phone \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e input(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;电话[\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecard[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;phone\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e]：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            new_email \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e input(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;邮箱[\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecard[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;email\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e]：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            new_company \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e input(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;公司[\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecard[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;company\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e]：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e new_phone:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                card[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;phone\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e new_phone\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e new_email:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                card[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;email\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e new_email\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e new_company:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                card[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;company\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e new_company\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;√ 名片「\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003esearch_name\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e」修改成功！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;没有找到名为「\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003esearch_name\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e」的名片\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ========== 6. 删除名片 ==========\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edelete_card\u003c/span\u003e(cards):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e len(cards) \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;当前没有任何名片！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    search_name \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e input(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;请输入要删除的姓名：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e i, card \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e enumerate(cards):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e card[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e search_name:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            confirm \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e input(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;确定删除名片「\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003esearch_name\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e」？(y/n)：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e confirm\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003elower() \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;y\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                cards\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epop(i)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;√ 名片「\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003esearch_name\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e」已删除！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;没有找到名为「\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003esearch_name\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e」的名片\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"14-主程序循环\"\u003e1.4 主程序循环\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cards \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []  \u003cspan style=\"color:#75715e\"\u003e# 存储所有名片的列表\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ewhile\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        show_menu()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        user_choice \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e input(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;请选择操作（0-5）：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e user_choice \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            add_card(cards)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelif\u003c/span\u003e user_choice \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;2\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            show_all(cards)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelif\u003c/span\u003e user_choice \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;3\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            search_card(cards)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelif\u003c/span\u003e user_choice \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;4\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            modify_card(cards)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelif\u003c/span\u003e user_choice \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;5\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            delete_card(cards)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelif\u003c/span\u003e user_choice \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;0\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;感谢使用，再见！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ebreak\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;无效选择，请输入 0-5 之间的数字\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e __name__ \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;__main__\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    main()\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"15-运行效果示例\"\u003e1.5 运行效果示例\u003c/h3\u003e\n==================================================\n  名片管理系统 V1.0\n  1. 新增名片\n  2. 显示全部\n  3. 搜索名片\n  4. 修改名片\n  5. 删除名片\n  0. 退出系统\n==================================================\n请选择操作（0-5）：1\n请输入姓名：张三\n请输入电话：13800138000\n请输入邮箱：zhangsan@example.com\n请输入公司：百度公司\n√ 名片「张三」添加成功！\n\n请选择操作（0-5）：2\n共找到 1 张名片：\n------------------------------------------------------------\n姓名：张三\n电话：13800138000\n邮箱：zhangsan@example.com\n公司：百度公司\n------------------------------------------------------------\n\n请选择操作（0-5）：0\n感谢使用，再见！\u003ch3 id=\"16-模块化改进进阶\"\u003e1.6 模块化改进（进阶）\u003c/h3\u003e\n\u003cp\u003e将代码拆分为多个文件：\u003c/p\u003e","tags":"Python, 编程, 综合项目","title":"Day20 综合练习：名片管理系统"},{"columns":"acp-course","content":"业务安全 详细讲解 一、内容安全 内容安全基于深度学习技术，提供图片、视频、语音、文字、网页等多媒体的内容风险智能识别和审核服务。\n产品功能 内容检测API：提供图片、视频、文本、语音、网页等形式内容违规检测API OSS违规检测：检测OSS中图片、视频、音频文件中的违规风险 自定义机审标准：基于业务场景配置审核标准 核心能力 海量数据样本：基于阿里巴巴多年积累的海量互联网数据训练AI模型 弹性服务扩容：服务秒级弹性扩容 性价比高：毫秒级结果返回，99%以上准确率 个性化定制：一对一运营，支持个性化识别策略调整 检测能力覆盖 暴恐、涉政、涉黄、广告、辱骂、不良场景等风险检测 人工审核服务 人机审核：机器识别基础上选择性人工审核 纯人工审核：对全量内容数据进行人工审核 二、实人认证 实人认证是对用户身份信息真实性核验的服务，验证用户为真人且为本人。\n产品优势 精准身份认证技术：基于深度学习生物识别算法 全局信息安全保障：从终端设备、网络传输、服务器、数据管理各环节保障 多样产品能力输出：PC、APP、H5、小程序全场景覆盖 安全对抗丰富经验：源自阿里巴巴多年风险对抗实战经验 金融级实人认证方案 方案 说明 金融级多因子意愿认证方案 人脸与声纹双模态活体检测 金融级活体人脸验证方案 活体检测+人脸比对 金融级活体检测方案 纯活体检测 金融级人脸比对方案 人脸比对 认证场景 有源认证：权威渠道验证 自定义比对源认证：自定义比对源 真人检测：验证真人为本人 三、风险识别 风险识别（Fraud Detection）是一套实时分析、精准识别、全场景覆盖的业务风险管理产品。\n核心能力 资深专家团队：多行业资深风控专家 全链路防控：从端到云全链路分析与动态攻防 智能算法策略：上千套策略模型即开即用 超强性能：毫秒级、超高并发能力 功能概述 功能 说明 决策引擎平台 可视化、交互友好的风险管理运营平台 场景化风控方案 面向注册、登录、营销、信贷等通用场景 设备安全能力 基于端上安全组件对设备风险进行识别 场景风控类型 注册风险识别：发现批量注册行为 登录风险识别：发现账户被盗行为 营销风险识别：发现作弊、薅羊毛、套利等风险 设备风险识别：对移动APP上的恶意设备行为进行识别 业务风险情报：对企业平台的账户或用户进行风险检测 版本对比 功能 基础版 增强版 实时分析 支持 支持 服务返回值 量化评分 量化评分+风险特征标签 设备风险监测 不支持 支持 设备指纹 不支持 支持 团伙分析 不支持 支持 日志服务投递 不支持 支持 背诵版 内容安全：深度学习 + 图片/视频/语音/文字/网页检测 + 毫秒级返回 + 99%准确率\n实人认证：证件OCR识别 + 活体检测 + 人脸对比 = 真人+本人\n金融级方案：多因子意愿 + 活体人脸验证 + 活体检测 + 人脸比对\n风险识别：实时分析 + 精准识别 + 全场景覆盖\n场景风控：注册 + 登录 + 营销 + 设备 + 情报\n决策引擎：购买→接入→创建事件→创建/运行策略→获得决策结果\n速记版 内容安全 = 多媒体检测 + 机器+人工审核\n实人认证 = OCR识别 + 活体检测 + 人脸比对\n风险识别 = 全链路 + 智能算法 + 超强性能\n场景风控 = 注册/登录/营销/设备/情报\n增强版 vs 基础版 = 设备风险+指纹+团伙分析+日志投递\n测试题 选择题 内容安全的核心技术是什么？\nA. 规则引擎 B. 深度学习 C. 专家系统 D. 模糊逻辑 实人认证不包含以下哪项能力？\nA. 证件OCR识别 B. 活体检测 C. 语音识别 D. 人脸对比 风险识别的决策引擎平台接入流程第一步是什么？\nA. 购买决策引擎 B. 接入决策引擎 C. 创建事件 D. 创建/运行策略 以下哪种不属于风险识别的场景风控类型？\nA. 注册风险识别 B. 登录风险识别 C. 数据库风险识别 D. 营销风险识别 内容安全的OSS违规检测不包括以下哪种文件类型？\nA. 图片 B. 视频 C. 音频 D. 文档 判断题 内容安全返回结果的准确率可以达到99%以上。 实人认证只能通过APP方式接入，不能通过PC端接入。 风险识别的增强版支持设备指纹和团伙分析功能。 基础版风险识别支持日志服务SLS投递功能。 金融级多因子意愿认证方案支持用户明确表达知情且自愿认证。 答案 1.B | 2.C | 3.A | 4.C | 5.D\n6.√ | 7.× | 8.√ | 9.× | 10.√\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-20-acp-day-20-%E4%B8%9A%E5%8A%A1%E5%AE%89%E5%85%A8/","summary":"\u003ch1 id=\"业务安全\"\u003e业务安全\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"一内容安全\"\u003e一、内容安全\u003c/h3\u003e\n\u003cp\u003e内容安全基于深度学习技术，提供图片、视频、语音、文字、网页等多媒体的内容风险智能识别和审核服务。\u003c/p\u003e\n\u003ch4 id=\"产品功能\"\u003e产品功能\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e内容检测API\u003c/strong\u003e：提供图片、视频、文本、语音、网页等形式内容违规检测API\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eOSS违规检测\u003c/strong\u003e：检测OSS中图片、视频、音频文件中的违规风险\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e自定义机审标准\u003c/strong\u003e：基于业务场景配置审核标准\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"核心能力\"\u003e核心能力\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e海量数据样本\u003c/strong\u003e：基于阿里巴巴多年积累的海量互联网数据训练AI模型\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e弹性服务扩容\u003c/strong\u003e：服务秒级弹性扩容\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e性价比高\u003c/strong\u003e：毫秒级结果返回，99%以上准确率\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e个性化定制\u003c/strong\u003e：一对一运营，支持个性化识别策略调整\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"检测能力覆盖\"\u003e检测能力覆盖\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e暴恐、涉政、涉黄、广告、辱骂、不良场景等风险检测\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"人工审核服务\"\u003e人工审核服务\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e人机审核\u003c/strong\u003e：机器识别基础上选择性人工审核\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e纯人工审核\u003c/strong\u003e：对全量内容数据进行人工审核\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"二实人认证\"\u003e二、实人认证\u003c/h3\u003e\n\u003cp\u003e实人认证是对用户身份信息真实性核验的服务，验证用户为真人且为本人。\u003c/p\u003e\n\u003ch4 id=\"产品优势\"\u003e产品优势\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e精准身份认证技术\u003c/strong\u003e：基于深度学习生物识别算法\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e全局信息安全保障\u003c/strong\u003e：从终端设备、网络传输、服务器、数据管理各环节保障\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e多样产品能力输出\u003c/strong\u003e：PC、APP、H5、小程序全场景覆盖\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e安全对抗丰富经验\u003c/strong\u003e：源自阿里巴巴多年风险对抗实战经验\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"金融级实人认证方案\"\u003e金融级实人认证方案\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e方案\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e金融级多因子意愿认证方案\u003c/td\u003e\n          \u003ctd\u003e人脸与声纹双模态活体检测\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e金融级活体人脸验证方案\u003c/td\u003e\n          \u003ctd\u003e活体检测+人脸比对\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e金融级活体检测方案\u003c/td\u003e\n          \u003ctd\u003e纯活体检测\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e金融级人脸比对方案\u003c/td\u003e\n          \u003ctd\u003e人脸比对\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"认证场景\"\u003e认证场景\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e有源认证\u003c/strong\u003e：权威渠道验证\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e自定义比对源认证\u003c/strong\u003e：自定义比对源\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e真人检测\u003c/strong\u003e：验证真人为本人\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"三风险识别\"\u003e三、风险识别\u003c/h3\u003e\n\u003cp\u003e风险识别（Fraud Detection）是一套实时分析、精准识别、全场景覆盖的业务风险管理产品。\u003c/p\u003e\n\u003ch4 id=\"核心能力-1\"\u003e核心能力\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e资深专家团队\u003c/strong\u003e：多行业资深风控专家\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e全链路防控\u003c/strong\u003e：从端到云全链路分析与动态攻防\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e智能算法策略\u003c/strong\u003e：上千套策略模型即开即用\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e超强性能\u003c/strong\u003e：毫秒级、超高并发能力\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"功能概述\"\u003e功能概述\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e功能\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e决策引擎平台\u003c/td\u003e\n          \u003ctd\u003e可视化、交互友好的风险管理运营平台\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e场景化风控方案\u003c/td\u003e\n          \u003ctd\u003e面向注册、登录、营销、信贷等通用场景\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e设备安全能力\u003c/td\u003e\n          \u003ctd\u003e基于端上安全组件对设备风险进行识别\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"场景风控类型\"\u003e场景风控类型\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e注册风险识别\u003c/strong\u003e：发现批量注册行为\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e登录风险识别\u003c/strong\u003e：发现账户被盗行为\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e营销风险识别\u003c/strong\u003e：发现作弊、薅羊毛、套利等风险\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e设备风险识别\u003c/strong\u003e：对移动APP上的恶意设备行为进行识别\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e业务风险情报\u003c/strong\u003e：对企业平台的账户或用户进行风险检测\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"版本对比\"\u003e版本对比\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e功能\u003c/th\u003e\n          \u003cth\u003e基础版\u003c/th\u003e\n          \u003cth\u003e增强版\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e实时分析\u003c/td\u003e\n          \u003ctd\u003e支持\u003c/td\u003e\n          \u003ctd\u003e支持\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e服务返回值\u003c/td\u003e\n          \u003ctd\u003e量化评分\u003c/td\u003e\n          \u003ctd\u003e量化评分+风险特征标签\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e设备风险监测\u003c/td\u003e\n          \u003ctd\u003e不支持\u003c/td\u003e\n          \u003ctd\u003e支持\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e设备指纹\u003c/td\u003e\n          \u003ctd\u003e不支持\u003c/td\u003e\n          \u003ctd\u003e支持\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e团伙分析\u003c/td\u003e\n          \u003ctd\u003e不支持\u003c/td\u003e\n          \u003ctd\u003e支持\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e日志服务投递\u003c/td\u003e\n          \u003ctd\u003e不支持\u003c/td\u003e\n          \u003ctd\u003e支持\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch2 id=\"背诵版\"\u003e背诵版\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e内容安全\u003c/strong\u003e：深度学习 + 图片/视频/语音/文字/网页检测 + 毫秒级返回 + 99%准确率\u003c/p\u003e","tags":"","title":"Day20 业务安全"},{"columns":"python-course","content":"Day 21 - 面向对象编程：类与对象基础 什么是面向对象编程（OOP）？ 面向对象编程（Object-Oriented Programming，简称OOP）是一种程序设计范式，它使用\u0026quot;对象\u0026quot;来描述现实世界中的事物。Python 是一种多范式编程语言，完全支持面向对象编程。在 Python 中，一切皆为对象——数字、字符串、列表、字典，甚至函数都是对象。理解类和对象的概念是掌握 Python 编程的关键一步。\n面向对象编程的核心思想是将数据和操作数据的方法封装在一起，形成一个独立的单元——类（Class）。类就像是一张蓝图或者模板，定义了某种类型对象所具有的属性（特征）和方法（行为）。而对象（Object）则是根据类这张蓝图创建出来的具体实例。打个比方，\u0026ldquo;汽车\u0026quot;是一个类，而一辆具体的红色 BMW 汽车就是一个对象；\u0026ldquo;学生\u0026quot;是一个类，而\u0026quot;张三\u0026quot;这位具体的学生就是一个对象。\n类的定义与语法 在 Python 中，使用 class 关键字来定义一个类。类名通常采用 PascalCase 命名法（每个单词首字母大写），例如 Student、Person、BankAccount 等。类的定义体包含属性（数据）和方法（函数）。让我们从一个最简单的例子开始：\nclass Person: \u0026#34;\u0026#34;\u0026#34;一个人类的简单表示\u0026#34;\u0026#34;\u0026#34; def say_hello(self): \u0026#34;\u0026#34;\u0026#34;打招呼的方法\u0026#34;\u0026#34;\u0026#34; print(\u0026#34;你好！\u0026#34;) # 创建对象 p = Person() p.say_hello() 在这个例子中，我们定义了一个名为 Person 的类。类中有一个 say_hello 方法。注意方法定义中的第一个参数 self，这是面向对象编程中最重要的概念之一。\nself 参数详解 self 参数是类方法（除了类方法和静态方法之外）的第一个参数，它指向对象本身。当我们调用 p.say_hello() 时，Python 内部会将这个调用转换为 Person.say_hello(p)，也就是说，self 接收到了调用该方法的对象 p 本身。\nself 这个名字并不是关键字，你可以用其他名字来代替它，但按照 Python 的惯例，始终使用 self 是一个良好的编程习惯。使用其他名字虽然不会报错，但会让你的代码难以被其他程序员理解，因为 Python 社区已经形成了使用 self 的共识。\nself 的主要作用体现在以下几个方面：\n访问对象的属性（实例变量） 调用对象的其他方法 在方法之间传递对象本身 判断两个对象是否是同一个对象（使用 is 运算符） class Dog: def __init__(self, name, age): self.name = name # 将name存储在当前对象中 self.age = age # 将age存储在当前对象中 def bark(self): print(f\u0026#34;{self.name} 在叫：汪汪汪！\u0026#34;) def info(self): print(f\u0026#34;名字：{self.name}，年龄：{self.age}岁\u0026#34;) dog1 = Dog(\u0026#34;旺财\u0026#34;, 3) dog2 = Dog(\u0026#34;小白\u0026#34;, 5) dog1.bark() # 输出：旺财 在叫：汪汪汪！ dog2.bark() # 输出：小白 在叫：汪汪汪！ dog1.info() # 输出：名字：旺财，年龄：3岁 dog2.info() # 输出：名字：小白，年龄：5岁 类与对象的关系 类和对象之间的关系是\u0026quot;模板\u0026quot;与\u0026quot;实例\u0026quot;的关系。类定义了创建对象的蓝图，描述了一类对象共同的特征和行为；对象是类的具体实现，每个对象都有自己独立的属性值，但共享类中定义的方法。\nclass Car: # 类属性（所有对象共享） wheels = 4 def __init__(self, brand, model, year): # 实例属性（每个对象独立） self.brand = brand self.model = model self.year = year def drive(self): print(f\u0026#34;{self.brand} {self.model} 正在行驶...\u0026#34;) # 创建不同的汽车对象 car1 = Car(\u0026#34;丰田\u0026#34;, \u0026#34;卡罗拉\u0026#34;, 2022) car2 = Car(\u0026#34;本田\u0026#34;, \u0026#34;雅阁\u0026#34;, 2023) print(Car.wheels) # 4（通过类名访问类属性） print(car1.wheels) # 4（通过对象访问类属性） print(car2.wheels) # 4（通过对象访问类属性） car1.drive() # 丰田 卡罗拉 正在行驶... car2.drive() # 本田 雅阁 正在行驶... 实例属性与类属性 在 Python 类中，属性分为两大类：实例属性和类属性。实例属性是与特定对象绑定的属性，每个对象都有自己独立的实例属性副本；类属性是所有对象共享的属性，存储在类本身而非对象中。\n实例属性在 __init__ 方法中通过 self.属性名 的方式创建，也可以在其他地方动态创建。类属性直接在类体中定义，不在任何方法内部，它们被所有该类的对象共享。\n理解实例属性和类属性的区别非常重要：\n修改类属性会影响所有对象（如果对象没有覆盖它） 修改实例属性只影响当前对象 对象可以直接访问类属性，但无法直接修改类属性（除非使用特殊方法） class Student: # 类属性：所有学生共享的学校名称 school_name = \u0026#34;清华大学\u0026#34; def __init__(self, name, student_id): # 实例属性：每个学生独立的属性 self.name = name self.student_id = student_id self.grades = [] # 每个学生有自己的成绩列表 def add_grade(self, subject, score): \u0026#34;\u0026#34;\u0026#34;添加成绩\u0026#34;\u0026#34;\u0026#34; self.grades.append({\u0026#34;科目\u0026#34;: subject, \u0026#34;成绩\u0026#34;: score}) def show_info(self): \u0026#34;\u0026#34;\u0026#34;显示学生信息\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;学号：{self.student_id}\u0026#34;) print(f\u0026#34;姓名：{self.name}\u0026#34;) print(f\u0026#34;学校：{self.school_name}\u0026#34;) # 可以访问类属性 print(f\u0026#34;成绩：{self.grades}\u0026#34;) # 创建学生对象 student1 = Student(\u0026#34;张三\u0026#34;, \u0026#34;2023001\u0026#34;) student2 = Student(\u0026#34;李四\u0026#34;, \u0026#34;2023002\u0026#34;) # 通过类名访问类属性 print(Student.school_name) # 清华大学 # 通过对象访问类属性 print(student1.school_name) # 清华大学 # 修改类属性（通过类名） Student.school_name = \u0026#34;北京大学\u0026#34; print(student1.school_name) # 北京大学 print(student2.school_name) # 北京大学 # 修改实例属性 student1.school_name = \u0026#34;复旦大学\u0026#34; # 这只是给student1添加了一个新的实例属性 print(student1.school_name) # 复旦大学（实例属性） print(student2.school_name) # 北京大学（类属性，没受影响） print(Student.school_name) # 北京大学 对象的创建过程 当你使用 类名() 的方式创建对象时，Python 内部会执行一系列操作：首先，创建一个新的空对象；然后，调用 __init__ 方法（如果类定义了它）并将新对象作为 self 参数传入；最后，返回这个已经初始化好的对象。这个过程叫做\u0026quot;实例化\u0026rdquo;（Instantiation）。\nclass Book: def __init__(self, title, author, pages): print(\u0026#34;__init__ 方法被调用！\u0026#34;) self.title = title self.author = author self.pages = pages def read(self): print(f\u0026#34;正在阅读《{self.title}》...\u0026#34;) print(\u0026#34;开始创建对象...\u0026#34;) book = Book(\u0026#34;活着\u0026#34;, \u0026#34;余华\u0026#34;, 500) print(\u0026#34;对象创建完成！\u0026#34;) book.read() 执行结果：\n开始创建对象... __init__ 方法被调用！ 对象创建完成！ 正在阅读《活着》...魔术方法 dict 每个对象都有一个 __dict__ 属性，它是一个字典，包含了对象的所有实例属性。类也有 __dict__ 属性，但它包含的是类的属性和方法定义。你可以使用这个属性来动态地检查和操作对象的属性。\nclass Person: def __init__(self, name, age): self.name = name self.age = age p = Person(\u0026#34;小明\u0026#34;, 20) # 查看对象的实例属性 print(p.__dict__) # {\u0026#39;name\u0026#39;: \u0026#39;小明\u0026#39;, \u0026#39;age\u0026#39;: 20} # 动态添加属性 p.gender = \u0026#34;男\u0026#34; print(p.__dict__) # {\u0026#39;name\u0026#39;: \u0026#39;小明\u0026#39;, \u0026#39;age\u0026#39;: 20, \u0026#39;gender\u0026#39;: \u0026#39;男\u0026#39;} # 动态删除属性 del p.age print(p.__dict__) # {\u0026#39;name\u0026#39;: \u0026#39;小明\u0026#39;, \u0026#39;gender\u0026#39;: \u0026#39;男\u0026#39;} 类型与身份 在 Python 中，每个对象都有两个重要的标识：类型（type）和身份（id）。类型决定了对象可以执行哪些操作，身份是对象在内存中的唯一地址（可以使用 id() 函数获取）。使用 type() 函数可以查看对象的类型，使用 is 运算符可以比较两个对象是否是同一个对象。\nclass Animal: def __init__(self, name): self.name = name a = Animal(\u0026#34;猫\u0026#34;) b = Animal(\u0026#34;猫\u0026#34;) print(type(a)) # \u0026lt;class \u0026#39;__main__.Animal\u0026#39;\u0026gt; print(type(b)) # \u0026lt;class \u0026#39;__main__.Animal\u0026#39;\u0026gt; print(type(a) == type(b)) # True print(id(a)) # 140234567890 print(id(b)) # 140234567891（不同的内存地址） print(a is b) # False（不是同一个对象） print(a is not b) # True c = a # 让c指向a同一个对象 print(c is a) # True（是同一个对象） 属性访问的优先级 当访问一个对象的属性时，Python 会按照特定的优先级顺序进行查找：首先在对象的实例属性中查找，然后在类的类属性中查找，最后在父类中查找（关于继承和父类，我们会在后面的章节详细介绍）。\nclass MyClass: class_attr = \u0026#34;类属性\u0026#34; def __init__(self): self.instance_attr = \u0026#34;实例属性\u0026#34; obj = MyClass() # 访问实例属性 print(obj.instance_attr) # 实例属性 # 访问类属性（通过对象） print(obj.class_attr) # 类属性 # 访问不存在的属性会引发 AttributeError # print(obj.nonexistent) # AttributeError: \u0026#39;MyClass\u0026#39; object has no attribute \u0026#39;nonexistent\u0026#39; 对象的字符串表示 每个对象都可以通过 str() 或 repr() 函数转换为字符串。默认的实现通常不太友好（显示对象的内存地址），你可以通过定义 __str__ 和 __repr__ 方法来定制对象的字符串表示。我们会在 Day 23 中详细讨论这些魔术方法。\nclass Student: def __init__(self, name, score): self.name = name self.score = score s = Student(\u0026#34;王五\u0026#34;, 95) print(str(s)) # \u0026lt;__main__.Student object at 0x7f8a9c123456\u0026gt; print(repr(s)) # \u0026lt;__main__.Student object at 0x7f8a9c123456\u0026gt; 练习题 练习 1：创建简单的银行账户类 class BankAccount: def __init__(self, owner, balance=0): self.owner = owner self.balance = balance def deposit(self, amount): \u0026#34;\u0026#34;\u0026#34;存款\u0026#34;\u0026#34;\u0026#34; if amount \u0026gt; 0: self.balance += amount print(f\u0026#34;{self.owner} 存款 {amount} 元，当前余额：{self.balance} 元\u0026#34;) else: print(\u0026#34;存款金额必须为正数！\u0026#34;) def withdraw(self, amount): \u0026#34;\u0026#34;\u0026#34;取款\u0026#34;\u0026#34;\u0026#34; if amount \u0026lt;= 0: print(\u0026#34;取款金额必须为正数！\u0026#34;) elif amount \u0026gt; self.balance: print(f\u0026#34;余额不足！当前余额：{self.balance} 元\u0026#34;) else: self.balance -= amount print(f\u0026#34;{self.owner} 取款 {amount} 元，当前余额：{self.balance} 元\u0026#34;) # 测试 account = BankAccount(\u0026#34;赵六\u0026#34;, 1000) account.deposit(500) # 赵六 存款 500 元，当前余额：1500 元 account.withdraw(200) # 赵六 取款 200 元，当前余额：1300 元 account.withdraw(2000) # 余额不足！当前余额：1300 元 练习 2：创建矩形类 class Rectangle: def __init__(self, width, height): self.width = width self.height = height def area(self): \u0026#34;\u0026#34;\u0026#34;计算面积\u0026#34;\u0026#34;\u0026#34; return self.width * self.height def perimeter(self): \u0026#34;\u0026#34;\u0026#34;计算周长\u0026#34;\u0026#34;\u0026#34; return 2 * (self.width + self.height) rect = Rectangle(10, 5) print(f\u0026#34;矩形宽：{rect.width}，高：{rect.height}\u0026#34;) print(f\u0026#34;面积：{rect.area()}\u0026#34;) # 50 print(f\u0026#34;周长：{rect.perimeter()}\u0026#34;) # 30 练习 3：创建计数器类 class Counter: count = 0 # 类属性，记录所有计数器的总数 def __init__(self): Counter.count += 1 self.current = 0 def increment(self): \u0026#34;\u0026#34;\u0026#34;计数值加1\u0026#34;\u0026#34;\u0026#34; self.current += 1 def reset(self): \u0026#34;\u0026#34;\u0026#34;重置当前计数器\u0026#34;\u0026#34;\u0026#34; self.current = 0 @classmethod def get_total_count(cls): \u0026#34;\u0026#34;\u0026#34;获取创建的计数器总数\u0026#34;\u0026#34;\u0026#34; return cls.count c1 = Counter() c2 = Counter() c3 = Counter() print(f\u0026#34;创建的计数器总数：{Counter.get_total_count()}\u0026#34;) # 3 c1.increment() c1.increment() c2.increment() print(f\u0026#34;c1的计数值：{c1.current}\u0026#34;) # 2 print(f\u0026#34;c2的计数值：{c2.current}\u0026#34;) # 1 print(f\u0026#34;c3的计数值：{c3.current}\u0026#34;) # 0 常见错误与注意事项 忘记 self 参数：在类方法中忘记包含 self 参数是最常见的错误之一。\n拼写错误：属性名拼写错误会导致 AttributeError，例如 self.name 和 self.nmae 是两个不同的属性。\n可变默认参数：不要使用可变对象（如列表、字典）作为默认参数，这会导致所有对象共享同一份数据。\n类属性与实例属性混淆：初学者常常不小心修改了类属性而不是实例属性，导致意外影响所有对象。\n总结 今天我们学习了 Python 面向对象编程的基础知识：\n类是对象的蓝图，定义了对象的属性和方法 对象是类的实例，通过 类名() 的方式创建 self 参数指向当前对象，用于访问对象的属性和方法 实例属性属于单个对象，类属性被所有对象共享 理解 self、属性访问顺序、以及类与对象的关系是掌握 OOP 的基础 在接下来的几天里，我们将继续深入学习面向对象编程的其他重要概念，包括构造函数 __init__、字符串表示 __str__ 和 __del__、私有属性与封装、继承与多态等。掌握这些知识将帮助你编写更加结构化、可维护和可扩展的 Python 代码。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-21-oop-class-object/","summary":"\u003ch1 id=\"day-21---面向对象编程类与对象基础\"\u003eDay 21 - 面向对象编程：类与对象基础\u003c/h1\u003e\n\u003ch2 id=\"什么是面向对象编程oop\"\u003e什么是面向对象编程（OOP）？\u003c/h2\u003e\n\u003cp\u003e面向对象编程（Object-Oriented Programming，简称OOP）是一种程序设计范式，它使用\u0026quot;对象\u0026quot;来描述现实世界中的事物。Python 是一种多范式编程语言，完全支持面向对象编程。在 Python 中，一切皆为对象——数字、字符串、列表、字典，甚至函数都是对象。理解类和对象的概念是掌握 Python 编程的关键一步。\u003c/p\u003e\n\u003cp\u003e面向对象编程的核心思想是将数据和操作数据的方法封装在一起，形成一个独立的单元——类（Class）。类就像是一张蓝图或者模板，定义了某种类型对象所具有的属性（特征）和方法（行为）。而对象（Object）则是根据类这张蓝图创建出来的具体实例。打个比方，\u0026ldquo;汽车\u0026quot;是一个类，而一辆具体的红色 BMW 汽车就是一个对象；\u0026ldquo;学生\u0026quot;是一个类，而\u0026quot;张三\u0026quot;这位具体的学生就是一个对象。\u003c/p\u003e\n\u003ch2 id=\"类的定义与语法\"\u003e类的定义与语法\u003c/h2\u003e\n\u003cp\u003e在 Python 中，使用 \u003ccode\u003eclass\u003c/code\u003e 关键字来定义一个类。类名通常采用 PascalCase 命名法（每个单词首字母大写），例如 \u003ccode\u003eStudent\u003c/code\u003e、\u003ccode\u003ePerson\u003c/code\u003e、\u003ccode\u003eBankAccount\u003c/code\u003e 等。类的定义体包含属性（数据）和方法（函数）。让我们从一个最简单的例子开始：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePerson\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;一个人类的简单表示\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003esay_hello\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;打招呼的方法\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;你好！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 创建对象\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ep \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Person()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ep\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esay_hello()\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e在这个例子中，我们定义了一个名为 \u003ccode\u003ePerson\u003c/code\u003e 的类。类中有一个 \u003ccode\u003esay_hello\u003c/code\u003e 方法。注意方法定义中的第一个参数 \u003ccode\u003eself\u003c/code\u003e，这是面向对象编程中最重要的概念之一。\u003c/p\u003e\n\u003ch2 id=\"self-参数详解\"\u003eself 参数详解\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eself\u003c/code\u003e 参数是类方法（除了类方法和静态方法之外）的第一个参数，它指向对象本身。当我们调用 \u003ccode\u003ep.say_hello()\u003c/code\u003e 时，Python 内部会将这个调用转换为 \u003ccode\u003ePerson.say_hello(p)\u003c/code\u003e，也就是说，\u003ccode\u003eself\u003c/code\u003e 接收到了调用该方法的对象 \u003ccode\u003ep\u003c/code\u003e 本身。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eself\u003c/code\u003e 这个名字并不是关键字，你可以用其他名字来代替它，但按照 Python 的惯例，始终使用 \u003ccode\u003eself\u003c/code\u003e 是一个良好的编程习惯。使用其他名字虽然不会报错，但会让你的代码难以被其他程序员理解，因为 Python 社区已经形成了使用 \u003ccode\u003eself\u003c/code\u003e 的共识。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eself\u003c/code\u003e 的主要作用体现在以下几个方面：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e访问对象的属性（实例变量）\u003c/li\u003e\n\u003cli\u003e调用对象的其他方法\u003c/li\u003e\n\u003cli\u003e在方法之间传递对象本身\u003c/li\u003e\n\u003cli\u003e判断两个对象是否是同一个对象（使用 \u003ccode\u003eis\u003c/code\u003e 运算符）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eDog\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e __init__(self, name, age):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ename \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e name      \u003cspan style=\"color:#75715e\"\u003e# 将name存储在当前对象中\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eage \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e age        \u003cspan style=\"color:#75715e\"\u003e# 将age存储在当前对象中\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ebark\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 在叫：汪汪汪！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003einfo\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;名字：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e，年龄：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eage\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e岁\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edog1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Dog(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;旺财\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edog2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Dog(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;小白\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edog1\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ebark()    \u003cspan style=\"color:#75715e\"\u003e# 输出：旺财 在叫：汪汪汪！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edog2\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ebark()    \u003cspan style=\"color:#75715e\"\u003e# 输出：小白 在叫：汪汪汪！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edog1\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003einfo()    \u003cspan style=\"color:#75715e\"\u003e# 输出：名字：旺财，年龄：3岁\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edog2\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003einfo()    \u003cspan style=\"color:#75715e\"\u003e# 输出：名字：小白，年龄：5岁\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"类与对象的关系\"\u003e类与对象的关系\u003c/h2\u003e\n\u003cp\u003e类和对象之间的关系是\u0026quot;模板\u0026quot;与\u0026quot;实例\u0026quot;的关系。类定义了创建对象的蓝图，描述了一类对象共同的特征和行为；对象是类的具体实现，每个对象都有自己独立的属性值，但共享类中定义的方法。\u003c/p\u003e","tags":"Python, 编程","title":"Day 21 - 面向对象编程：类与对象基础"},{"columns":"acp-course","content":"其他安全产品 详细讲解 一、身份安全 - IDaaS 应用身份服务IDaaS介绍 IDaaS（Identity as a Service）是阿里云原生企业身份管理服务：\nEIAM：用于保护企业内部身份 CIAM：提供面向外部会员的身份管理 安全认证：集成多种无密码认证方式 IDaaS设计理念 默认安全：可用性和安全性难以两全时，优先保障安全性 开发友好：API在线调试、SDK与样例代码、代码开源 EIAM使用流程 免费开通实例 → 创建账户 → 登录门户 → 创建应用\nCIAM版本 版本 说明 专属版 独立环境部署，支持功能定制，适合中大型公司 标准版（未开放） 共享集群，按月活用户计费 免费版（未开放） MAU限制100以内 安全认证 号码认证：整合三大运营商网关认证能力 IFAA：金融级移动端生物识别产品 WebAuthn：PC端浏览器免密登录 短信认证、OTP 二、安全管理服务 安全管家服务 阿里云安全专家提供的全方位安全技术和咨询服务。\n产品功能 安全体系咨询：建设完善的安全运营体系 安全风险评估：评估企业信息系统安全风险 安全事件应急响应：7*24远程紧急响应处理 应用安全评估：评估应用层安全风险 安全监测与巡检：每日安全巡检 安全加固服务：指导安全加固 双层服务形态 类型 说明 企业版 安全常态化防护，风险评估+每日巡检+安全加固+事件提醒+应急响应 护航版 应急突发保障，量身定制防护方案+全面安全体检+全天候值守 应急响应服务 参照国家信息安全事件响应处理标准，提供预防、情报收集、遏制、根除、恢复流程的7*24远程紧急响应处理。\n等保咨询服务 等级保护整改方案咨询 安全产品选型及部署指导 系统安全整改工作 安全管理咨询 威胁狩猎服务 基于欺骗伪装技术，通过部署诱饵和陷阱，诱导攻击者进入蜜网，完整记录攻击者行为，捕获高级未知攻击。\n三、通用安全解决方案 等保合规解决方案 覆盖等保定级、备案、建设整改及测评阶段：\n系统定级 系统备案 建设整改 等级测评 监督检查 等保合规2.0架构（等保三级） 安全物理环境：阿里云平台自带 安全通信网络：网络架构、通信传输、可信验证 安全区域边界：边界防护、访问控制、入侵防范、恶意代码防护、安全审计 安全计算环境：身份鉴别、访问控制、安全审计、入侵防范等 安全管理中心：系统管理、审计管理、安全管理、集中管控 四、云监控 云监控概念 云监控（CloudMonitor）是针对阿里云资源和互联网应用进行监控的服务，用于收集监控指标、探测可用性、设置警报。\n产品功能 Dashboard：创建自定义监控大盘 应用分组：跨服务、跨region集中管理 主机监控：安装插件查看监控图表 自定义监控：创建自定义监控报警规则 站点监控：创建站点监控任务 日志监控：结合日志服务 云产品监控：查看监控数据 报警服务：创建报警规则、联系人、联系组 主机监控 云监控每分钟统计CPU消耗Top5的进程，记录CPU使用率、内存使用率和打开文件数。\n自定义事件监控 提供事件类型数据的上报、查询和报警功能。\n收费概览 基础云监控：免费（主机监控、云产品监控、报警等） 收费项：站点监控、自定义监控、短信或电话报警通知 背诵版 IDaaS = EIAM(企业内部) + CIAM(外部会员) + 安全认证\nEIAM流程：开通实例 → 创建账户 → 登录门户 → 创建应用\n安全管家服务：风险评估 + 巡检 + 加固 + 应急响应\n双层服务形态：企业版(常态化) + 护航版(突发应急)\n等保合规五步：定级 → 备案 → 整改 → 测评 → 监督\n云监控功能：Dashboard + 应用分组 + 主机监控 + 自定义监控 + 站点监控 + 日志监控 + 报警服务\n云监控收费：基础功能免费，站点监控/自定义监控/短信电话报警收费\n速记版 IDaaS = 云原生身份管理 = EIAM + CIAM + 无密码认证\n安全管家 = 阿里云安全专家 + 全方位安全咨询\n等保合规 = 定级→备案→整改→测评→监督\n云监控 = IT运维的眼 = 采集+检测+告警+展示+闭环\n云监控免费 = 主机+云产品+应用分组+Dashboard\n云监控收费 = 站点监控+自定义监控+短信电话报警\n测试题 选择题 IDaaS中，用于保护企业内部身份的是？\nA. CIAM B. EIAM C. 专属版 D. 标准版 安全管家服务不包含以下哪项功能？\nA. 安全风险评估 B. 数据加密 C. 安全监测与巡检 D. 安全加固服务 等保合规解决方案第一步是什么？\nA. 系统备案 B. 系统定级 C. 建设整改 D. 等级测评 云监控每分钟统计CPU消耗Top几的进程？\nA. Top 3 B. Top 5 C. Top 10 D. Top 15 以下哪项不是云监控的收费项？\nA. 站点监控 B. 自定义监控 C. 主机监控 D. 短信报警 判断题 IDaaS的\u0026quot;默认安全\u0026quot;设计理念是在可用性和安全性难以两全时，优先保障安全性。 安全管家服务的护航版主要针对安全常态化防护场景。 云监控的基础功能全部免费，不收取任何费用。 威胁狩猎服务通过部署蜜罐来诱骗攻击者。 云监控的事件监控提供事件类型数据的上报、查询和报警功能。 答案 1.B | 2.B | 3.B | 4.B | 5.C\n6.√ | 7.× | 8.× | 9.√ | 10.√\n","description":"","permalink":"https://blog.uuworld.cn/acp/acp-day-21-acp-day-21-%E5%85%B6%E4%BB%96%E5%AE%89%E5%85%A8%E4%BA%A7%E5%93%81/","summary":"\u003ch1 id=\"其他安全产品\"\u003e其他安全产品\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"一身份安全---idaas\"\u003e一、身份安全 - IDaaS\u003c/h3\u003e\n\u003ch4 id=\"应用身份服务idaas介绍\"\u003e应用身份服务IDaaS介绍\u003c/h4\u003e\n\u003cp\u003eIDaaS（Identity as a Service）是阿里云原生企业身份管理服务：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eEIAM\u003c/strong\u003e：用于保护企业内部身份\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCIAM\u003c/strong\u003e：提供面向外部会员的身份管理\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e安全认证\u003c/strong\u003e：集成多种无密码认证方式\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"idaas设计理念\"\u003eIDaaS设计理念\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e默认安全\u003c/strong\u003e：可用性和安全性难以两全时，优先保障安全性\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e开发友好\u003c/strong\u003e：API在线调试、SDK与样例代码、代码开源\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"eiam使用流程\"\u003eEIAM使用流程\u003c/h4\u003e\n\u003cp\u003e免费开通实例 → 创建账户 → 登录门户 → 创建应用\u003c/p\u003e\n\u003ch4 id=\"ciam版本\"\u003eCIAM版本\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e版本\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e专属版\u003c/td\u003e\n          \u003ctd\u003e独立环境部署，支持功能定制，适合中大型公司\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e标准版（未开放）\u003c/td\u003e\n          \u003ctd\u003e共享集群，按月活用户计费\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e免费版（未开放）\u003c/td\u003e\n          \u003ctd\u003eMAU限制100以内\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"安全认证\"\u003e安全认证\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e号码认证\u003c/strong\u003e：整合三大运营商网关认证能力\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIFAA\u003c/strong\u003e：金融级移动端生物识别产品\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eWebAuthn\u003c/strong\u003e：PC端浏览器免密登录\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e短信认证、OTP\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"二安全管理服务\"\u003e二、安全管理服务\u003c/h3\u003e\n\u003ch4 id=\"安全管家服务\"\u003e安全管家服务\u003c/h4\u003e\n\u003cp\u003e阿里云安全专家提供的全方位安全技术和咨询服务。\u003c/p\u003e\n\u003ch4 id=\"产品功能\"\u003e产品功能\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e安全体系咨询\u003c/strong\u003e：建设完善的安全运营体系\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e安全风险评估\u003c/strong\u003e：评估企业信息系统安全风险\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e安全事件应急响应\u003c/strong\u003e：7*24远程紧急响应处理\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e应用安全评估\u003c/strong\u003e：评估应用层安全风险\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e安全监测与巡检\u003c/strong\u003e：每日安全巡检\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e安全加固服务\u003c/strong\u003e：指导安全加固\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"双层服务形态\"\u003e双层服务形态\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e类型\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e企业版\u003c/td\u003e\n          \u003ctd\u003e安全常态化防护，风险评估+每日巡检+安全加固+事件提醒+应急响应\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e护航版\u003c/td\u003e\n          \u003ctd\u003e应急突发保障，量身定制防护方案+全面安全体检+全天候值守\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"应急响应服务\"\u003e应急响应服务\u003c/h4\u003e\n\u003cp\u003e参照国家信息安全事件响应处理标准，提供预防、情报收集、遏制、根除、恢复流程的7*24远程紧急响应处理。\u003c/p\u003e\n\u003ch4 id=\"等保咨询服务\"\u003e等保咨询服务\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e等级保护整改方案咨询\u003c/li\u003e\n\u003cli\u003e安全产品选型及部署指导\u003c/li\u003e\n\u003cli\u003e系统安全整改工作\u003c/li\u003e\n\u003cli\u003e安全管理咨询\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"威胁狩猎服务\"\u003e威胁狩猎服务\u003c/h4\u003e\n\u003cp\u003e基于欺骗伪装技术，通过部署诱饵和陷阱，诱导攻击者进入蜜网，完整记录攻击者行为，捕获高级未知攻击。\u003c/p\u003e\n\u003ch3 id=\"三通用安全解决方案\"\u003e三、通用安全解决方案\u003c/h3\u003e\n\u003ch4 id=\"等保合规解决方案\"\u003e等保合规解决方案\u003c/h4\u003e\n\u003cp\u003e覆盖等保定级、备案、建设整改及测评阶段：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e系统定级\u003c/li\u003e\n\u003cli\u003e系统备案\u003c/li\u003e\n\u003cli\u003e建设整改\u003c/li\u003e\n\u003cli\u003e等级测评\u003c/li\u003e\n\u003cli\u003e监督检查\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"等保合规20架构等保三级\"\u003e等保合规2.0架构（等保三级）\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e安全物理环境：阿里云平台自带\u003c/li\u003e\n\u003cli\u003e安全通信网络：网络架构、通信传输、可信验证\u003c/li\u003e\n\u003cli\u003e安全区域边界：边界防护、访问控制、入侵防范、恶意代码防护、安全审计\u003c/li\u003e\n\u003cli\u003e安全计算环境：身份鉴别、访问控制、安全审计、入侵防范等\u003c/li\u003e\n\u003cli\u003e安全管理中心：系统管理、审计管理、安全管理、集中管控\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"四云监控\"\u003e四、云监控\u003c/h3\u003e\n\u003ch4 id=\"云监控概念\"\u003e云监控概念\u003c/h4\u003e\n\u003cp\u003e云监控（CloudMonitor）是针对阿里云资源和互联网应用进行监控的服务，用于收集监控指标、探测可用性、设置警报。\u003c/p\u003e","tags":"","title":"Day21 其他安全产品"},{"columns":"python-course","content":"Day 22 - 构造函数 init 详解 什么是 init 方法？ __init__ 是 Python 类中的一个特殊方法，也被称为\u0026quot;构造函数\u0026quot;或\u0026quot;初始化方法\u0026quot;。当我们使用 类名() 创建对象时，__init__ 方法会被自动调用。它的主要作用是对新创建的对象进行初始化设置，比如给对象的属性赋初值、建立对象之间的关联关系等。\n__init__ 这个名字来源于 \u0026ldquo;initialize\u0026rdquo;（初始化）这个词。在 Python 中，以双下划线 __ 开头和结尾的方法称为\u0026quot;魔术方法\u0026quot;（Magic Methods）或\u0026quot;特殊方法\u0026quot;（Special Methods），它们有特殊的用途，会在特定情况下被 Python 自动调用。\ninit 的基本语法 class 类名: def __init__(self, 参数1, 参数2, ...): # 初始化代码 self.属性1 = 参数1 self.属性2 = 参数2 __init__ 方法的第一个参数永远是 self（指向正在创建的对象），后面的参数是你在创建对象时需要传入的值。\nclass Person: def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender print(f\u0026#34;新对象创建：{self.name}\u0026#34;) # 创建对象时传入参数 person1 = Person(\u0026#34;张三\u0026#34;, 25, \u0026#34;男\u0026#34;) person2 = Person(\u0026#34;李四\u0026#34;, 30, \u0026#34;女\u0026#34;) print(f\u0026#34;{person1.name} 是 {person1.age} 岁的 {person1.gender}生\u0026#34;) print(f\u0026#34;{person2.name} 是 {person2.age} 岁的 {person2.gender}生\u0026#34;) 输出：\n新对象创建：张三 新对象创建：李四 张三 是 25 岁的 男生 李四 是 30 岁的 女生为什么需要 init？ __init__ 方法的主要价值在于确保每个对象在创建后都处于一个有效的初始状态。没有 __init__ 的对象，其属性是未定义的，尝试访问这些属性会引发 AttributeError。通过在 __init__ 中定义属性并赋予初始值，我们可以保证对象的属性在任何时候都是可访问的。\n考虑一个实际场景：假设我们需要创建一个表示\u0026quot;学生\u0026quot;的类。没有 __init__ 时，我们不得不这样做：\nclass Student: pass # 空类 # 创建对象 s = Student() s.name = \u0026#34;张三\u0026#34; # 手动添加属性 s.score = 95 # 手动添加属性 这种方式虽然可行，但存在很多问题：忘记设置某个属性、属性名称拼写错误、不同对象可能缺少不同的属性等。通过使用 __init__，我们强制要求在创建对象时提供必要的初始值，并且明确了对象应该具有哪些属性。\nclass Student: def __init__(self, name, score): self.name = name self.score = score # 创建对象时必须提供所有必要参数 s = Student(\u0026#34;张三\u0026#34;, 95) # 正确：所有属性都被初始化 print(s.name, s.score) # s2 = Student() # 错误：缺少必要参数 # s3 = Student(\u0026#34;李四\u0026#34;) # 错误：缺少 score 参数 默认参数值 与普通函数一样，__init__ 方法的参数也可以有默认值。这允许我们创建对象时提供部分参数，使用默认值填充其他参数。\nclass Rectangle: def __init__(self, width=10, height=5): self.width = width self.height = height def area(self): return self.width * self.height # 使用默认值 r1 = Rectangle() print(f\u0026#34;r1 宽：{r1.width}，高：{r1.height}，面积：{r1.area()}\u0026#34;) # r1 宽：10，高：5，面积：50 # 只提供一个参数 r2 = Rectangle(20) print(f\u0026#34;r2 宽：{r2.width}，高：{r2.height}，面积：{r2.area()}\u0026#34;) # r2 宽：20，高：5，面积：100 # 提供两个参数 r3 = Rectangle(8, 12) print(f\u0026#34;r3 宽：{r3.width}，高：{r3.height}，面积：{r3.area()}\u0026#34;) # r3 宽：8，高：12，面积：96 None 作为默认值的妙用 在某些情况下，我们需要创建一个可能暂时没有实际值的属性。这时可以使用 None 作为默认值，并在后续代码中根据需要赋值。\nclass Book: def __init__(self, title, author, price=None, publisher=None): self.title = title self.author = author self.price = price # 价格可能还不知道 self.publisher = publisher # 出版社可能还不知道 def publish(self, publisher, price): \u0026#34;\u0026#34;\u0026#34;出版图书，设置出版社和价格\u0026#34;\u0026#34;\u0026#34; self.publisher = publisher self.price = price def display(self): \u0026#34;\u0026#34;\u0026#34;显示图书信息\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;书名：《{self.title}》\u0026#34;) print(f\u0026#34;作者：{self.author}\u0026#34;) if self.publisher: print(f\u0026#34;出版社：{self.publisher}\u0026#34;) if self.price: print(f\u0026#34;价格：{self.price}元\u0026#34;) # 创建图书时，价格和出版社暂未确定 book = Book(\u0026#34;时间简史\u0026#34;, \u0026#34;史蒂芬·霍金\u0026#34;) book.display() print(\u0026#34;--- 出版后 ---\u0026#34;) book.publish(\u0026#34;湖南科技出版社\u0026#34;, 68) book.display() 可变默认参数的陷阱 这是一个 Python 初学者经常犯的错误：不要使用可变对象（如列表、字典）作为默认参数。默认值只在函数定义时计算一次，如果修改了可变默认值，所有后续调用都会使用同一个被修改的对象。\n# 错误的方式：使用了可变默认参数 class BuggyStack: def __init__(self, items=[]): # 危险！items 会在所有实例间共享 self.items = items def push(self, item): self.items.append(item) def pop(self): return self.items.pop() # 测试 stack1 = BuggyStack() stack1.push(1) print(f\u0026#34;stack1.items: {stack1.items}\u0026#34;) # [1] stack2 = BuggyStack() print(f\u0026#34;stack2.items: {stack2.items}\u0026#34;) # [1] -- 这是个 BUG！应该是 [] # 正确的方式：使用 None 作为默认值 class CorrectStack: def __init__(self, items=None): self.items = items if items is not None else [] def push(self, item): self.items.append(item) def pop(self): return self.items.pop() # 测试 stack3 = CorrectStack() stack3.push(1) print(f\u0026#34;stack3.items: {stack3.items}\u0026#34;) # [1] stack4 = CorrectStack() print(f\u0026#34;stack4.items: {stack4.items}\u0026#34;) # [] -- 正确！ 实例属性与 init 的关系 __init__ 方法是设置实例属性的主要场所，但实例属性并不一定要在 __init__ 中定义。你可以在其他方法中创建实例属性，也可以在对象创建后动态添加属性。\nclass Example: def __init__(self, value): self.value = value # 在 __init__ 中定义 self.double = value * 2 # 也可以在 __init__ 中计算得到 def add_method(self, amount): # 在其他方法中创建新的实例属性 self.added = amount self.total = self.value + amount obj = Example(10) print(obj.value) # 10 print(obj.double) # 20 obj.add_method(5) print(obj.added) # 5 print(obj.total) # 15 # 动态添加属性（不推荐，但可行） obj.new_attr = \u0026#34;动态添加的属性\u0026#34; print(obj.new_attr) # 动态添加的属性 虽然可以动态添加属性，但为了代码的可读性和可维护性，建议将所有实例属性都在 __init__ 中定义。这样做的好处是：所有对象都会有一致的属性结构，代码审查时能一眼看出类的所有状态。\n多态与 init __init__ 方法在面向对象的多态特性中扮演重要角色。虽然 Python 本身是动态类型语言，但通过合理设计 __init__ 方法和类层次结构，可以实现统一接口的效果。\nclass Shape: def __init__(self, color=\u0026#34;黑色\u0026#34;): self.color = color def area(self): raise NotImplementedError(\u0026#34;子类必须实现 area 方法\u0026#34;) def describe(self): return f\u0026#34;一个{self.color}的形状\u0026#34; class Circle(Shape): def __init__(self, radius, color=\u0026#34;红色\u0026#34;): super().__init__(color) # 调用父类的 __init__ self.radius = radius def area(self): return 3.14159 * self.radius ** 2 class Rectangle(Shape): def __init__(self, width, height, color=\u0026#34;蓝色\u0026#34;): super().__init__(color) self.width = width self.height = height def area(self): return self.width * self.height # 多态：不同类型的对象可以用相同的接口 shapes = [Circle(5), Rectangle(4, 6), Circle(3)] for shape in shapes: print(f\u0026#34;{shape.describe()}，面积：{shape.area():.2f}\u0026#34;) init 与 new 的区别 Python 中还有另一个魔术方法 __new__，它负责创建对象，而 __init__ 负责初始化对象。在大多数情况下，你只需要重写 __new__ 来实现单例模式或其他特殊的对象创建逻辑，而让 __init__ 处理初始化。\nclass MyClass: def __new__(cls, *args, **kwargs): print(\u0026#34;__new__ 被调用，创建对象\u0026#34;) instance = super().__new__(cls) # 调用父类的 __new__ return instance def __init__(self, value): print(\u0026#34;__init__ 被调用，初始化对象\u0026#34;) self.value = value # 创建对象 obj = MyClass(100) print(f\u0026#34;obj.value = {obj.value}\u0026#34;) 输出：\n__new__ 被调用，创建对象 __init__ 被调用，初始化对象 obj.value = 100链式调用与 init 一个高级技巧是在 __init__ 中返回 None（或者更准确地说，__init__ 不应该返回任何东西）。如果你在 __init__ 中返回非 None 值，Python 会抛出 TypeError。这是因为 __init__ 的设计初衷是初始化对象，而不是创建对象。\nclass Test: def __init__(self): self.data = [] # return [] # 错误！__init__ 不能返回值 验证与类型检查 在 __init__ 中进行参数验证是一个好的实践。这确保了对象始终处于有效状态。\nclass BankAccount: def __init__(self, owner, balance=0): # 类型检查 if not isinstance(owner, str): raise TypeError(\u0026#34;owner 必须是字符串\u0026#34;) if not isinstance(balance, (int, float)): raise TypeError(\u0026#34;balance 必须是数字\u0026#34;) if balance \u0026lt; 0: raise ValueError(\u0026#34;balance 不能为负数\u0026#34;) self.owner = owner self.balance = balance def deposit(self, amount): if amount \u0026lt;= 0: raise ValueError(\u0026#34;存款金额必须为正数\u0026#34;) self.balance += amount def withdraw(self, amount): if amount \u0026lt;= 0: raise ValueError(\u0026#34;取款金额必须为正数\u0026#34;) if amount \u0026gt; self.balance: raise ValueError(\u0026#34;余额不足\u0026#34;) self.balance -= amount # 测试验证 try: account = BankAccount(\u0026#34;张三\u0026#34;, -100) # 抛出 ValueError except ValueError as e: print(f\u0026#34;错误：{e}\u0026#34;) try: account = BankAccount(\u0026#34;李四\u0026#34;, 100) account.withdraw(200) # 余额不足 except ValueError as e: print(f\u0026#34;错误：{e}\u0026#34;) 属性类型标注（Type Hints） Python 3.5+ 引入了类型标注（Type Hints）功能，在 __init__ 中使用类型标注可以让代码更加清晰，也能配合 IDE 提供更好的自动补全和类型检查。\nfrom typing import Optional, List class Student: def __init__(self, name: str, age: int, grades: Optional[List[int]] = None): self.name: str = name self.age: int = age self.grades: List[int] = grades if grades is not None else [] def add_grade(self, grade: int) -\u0026gt; None: if 0 \u0026lt;= grade \u0026lt;= 100: self.grades.append(grade) else: raise ValueError(\u0026#34;成绩必须在 0-100 之间\u0026#34;) def average(self) -\u0026gt; float: if not self.grades: return 0.0 return sum(self.grades) / len(self.grades) # 使用类型标注 s = Student(\u0026#34;王五\u0026#34;, 18) s.add_grade(95) s.add_grade(88) s.add_grade(92) print(f\u0026#34;{s.name} 的平均分：{s.average():.2f}\u0026#34;) 练习题 练习 1：创建日期类 class Date: def __init__(self, year, month, day): self.year = year self.month = month self.day = day def is_valid(self): \u0026#34;\u0026#34;\u0026#34;简单的日期有效性检查\u0026#34;\u0026#34;\u0026#34; if month \u0026lt; 1 or month \u0026gt; 12: return False if day \u0026lt; 1 or day \u0026gt; 31: return False return True def display(self): \u0026#34;\u0026#34;\u0026#34;以 YYYY-MM-DD 格式显示\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;{self.year:04d}-{self.month:02d}-{self.day:02d}\u0026#34; # 创建日期对象 date1 = Date(2024, 1, 15) date2 = Date(2024, 12, 25) print(date1.display()) # 2024-01-15 print(date2.display()) # 2024-12-25 练习 2：创建带验证的分数类 class Fraction: def __init__(self, numerator, denominator=1): if denominator == 0: raise ValueError(\u0026#34;分母不能为零\u0026#34;) self.numerator = numerator self.denominator = denominator self._simplify() def _simplify(self): \u0026#34;\u0026#34;\u0026#34;约分\u0026#34;\u0026#34;\u0026#34; from math import gcd g = gcd(abs(self.numerator), abs(self.denominator)) self.numerator //= g self.denominator //= g if self.denominator \u0026lt; 0: self.numerator = -self.numerator self.denominator = -self.denominator def __str__(self): if self.denominator == 1: return str(self.numerator) return f\u0026#34;{self.numerator}/{self.denominator}\u0026#34; # 测试 f1 = Fraction(4, 8) f2 = Fraction(6, -9) f3 = Fraction(5) print(f1) # 1/2 print(f2) # -2/3 print(f3) # 5 练习 3：创建简单的联系人簿 class Contact: def __init__(self, name, phone, email=None, address=None): self.name = name self.phone = phone self.email = email self.address = address def display(self): print(f\u0026#34;姓名：{self.name}\u0026#34;) print(f\u0026#34;电话：{self.phone}\u0026#34;) if self.email: print(f\u0026#34;邮箱：{self.email}\u0026#34;) if self.address: print(f\u0026#34;地址：{self.address}\u0026#34;) class AddressBook: def __init__(self): self.contacts = [] def add_contact(self, contact): self.contacts.append(contact) def search(self, name): for c in self.contacts: if name in c.name: c.display() print(\u0026#34;-\u0026#34; * 20) # 使用 ab = AddressBook() ab.add_contact(Contact(\u0026#34;张三\u0026#34;, \u0026#34;13800138000\u0026#34;, \u0026#34;zhang@example.com\u0026#34;)) ab.add_contact(Contact(\u0026#34;李四\u0026#34;, \u0026#34;13900139000\u0026#34;, address=\u0026#34;北京市朝阳区\u0026#34;)) ab.add_contact(Contact(\u0026#34;张五\u0026#34;, \u0026#34;13700137000\u0026#34;)) print(\u0026#34;搜索\u0026#39;张\u0026#39;的结果：\u0026#34;) ab.search(\u0026#34;张\u0026#34;) 总结 __init__ 方法是 Python 面向对象编程中最核心的概念之一：\n__init__ 在对象创建后自动调用，用于初始化对象的状态 第一个参数必须是 self，指向正在创建的对象 可以使用默认参数来提供可选参数 避免使用可变对象作为默认参数，使用 None 代替 应该在 __init__ 中定义所有实例属性，保证对象的完整性 可以进行参数验证，确保对象状态的有效性 配合类型标注使用，可以让代码更加清晰和易于维护 掌握 __init__ 的使用是编写高质量 Python 类的基础。在后续的学习中，我们将继续探索 __str__、__del__ 等其他魔术方法，以及继承、多态等高级面向对象概念。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-22-init/","summary":"\u003ch1 id=\"day-22---构造函数-init-详解\"\u003eDay 22 - 构造函数 \u003cstrong\u003einit\u003c/strong\u003e 详解\u003c/h1\u003e\n\u003ch2 id=\"什么是-init-方法\"\u003e什么是 \u003cstrong\u003einit\u003c/strong\u003e 方法？\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003e__init__\u003c/code\u003e 是 Python 类中的一个特殊方法，也被称为\u0026quot;构造函数\u0026quot;或\u0026quot;初始化方法\u0026quot;。当我们使用 \u003ccode\u003e类名()\u003c/code\u003e 创建对象时，\u003ccode\u003e__init__\u003c/code\u003e 方法会被自动调用。它的主要作用是对新创建的对象进行初始化设置，比如给对象的属性赋初值、建立对象之间的关联关系等。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e__init__\u003c/code\u003e 这个名字来源于 \u0026ldquo;initialize\u0026rdquo;（初始化）这个词。在 Python 中，以双下划线 \u003ccode\u003e__\u003c/code\u003e 开头和结尾的方法称为\u0026quot;魔术方法\u0026quot;（Magic Methods）或\u0026quot;特殊方法\u0026quot;（Special Methods），它们有特殊的用途，会在特定情况下被 Python 自动调用。\u003c/p\u003e\n\u003ch2 id=\"init-的基本语法\"\u003e\u003cstrong\u003einit\u003c/strong\u003e 的基本语法\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e类名\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e __init__(self, 参数1, 参数2, \u003cspan style=\"color:#f92672\"\u003e...\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 初始化代码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e属性1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e 参数1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e属性2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e 参数2\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003e__init__\u003c/code\u003e 方法的第一个参数永远是 \u003ccode\u003eself\u003c/code\u003e（指向正在创建的对象），后面的参数是你在创建对象时需要传入的值。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePerson\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e __init__(self, name, age, gender):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ename \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e name\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eage \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e age\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egender \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e gender\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;新对象创建：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 创建对象时传入参数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eperson1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Person(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e25\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;男\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eperson2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Person(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;李四\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;女\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eperson1\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 是 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eperson1\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eage\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 岁的 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eperson1\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egender\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e生\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eperson2\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 是 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eperson2\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eage\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 岁的 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eperson2\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egender\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e生\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输出：\u003c/p\u003e","tags":"Python, 编程","title":"Day 22 - 构造函数 __init__ 详解"},{"columns":"python-course","content":"Day 23 - 字符串表示 str 与 del 对象的字符串表示概述 在 Python 中，每个对象都可以被转换为字符串。当你使用 print() 函数打印一个对象，或者在某些需要字符串的地方使用对象时，Python 需要将对象转换为字符串。默认的实现通常显示的是类似 \u0026lt;__main__.ClassName object at 0x7f8a9c123456\u0026gt; 这样的信息，虽然包含了对象的内存地址，但对于人类阅读来说并不友好。\n为了提供更有意义的字符串表示，Python 提供了两个魔术方法：__str__ 和 __repr__。通过在类中重写这两个方法，你可以自定义对象的字符串表现形式，使输出更加友好和有意义。\n这两个方法的区别在于：__str__ 是面向用户的字符串表示，用于给终端用户查看；而 __repr__ 是面向开发者的字符串表示，应该尽可能提供详细的信息，以便开发者调试。\nstr 方法详解 __str__ 方法在以下情况会被调用：\n使用 print() 函数打印对象时 使用 str() 函数转换对象时 在需要字符串的地方使用 f-string 格式化对象时 用户友好的错误消息中 __str__ 方法应该返回一个字符串。如果没有定义 __str__，Python 会使用 __repr__ 作为备选。\nclass Book: def __init__(self, title, author, pages): self.title = title self.author = author self.pages = pages def __str__(self): \u0026#34;\u0026#34;\u0026#34;返回用户友好的字符串表示\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;《{self.title}》 - {self.author}\u0026#34; book = Book(\u0026#34;活着\u0026#34;, \u0026#34;余华\u0026#34;, 500) print(book) # 《活着》 - 余华 print(str(book)) # 《活着》 - 余华 print(f\u0026#34;我正在读{book}\u0026#34;) # 我正在读《活着》 - 余华 repr 方法详解 __repr__ 方法在以下情况会被调用：\n在交互式解释器中直接输入对象并按回车时 在调试时显示对象信息 在某些日志输出中 如果没有定义 __str__，则 print() 也会调用 __repr__ __repr__ 方法应该返回一个字符串，该字符串理论上应该能够用于重新创建对象（即包含足够的重建信息）。如果一个类同时定义了 __str__ 和 __repr__，print() 和 str() 会优先使用 __str__。\nclass Point: def __init__(self, x, y): self.x = x self.y = y def __repr__(self): \u0026#34;\u0026#34;\u0026#34;返回开发者的字符串表示\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;Point(x={self.x}, y={self.y})\u0026#34; def __str__(self): \u0026#34;\u0026#34;\u0026#34;返回用户的字符串表示\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;({self.x}, {self.y})\u0026#34; p = Point(3, 4) print(repr(p)) # Point(x=3, y=4) print(str(p)) # (3, 4) print(p) # (3, 4) -- print 优先使用 __str__ 最佳实践：同时定义两个方法 为了提供最佳体验，建议同时定义 __str__ 和 __repr__ 方法。__repr__ 应该提供更详细的信息，让开发者能够精确了解对象的状态；__str__ 则提供更简洁友好的信息。\nclass Student: def __init__(self, name, student_id, major, grades=None): self.name = name self.student_id = student_id self.major = major self.grades = grades if grades else {} def __repr__(self): \u0026#34;\u0026#34;\u0026#34;开发者友好的表示，包含所有详细信息\u0026#34;\u0026#34;\u0026#34; return (f\u0026#34;Student(name={repr(self.name)}, \u0026#34; f\u0026#34;student_id={repr(self.student_id)}, \u0026#34; f\u0026#34;major={repr(self.major)}, \u0026#34; f\u0026#34;grades={repr(self.grades)})\u0026#34;) def __str__(self): \u0026#34;\u0026#34;\u0026#34;用户友好的表示\u0026#34;\u0026#34;\u0026#34; avg_grade = self.average() if self.grades else 0 return f\u0026#34;{self.name}（学号：{self.student_id}，专业：{self.major}，平均分：{avg_grade:.1f}）\u0026#34; def add_grade(self, subject, grade): self.grades[subject] = grade def average(self): if not self.grades: return 0 return sum(self.grades.values()) / len(self.grades) s = Student(\u0026#34;张三\u0026#34;, \u0026#34;2023001\u0026#34;, \u0026#34;计算机科学与技术\u0026#34;) s.add_grade(\u0026#34;数学\u0026#34;, 95) s.add_grade(\u0026#34;英语\u0026#34;, 88) s.add_grade(\u0026#34;编程\u0026#34;, 92) print(repr(s)) # Student(name=\u0026#39;张三\u0026#39;, student_id=\u0026#39;2023001\u0026#39;, major=\u0026#39;计算机科学与技术\u0026#39;, grades={\u0026#39;数学\u0026#39;: 95, \u0026#39;英语\u0026#39;: 88, \u0026#39;编程\u0026#39;: 92}) print(str(s)) # 张三（学号：2023001，专业：计算机科学与技术，平均分：91.7） del 析构器方法 __del__ 是 Python 中的析构器方法，当对象即将被销毁时（通常是引用计数降为零或程序退出时）会被调用。它的作用与 __init__ 相反——__init__ 用于初始化对象，而 __del__ 用于清理对象。\n需要注意的是，__del__ 并不等同于 C++ 中的析构函数。Python 有自己的垃圾回收机制，__del__ 的调用时机并不完全确定。在大多数情况下，你应该避免使用 __del__，除非确实需要在对象销毁时执行某些清理操作（如关闭文件、释放外部资源等）。\nclass FileHandler: def __init__(self, filename): self.filename = filename self.file = open(filename, \u0026#39;w\u0026#39;) print(f\u0026#34;文件 {filename} 已打开\u0026#34;) def write(self, content): self.file.write(content) def __del__(self): \u0026#34;\u0026#34;\u0026#34;关闭文件\u0026#34;\u0026#34;\u0026#34; if hasattr(self, \u0026#39;file\u0026#39;) and not self.file.closed: self.file.close() print(f\u0026#34;文件 {self.filename} 已关闭\u0026#34;) # 使用上下文管理器（with）更安全，后面的章节会讲到 handler = FileHandler(\u0026#34;test.txt\u0026#34;) handler.write(\u0026#34;Hello, World!\u0026#34;) # 当 handler 被删除时，__del__ 会被调用 引用计数与垃圾回收 Python 使用引用计数（Reference Counting）作为主要的内存管理机制。当一个对象的引用计数降为零时，对象会立即被销毁，__del__ 方法会被调用。然而，当存在循环引用时，引用计数无法检测到这些循环引用，Python 的垃圾回收器（Garbage Collector）会定期检测并清理这些循环引用的对象。\nimport gc class Node: def __init__(self, value): self.value = value self.next = None def __repr__(self): return f\u0026#34;Node({self.value})\u0026#34; def __del__(self): print(f\u0026#34;Node({self.value}) 被销毁\u0026#34;) # 创建循环引用 node1 = Node(1) node2 = Node(2) node3 = Node(3) node1.next = node2 node2.next = node3 node3.next = node1 # 形成循环引用：1 -\u0026gt; 2 -\u0026gt; 3 -\u0026gt; 1 print(\u0026#34;删除 node1...\u0026#34;) del node1 print(\u0026#34;删除 node2...\u0026#34;) del node2 print(\u0026#34;删除 node3...\u0026#34;) del node3 # 即使删除了所有引用，循环引用可能导致对象仍未被销毁 # 需要手动触发垃圾回收 print(\u0026#34;手动触发垃圾回收...\u0026#34;) gc.collect() print(\u0026#34;完成\u0026#34;) 使用 try\u0026hellip;finally 确保清理 虽然 __del__ 可以用于清理工作，但更可靠的方式是使用 try...finally 语句或上下文管理器（with 语句）。这样可以确保清理代码在任何情况下都会执行，即使发生异常也不例外。\nclass DatabaseConnection: def __init__(self, connection_string): self.connection_string = connection_string self.connected = False print(f\u0026#34;连接数据库：{connection_string}\u0026#34;) def connect(self): self.connected = True print(\u0026#34;数据库连接成功\u0026#34;) def query(self, sql): if not self.connected: raise RuntimeError(\u0026#34;请先连接数据库\u0026#34;) print(f\u0026#34;执行查询：{sql}\u0026#34;) def close(self): if self.connected: self.connected = False print(\u0026#34;数据库连接已关闭\u0026#34;) # 方法1：使用 try...finally db = DatabaseConnection(\u0026#34;mysql://localhost/testdb\u0026#34;) try: db.connect() db.query(\u0026#34;SELECT * FROM users\u0026#34;) finally: db.close() print(\u0026#34;---\u0026#34;) # 方法2：使用上下文管理器（推荐） class DatabaseConnection2: def __init__(self, connection_string): self.connection_string = connection_string self.connected = False def __enter__(self): print(f\u0026#34;连接数据库：{self.connection_string}\u0026#34;) self.connected = True return self def __exit__(self, exc_type, exc_val, exc_tb): if self.connected: print(\u0026#34;关闭数据库连接\u0026#34;) return False # 不吞没异常 def query(self, sql): print(f\u0026#34;执行查询：{sql}\u0026#34;) with DatabaseConnection2(\u0026#34;mysql://localhost/testdb\u0026#34;) as db: db.query(\u0026#34;SELECT * FROM users\u0026#34;) # with 块结束时自动调用 __exit__，确保连接被关闭 为什么应该避免 del __del__ 方法存在一些潜在问题：\n调用时机不确定：由于 Python 的垃圾回收机制，__del__ 的调用时机可能与预期不符。\n循环引用问题：如果对象之间存在循环引用，__del__ 可能不会被立即调用。\n异常风险：如果在 __del__ 执行期间发生异常，Python 会打印警告但不抛出异常。\n模块级变量问题：当程序退出时，某些 __del__ 可能根本不会被调用。\nimport warnings class Problematic: def __init__(self, name): self.name = name def __del__(self): # 警告：不要在 __del__ 中抛出异常 raise RuntimeError(f\u0026#34;在 {self.name} 的 __del__ 中发生错误\u0026#34;) # 这会导致警告而非异常 # obj = Problematic(\u0026#34;test\u0026#34;) # del obj # 会打印警告但不抛出异常 更好的替代方案：上下文管理器 对于需要清理资源的情况，Python 提供了上下文管理器（Context Manager）作为更优雅、更安全的解决方案。实现上下文管理器有两种方式：定义 __enter__ 和 __exit__ 方法，或者使用 @contextmanager 装饰器。\nclass FileManager: def __init__(self, filename, mode=\u0026#39;r\u0026#39;): self.filename = filename self.mode = mode self.file = None def __enter__(self): self.file = open(self.filename, self.mode) return self.file def __exit__(self, exc_type, exc_val, exc_tb): if self.file: self.file.close() return False # 不吞没异常 # 使用 with FileManager(\u0026#34;example.txt\u0026#34;, \u0026#34;w\u0026#34;) as f: f.write(\u0026#34;Hello, World!\u0026#34;) # 文件自动关闭，即使写入时发生异常也会正确关闭 使用 @contextmanager 装饰器 contextlib 模块提供了一个 @contextmanager 装饰器，可以更简洁地创建上下文管理器。\nfrom contextlib import contextmanager @contextmanager def managed_resource(name): print(f\u0026#34;获取资源：{name}\u0026#34;) resource = {\u0026#34;name\u0026#34;: name, \u0026#34;data\u0026#34;: []} try: yield resource # 返回要管理的对象 finally: print(f\u0026#34;释放资源：{name}\u0026#34;) with managed_resource(\u0026#34;数据库连接\u0026#34;) as res: res[\u0026#34;data\u0026#34;].append(\u0026#34;some data\u0026#34;) print(f\u0026#34;使用 {res[\u0026#39;name\u0026#39;]} 中...\u0026#34;) # 资源自动释放 字符串方法的组合使用 在实际应用中，__str__ 和 __repr__ 通常会与其他字符串方法组合使用，以提供更丰富的功能。\nclass Vector: def __init__(self, x, y, z): self.x = x self.y = y self.z = z def __repr__(self): return f\u0026#34;Vector({self.x}, {self.y}, {self.z})\u0026#34; def __str__(self): return f\u0026#34;向量({self.x}, {self.y}, {self.z})，模长：{self.magnitude():.2f}\u0026#34; def magnitude(self): return (self.x**2 + self.y**2 + self.z**2) ** 0.5 def __format__(self, format_spec): \u0026#34;\u0026#34;\u0026#34;支持自定义格式化\u0026#34;\u0026#34;\u0026#34; if format_spec == \u0026#34;short\u0026#34;: return f\u0026#34;({self.x}, {self.y}, {self.z})\u0026#34; elif format_spec == \u0026#34;detailed\u0026#34;: return f\u0026#34;Vector(x={self.x}, y={self.y}, z={self.z}, |v|={self.magnitude():.4f})\u0026#34; return str(self) v = Vector(3, 4, 5) print(repr(v)) # Vector(3, 4, 5) print(str(v)) # 向量(3, 4, 5)，模长：7.07 print(format(v, \u0026#34;short\u0026#34;)) # (3, 4, 5) print(format(v, \u0026#34;detailed\u0026#34;)) # Vector(x=3, y=4, z=5, |v|=7.0711) bool 方法 除了 __str__ 和 __repr__，还有一个相关的魔术方法 __bool__，它用于定义对象的布尔值。在 if 语句或 bool() 函数中需要布尔值时，会调用对象的 __bool__ 方法（如果未定义，则使用 __len__，如果也没有，则默认为 True）。\nclass EmptyList: def __init__(self, items=None): self.items = items if items else [] def __bool__(self): \u0026#34;\u0026#34;\u0026#34;定义对象的布尔值\u0026#34;\u0026#34;\u0026#34; return len(self.items) \u0026gt; 0 lst = EmptyList([]) print(bool(lst)) # False（因为 items 为空） lst.items.append(1) print(bool(lst)) # True（因为 items 不为空） hash 与 eq 如果一个类定义了 __eq__ 方法（用于比较两个对象是否相等），但没有定义 __hash__ 方法，那么这个类的实例将变成不可哈希的（unhashable），不能用作字典的键或集合的元素。\nclass Person: def __init__(self, name, age): self.name = name self.age = age def __repr__(self): return f\u0026#34;Person(name={self.name}, age={self.age})\u0026#34; def __eq__(self, other): if isinstance(other, Person): return self.name == other.name and self.age == other.age return False def __hash__(self): \u0026#34;\u0026#34;\u0026#34;定义哈希值，使得相等的对象有相同的哈希值\u0026#34;\u0026#34;\u0026#34; return hash((self.name, self.age)) p1 = Person(\u0026#34;张三\u0026#34;, 25) p2 = Person(\u0026#34;张三\u0026#34;, 25) p3 = Person(\u0026#34;李四\u0026#34;, 25) print(p1 == p2) # True（内容相等） print(p1 == p3) # False print(hash(p1) == hash(p2)) # True（相等的对象哈希值相同） # 可以用作字典的键或集合的元素 people_set = {p1, p2, p3} print(len(people_set)) # 2（p1 和 p2 相等，只保留一个） 练习题 练习 1：实现有理数的字符串表示 from math import gcd class Rational: def __init__(self, numerator, denominator=1): if denominator == 0: raise ValueError(\u0026#34;分母不能为零\u0026#34;) g = gcd(abs(numerator), abs(denominator)) self.numerator = numerator // g self.denominator = denominator // g if self.denominator \u0026lt; 0: self.numerator = -self.numerator self.denominator = -self.denominator def __repr__(self): return f\u0026#34;Rational({self.numerator}, {self.denominator})\u0026#34; def __str__(self): if self.denominator == 1: return str(self.numerator) return f\u0026#34;{self.numerator}/{self.denominator}\u0026#34; def __add__(self, other): if isinstance(other, int): other = Rational(other) if not isinstance(other, Rational): return NotImplemented num = self.numerator * other.denominator + other.numerator * self.denominator den = self.denominator * other.denominator return Rational(num, den) def __eq__(self, other): if isinstance(other, int): other = Rational(other) if not isinstance(other, Rational): return False return self.numerator == other.numerator and self.denominator == other.denominator # 测试 r1 = Rational(1, 2) r2 = Rational(2, 4) r3 = Rational(3) print(repr(r1)) # Rational(1, 2) print(str(r1)) # 1/2 print(r1 == r2) # True（约分后相等） print(r1 + r3) # 7/2 练习 2：实现简单的栈类 class Stack: def __init__(self): self._items = [] def push(self, item): self._items.append(item) def pop(self): if not self._items: raise IndexError(\u0026#34;栈为空\u0026#34;) return self._items.pop() def peek(self): if not self._items: raise IndexError(\u0026#34;栈为空\u0026#34;) return self._items[-1] def __len__(self): return len(self._items) def __bool__(self): return len(self._items) \u0026gt; 0 def __repr__(self): return f\u0026#34;Stack({self._items!r})\u0026#34; def __str__(self): if not self._items: return \u0026#34;Stack: [] (空)\u0026#34; return \u0026#34;Stack: [\u0026#34; + \u0026#34; → \u0026#34;.join(str(x) for x in self._items) + \u0026#34;]\u0026#34; s = Stack() print(s) # Stack: [] (空) print(bool(s)) # False s.push(1) s.push(2) s.push(3) print(s) # Stack: [1 → 2 → 3] print(len(s)) # 3 print(s.peek()) # 3 练习 3：实现配置类 class Config: def __init__(self, **kwargs): self._settings = {} for key, value in kwargs.items(): self._settings[key] = value def __repr__(self): return f\u0026#34;Config({self._settings!r})\u0026#34; def __str__(self): if not self._settings: return \u0026#34;Config: (空)\u0026#34; lines = [\u0026#34;Config:\u0026#34;] for key, value in self._settings.items(): lines.append(f\u0026#34; {key} = {value!r}\u0026#34;) return \u0026#34;\\n\u0026#34;.join(lines) def __getitem__(self, key): return self._settings[key] def __setitem__(self, key, value): self._settings[key] = value def __contains__(self, key): return key in self._settings def get(self, key, default=None): return self._settings.get(key, default) # 测试 config = Config( db_host=\u0026#34;localhost\u0026#34;, db_port=3306, db_name=\u0026#34;testdb\u0026#34;, debug=True ) print(str(config)) # Config: # db_host = \u0026#39;localhost\u0026#39; # db_port = 3306 # db_name = \u0026#39;testdb\u0026#39; # debug = True print(\u0026#34;db_host\u0026#34; in config) # True print(config[\u0026#34;db_port\u0026#34;]) # 3306 config[\u0026#34;timeout\u0026#34;] = 30 print(config.get(\u0026#34;nonexistent\u0026#34;, \u0026#34;default\u0026#34;)) # default 总结 今天我们学习了 Python 中与对象字符串表示和生命周期相关的重要概念：\n__str__：用户友好的字符串表示，用于 print() 和 str() 函数 __repr__：开发者友好的字符串表示，应能表示重建对象所需的信息 __del__：析构器方法，在对象销毁前调用，但应该尽量避免使用 __bool__：定义对象的布尔值 __hash__ 和 __eq__：定义对象的哈希值和相等性比较 最佳实践建议：\n同时定义 __repr__ 和 __str__ 以提供不同层级的信息 避免在 __del__ 中抛出异常或执行复杂操作 对于资源清理，使用上下文管理器（with 语句）比 __del__ 更安全可靠 使用 @contextmanager 装饰器可以更简洁地创建上下文管理器 在下一节中，我们将学习私有属性和封装（数据隐藏）的概念。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-23-str-del/","summary":"\u003ch1 id=\"day-23---字符串表示-str-与-del\"\u003eDay 23 - 字符串表示 \u003cstrong\u003estr\u003c/strong\u003e 与 \u003cstrong\u003edel\u003c/strong\u003e\u003c/h1\u003e\n\u003ch2 id=\"对象的字符串表示概述\"\u003e对象的字符串表示概述\u003c/h2\u003e\n\u003cp\u003e在 Python 中，每个对象都可以被转换为字符串。当你使用 \u003ccode\u003eprint()\u003c/code\u003e 函数打印一个对象，或者在某些需要字符串的地方使用对象时，Python 需要将对象转换为字符串。默认的实现通常显示的是类似 \u003ccode\u003e\u0026lt;__main__.ClassName object at 0x7f8a9c123456\u0026gt;\u003c/code\u003e 这样的信息，虽然包含了对象的内存地址，但对于人类阅读来说并不友好。\u003c/p\u003e\n\u003cp\u003e为了提供更有意义的字符串表示，Python 提供了两个魔术方法：\u003ccode\u003e__str__\u003c/code\u003e 和 \u003ccode\u003e__repr__\u003c/code\u003e。通过在类中重写这两个方法，你可以自定义对象的字符串表现形式，使输出更加友好和有意义。\u003c/p\u003e\n\u003cp\u003e这两个方法的区别在于：\u003ccode\u003e__str__\u003c/code\u003e 是面向用户的字符串表示，用于给终端用户查看；而 \u003ccode\u003e__repr__\u003c/code\u003e 是面向开发者的字符串表示，应该尽可能提供详细的信息，以便开发者调试。\u003c/p\u003e\n\u003ch2 id=\"str-方法详解\"\u003e\u003cstrong\u003estr\u003c/strong\u003e 方法详解\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003e__str__\u003c/code\u003e 方法在以下情况会被调用：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e使用 \u003ccode\u003eprint()\u003c/code\u003e 函数打印对象时\u003c/li\u003e\n\u003cli\u003e使用 \u003ccode\u003estr()\u003c/code\u003e 函数转换对象时\u003c/li\u003e\n\u003cli\u003e在需要字符串的地方使用 f-string 格式化对象时\u003c/li\u003e\n\u003cli\u003e用户友好的错误消息中\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003ccode\u003e__str__\u003c/code\u003e 方法应该返回一个字符串。如果没有定义 \u003ccode\u003e__str__\u003c/code\u003e，Python 会使用 \u003ccode\u003e__repr__\u003c/code\u003e 作为备选。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eBook\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e __init__(self, title, author, pages):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003etitle \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e title\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eauthor \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e author\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epages \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e pages\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e __str__(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;返回用户友好的字符串表示\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;《\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003etitle\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e》 - \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eauthor\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebook \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Book(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;活着\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;余华\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e500\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(book)           \u003cspan style=\"color:#75715e\"\u003e# 《活着》 - 余华\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(str(book))      \u003cspan style=\"color:#75715e\"\u003e# 《活着》 - 余华\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;我正在读\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ebook\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 我正在读《活着》 - 余华\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"repr-方法详解\"\u003e\u003cstrong\u003erepr\u003c/strong\u003e 方法详解\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003e__repr__\u003c/code\u003e 方法在以下情况会被调用：\u003c/p\u003e","tags":"Python, 编程","title":"Day 23 - 字符串表示 __str__ 与 __del__"},{"columns":"python-course","content":"Day 24 - 私有属性与封装 什么是封装？ 封装（Encapsulation）是面向对象编程的三大基本特性之一（另外两个是继承和多态）。封装的核心理念是将数据（属性）和操作数据的方法（行为）打包在一起，对外隐藏内部实现细节，只暴露必要的接口。这样做的好处是：提高代码的可维护性、降低模块间的耦合度、保护数据不被意外或恶意修改。\n在 Python 中，封装并不是像 Java 或 C++ 那样通过严格的访问控制关键字（public、private、protected）来实现的。Python 采用了一种\u0026quot;约定优于配置\u0026quot;的方式，通过命名规范来标识成员的访问级别。\nPython 的命名规范 Python 中以下划线的前缀和数量来表示属性的访问级别：\n_name（单下划线）：受保护的属性，按照约定，外部代码不应该直接访问，但 Python 不会阻止这种访问。这是一种\u0026quot;软私有\u0026quot;的约定。\n__name（双下划线开头）：名称改写（Name Mangling）机制，会将属性名改写为 _类名__name 的形式。这提供了一定程度的\u0026quot;硬私有\u0026quot;保护，但通过改写后的名称仍然可以访问。\n__name__（双下划线开头和结尾）：这是魔术方法/属性的保留命名空间，如 __init__、__str__、__dict__ 等。普通属性不应该使用这种命名方式。\nclass BankAccount: def __init__(self, account_id, initial_balance): self.account_id = account_id # 公开属性 self._transactions = [] # 受保护属性（约定不直接访问） self.__balance = initial_balance # 私有属性（名称改写） def deposit(self, amount): if amount \u0026lt;= 0: raise ValueError(\u0026#34;存款金额必须为正数\u0026#34;) self.__balance += amount self._transactions.append((\u0026#34;存款\u0026#34;, amount)) def withdraw(self, amount): if amount \u0026lt;= 0: raise ValueError(\u0026#34;取款金额必须为正数\u0026#34;) if amount \u0026gt; self.__balance: raise ValueError(\u0026#34;余额不足\u0026#34;) self.__balance -= amount self._transactions.append((\u0026#34;取款\u0026#34;, -amount)) def get_balance(self): \u0026#34;\u0026#34;\u0026#34;获取余额（受控访问）\u0026#34;\u0026#34;\u0026#34; return self.__balance def get_transactions(self): \u0026#34;\u0026#34;\u0026#34;获取交易记录\u0026#34;\u0026#34;\u0026#34; return self._transactions.copy() # 创建账户 account = BankAccount(\u0026#34;ACC001\u0026#34;, 1000) # 公开属性可以直接访问 print(f\u0026#34;账号：{account.account_id}\u0026#34;) # 受保护属性（可以访问，但不推荐） print(f\u0026#34;交易记录：{account._transactions}\u0026#34;) # 私有属性（访问会报错） # print(account.__balance) # AttributeError # 但可以通过改写后的名称访问（不推荐） print(account._BankAccount__balance) # 1000 # 通过方法访问私有属性（推荐方式） print(f\u0026#34;余额：{account.get_balance()}\u0026#34;) # 存款和取款 account.deposit(500) account.withdraw(200) print(f\u0026#34;交易记录：{account.get_transactions()}\u0026#34;) # [(\u0026#39;存款\u0026#39;, 500), (\u0026#39;取款\u0026#39;, -200)] 为什么要使用私有属性？ 假设我们有一个 BankAccount 类，余额是一个私有属性。如果允许外部代码直接访问和修改余额，那么可能会出现以下问题：\n数据不一致：余额可能被修改成负数 业务逻辑被绕过：取款时没有检查余额是否充足 无法追踪变更：直接修改余额时无法记录交易历史 通过将余额设为私有属性，并提供 deposit、withdraw、get_balance 等公共方法，我们可以确保所有对余额的修改都经过适当的验证和记录。\n# 危险的代码：直接暴露余额 class UnsafeBankAccount: def __init__(self, balance): self.balance = balance # 余额是公开的，可以被随意修改 # 可能造成的问题 account = UnsafeBankAccount(1000) account.balance = -5000 # 余额变成负数（不合理） account.balance = \u0026#34;一千元\u0026#34; # 类型错误 属性访问器（Getter 和 Setter） 在 Java 等语言中，通常使用 getter 和 setter 方法来访问和修改属性。Python 也能这样做，但这不是 Pythonic（符合 Python 风格）的方式。不过，有些情况下使用 getter 和 setter 确实很有用，例如：\n在获取或设置属性时执行额外的逻辑 提供只读或只写的属性 实现计算属性（computed properties） class Temperature: def __init__(self, celsius=0): self._celsius = celsius def get_celsius(self): \u0026#34;\u0026#34;\u0026#34;获取摄氏温度\u0026#34;\u0026#34;\u0026#34; return self._celsius def set_celsius(self, value): \u0026#34;\u0026#34;\u0026#34;设置摄氏温度\u0026#34;\u0026#34;\u0026#34; if value \u0026lt; -273.15: raise ValueError(\u0026#34;温度不能低于绝对零度\u0026#34;) self._celsius = value # 使用 property 函数创建属性 celsius = property(get_celsius, set_celsius) @property def fahrenheit(self): \u0026#34;\u0026#34;\u0026#34;计算属性：华氏温度\u0026#34;\u0026#34;\u0026#34; return self._celsius * 9/5 + 32 @fahrenheit.setter def fahrenheit(self, value): \u0026#34;\u0026#34;\u0026#34;设置华氏温度\u0026#34;\u0026#34;\u0026#34; self._celsius = (value - 32) * 5/9 # 使用 temp = Temperature(25) print(f\u0026#34;摄氏温度：{temp.celsius}°C\u0026#34;) # 25°C print(f\u0026#34;华氏温度：{temp.fahrenheit}°F\u0026#34;) # 77.0°F temp.celsius = 30 print(f\u0026#34;摄氏温度：{temp.celsius}°C\u0026#34;) # 30°C print(f\u0026#34;华氏温度：{temp.fahrenheit}°F\u0026#34;) # 86.0°F temp.fahrenheit = 68 print(f\u0026#34;摄氏温度：{temp.celsius}°C\u0026#34;) # 20°C print(f\u0026#34;华氏温度：{temp.fahrenheit}°F\u0026#34;) # 68.0°F # 验证绝对零度 try: temp.celsius = -300 # 抛出异常 except ValueError as e: print(f\u0026#34;错误：{e}\u0026#34;) # 温度不能低于绝对零度 @property 装饰器 Python 提供了一个更优雅的方式来创建属性访问器：@property 装饰器。使用 @property 装饰器可以将类方法转换为同名属性的 getter 方法，代码更简洁、更符合 Python 风格。\nclass Circle: def __init__(self, radius): self.radius = radius # 这会调用 setter @property def radius(self): \u0026#34;\u0026#34;\u0026#34;获取半径\u0026#34;\u0026#34;\u0026#34; return self._radius @radius.setter def radius(self, value): \u0026#34;\u0026#34;\u0026#34;设置半径（带验证）\u0026#34;\u0026#34;\u0026#34; if value \u0026lt;= 0: raise ValueError(\u0026#34;半径必须为正数\u0026#34;) self._radius = value @property def diameter(self): \u0026#34;\u0026#34;\u0026#34;计算属性：直径\u0026#34;\u0026#34;\u0026#34; return self._radius * 2 @property def area(self): \u0026#34;\u0026#34;\u0026#34;计算属性：面积\u0026#34;\u0026#34;\u0026#34; import math return math.pi * self._radius ** 2 @property def circumference(self): \u0026#34;\u0026#34;\u0026#34;计算属性：周长\u0026#34;\u0026#34;\u0026#34; import math return 2 * math.pi * self._radius # 使用 circle = Circle(5) print(f\u0026#34;半径：{circle.radius}\u0026#34;) # 5 print(f\u0026#34;直径：{circle.diameter}\u0026#34;) # 10 print(f\u0026#34;面积：{circle.area:.2f}\u0026#34;) # 78.54 print(f\u0026#34;周长：{circle.circumference:.2f}\u0026#34;) # 31.42 circle.radius = 10 print(f\u0026#34;新半径：{circle.radius}\u0026#34;) # 10 print(f\u0026#34;新面积：{circle.area:.2f}\u0026#34;) # 314.16 try: circle.radius = -5 # 抛出异常 except ValueError as e: print(f\u0026#34;错误：{e}\u0026#34;) # 半径必须为正数 只读属性 通过只定义 getter 而不定义 setter，可以创建只读属性。\nclass Person: def __init__(self, name, birth_year): self.name = name self._birth_year = birth_year @property def name(self): \u0026#34;\u0026#34;\u0026#34;姓名（可读写）\u0026#34;\u0026#34;\u0026#34; return self._name @name.setter def name(self, value): if not value: raise ValueError(\u0026#34;姓名不能为空\u0026#34;) self._name = value @property def birth_year(self): \u0026#34;\u0026#34;\u0026#34;出生年份（只读）\u0026#34;\u0026#34;\u0026#34; return self._birth_year @property def age(self): \u0026#34;\u0026#34;\u0026#34;年龄（只读计算属性）\u0026#34;\u0026#34;\u0026#34; import datetime current_year = datetime.datetime.now().year return current_year - self._birth_year # 使用 person = Person(\u0026#34;张三\u0026#34;, 1990) print(f\u0026#34;姓名：{person.name}\u0026#34;) # 张三 print(f\u0026#34;出生年份：{person.birth_year}\u0026#34;) # 1990 print(f\u0026#34;年龄：{person.age}\u0026#34;) # 33 或 34（取决于当前年份） person.name = \u0026#34;李四\u0026#34; # 可以修改 print(f\u0026#34;新姓名：{person.name}\u0026#34;) # 李四 # person.birth_year = 1995 # AttributeError: property \u0026#39;birth_year\u0026#39; has no setter 受保护属性的使用场景 受保护属性（单下划线前缀）通常用于\u0026quot;子类可以使用，但外部代码不应直接访问\u0026quot;的场景。这是一种设计决策，表示该属性是类的内部实现细节，可能会在未来的版本中发生变化。\nclass Animal: def __init__(self, name, age): self.name = name self._age = age # 受保护，子类可以使用 def speak(self): raise NotImplementedError(\u0026#34;子类必须实现 speak 方法\u0026#34;) def _display_info(self): # 受保护的方法 \u0026#34;\u0026#34;\u0026#34;子类可以调用这个方法\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;动物：{self.name}，年龄：{self._age}\u0026#34;) class Dog(Animal): def __init__(self, name, age, breed): super().__init__(name, age) self._breed = breed # 子类的受保护属性 def speak(self): print(f\u0026#34;{self.name} 在叫：汪汪汪！\u0026#34;) def display(self): self._display_info() # 调用父类的受保护方法 print(f\u0026#34;品种：{self._breed}\u0026#34;) # 使用 dog = Dog(\u0026#34;旺财\u0026#34;, 3, \u0026#34;金毛\u0026#34;) dog.speak() # 旺财 在叫：汪汪汪！ dog.display() # 动物：旺财，年龄：3 # 品种：金毛 # 外部代码可以直接访问受保护属性（不推荐） print(f\u0026#34;年龄：{dog._age}\u0026#34;) 私有属性的继承与访问 私有属性（双下划线前缀）使用了名称改写机制，在子类中也无法直接通过原名称访问，但可以通过改写后的名称访问。这种设计提供了一定程度的保护。\nclass Base: def __init__(self): self.__secret = 42 # 私有属性，改写为 _Base__secret def get_secret(self): return self.__secret # 类内部可以访问 class Derived(Base): def __init__(self): super().__init__() self.__another = 100 # 私有属性，改写为 _Derived__another def access_base_secret(self): # 可以通过方法访问父类的私有属性 return self.get_secret() def get_own_secret(self): return self.__another # 可以访问自己的私有属性 obj = Derived() print(obj.access_base_secret()) # 42 print(obj.get_own_secret()) # 100 # 无法直接访问私有属性 # print(obj.__secret) # AttributeError # print(obj.__another) # AttributeError # 但可以通过改写后的名称访问（不推荐） print(obj._Base__secret) # 42 print(obj._Derived__another) # 100 封装与接口设计 良好的封装不仅仅是将属性设为私有，更重要的是设计清晰的公共接口。公共接口应该：\n最小化：只暴露必要的方法 一致性：相似的方法应有相似的行为模式 稳定性：公共接口应该在版本升级时保持兼容 自文档化：方法名应清晰表达其功能 class Stack: \u0026#34;\u0026#34;\u0026#34;栈数据结构\u0026#34;\u0026#34;\u0026#34; def __init__(self): self._items = [] def push(self, item): \u0026#34;\u0026#34;\u0026#34;入栈\u0026#34;\u0026#34;\u0026#34; self._items.append(item) def pop(self): \u0026#34;\u0026#34;\u0026#34;出栈\u0026#34;\u0026#34;\u0026#34; if self.is_empty(): raise IndexError(\u0026#34;栈为空\u0026#34;) return self._items.pop() def peek(self): \u0026#34;\u0026#34;\u0026#34;查看栈顶元素（不出栈）\u0026#34;\u0026#34;\u0026#34; if self.is_empty(): raise IndexError(\u0026#34;栈为空\u0026#34;) return self._items[-1] def is_empty(self): \u0026#34;\u0026#34;\u0026#34;判断栈是否为空\u0026#34;\u0026#34;\u0026#34; return len(self._items) == 0 def size(self): \u0026#34;\u0026#34;\u0026#34;获取栈的大小\u0026#34;\u0026#34;\u0026#34; return len(self._items) def __len__(self): return len(self._items) def __bool__(self): return not self.is_empty() # 公共接口：push, pop, peek, is_empty, size, __len__, __bool__ # 私有实现：_items # 外部代码不应该直接访问 _items 使用 slots 限制属性 Python 允许使用 __slots__ 来限制类可以拥有的属性。这可以节省内存，并防止动态添加新属性。\nclass Point: __slots__ = (\u0026#39;_x\u0026#39;, \u0026#39;_y\u0026#39;) def __init__(self, x, y): self._x = x self._y = y @property def x(self): return self._x @property def y(self): return self._y def __repr__(self): return f\u0026#34;Point({self._x}, {self._y})\u0026#34; p = Point(1, 2) print(p) # Point(1, 2) print(p.x, p.y) # 1 2 # 尝试添加新属性会失败 # p.z = 3 # AttributeError: \u0026#39;Point\u0026#39; object has no attribute \u0026#39;z\u0026#39; # 尝试动态添加也会失败 # Point.name = \u0026#34;test\u0026#34; # 这会影响类，但不影响已有实例 练习题 练习 1：实现银行账户类（完整版） class Account: \u0026#34;\u0026#34;\u0026#34;银行账户类\u0026#34;\u0026#34;\u0026#34; def __init__(self, account_id, owner_name, initial_balance=0): self._account_id = account_id self._owner_name = owner_name self.__balance = initial_balance # 私有属性 self._transactions = [] # 受保护的交易记录 self._frozen = False # 账户是否被冻结 @property def account_id(self): \u0026#34;\u0026#34;\u0026#34;账号（只读）\u0026#34;\u0026#34;\u0026#34; return self._account_id @property def owner_name(self): \u0026#34;\u0026#34;\u0026#34;户主姓名\u0026#34;\u0026#34;\u0026#34; return self._owner_name @owner_name.setter def owner_name(self, value): if not value or not value.strip(): raise ValueError(\u0026#34;姓名不能为空\u0026#34;) self._owner_name = value.strip() @property def balance(self): \u0026#34;\u0026#34;\u0026#34;余额（只读）\u0026#34;\u0026#34;\u0026#34; return self.__balance @property def frozen(self): \u0026#34;\u0026#34;\u0026#34;账户是否冻结\u0026#34;\u0026#34;\u0026#34; return self._frozen def _add_transaction(self, transaction_type, amount, description=\u0026#34;\u0026#34;): \u0026#34;\u0026#34;\u0026#34;添加交易记录（内部方法）\u0026#34;\u0026#34;\u0026#34; self._transactions.append({ \u0026#34;类型\u0026#34;: transaction_type, \u0026#34;金额\u0026#34;: amount, \u0026#34;描述\u0026#34;: description }) def deposit(self, amount, description=\u0026#34;\u0026#34;): \u0026#34;\u0026#34;\u0026#34;存款\u0026#34;\u0026#34;\u0026#34; if self._frozen: raise RuntimeError(\u0026#34;账户已被冻结，无法操作\u0026#34;) if amount \u0026lt;= 0: raise ValueError(\u0026#34;存款金额必须为正数\u0026#34;) self.__balance += amount self._add_transaction(\u0026#34;存款\u0026#34;, amount, description) return True def withdraw(self, amount, description=\u0026#34;\u0026#34;): \u0026#34;\u0026#34;\u0026#34;取款\u0026#34;\u0026#34;\u0026#34; if self._frozen: raise RuntimeError(\u0026#34;账户已被冻结，无法操作\u0026#34;) if amount \u0026lt;= 0: raise ValueError(\u0026#34;取款金额必须为正数\u0026#34;) if amount \u0026gt; self.__balance: raise ValueError(\u0026#34;余额不足\u0026#34;) self.__balance -= amount self._add_transaction(\u0026#34;取款\u0026#34;, -amount, description) return True def transfer(self, target_account, amount): \u0026#34;\u0026#34;\u0026#34;转账\u0026#34;\u0026#34;\u0026#34; if self._frozen: raise RuntimeError(\u0026#34;账户已被冻结，无法操作\u0026#34;) if amount \u0026lt;= 0: raise ValueError(\u0026#34;转账金额必须为正数\u0026#34;) if amount \u0026gt; self.__balance: raise ValueError(\u0026#34;余额不足\u0026#34;) self.__balance -= amount target_account.__balance += amount # 注意：这是直接访问，真实场景需要通过方法 self._add_transaction(\u0026#34;转出\u0026#34;, -amount, f\u0026#34;转账至{target_account._account_id}\u0026#34;) target_account._add_transaction(\u0026#34;转入\u0026#34;, amount, f\u0026#34;转账自{self._account_id}\u0026#34;) return True def freeze(self): \u0026#34;\u0026#34;\u0026#34;冻结账户\u0026#34;\u0026#34;\u0026#34; self._frozen = True def unfreeze(self): \u0026#34;\u0026#34;\u0026#34;解冻账户\u0026#34;\u0026#34;\u0026#34; self._frozen = False def get_transactions(self): \u0026#34;\u0026#34;\u0026#34;获取交易记录\u0026#34;\u0026#34;\u0026#34; return self._transactions.copy() def __repr__(self): status = \u0026#34;已冻结\u0026#34; if self._frozen else \u0026#34;正常\u0026#34; return f\u0026#34;Account({self._account_id}, {self._owner_name}, 余额={self.__balance}, 状态={status})\u0026#34; # 测试 acc1 = Account(\u0026#34;ACC001\u0026#34;, \u0026#34;张三\u0026#34;, 10000) acc2 = Account(\u0026#34;ACC002\u0026#34;, \u0026#34;李四\u0026#34;, 5000) acc1.deposit(2000, \u0026#34;工资\u0026#34;) acc1.withdraw(500, \u0026#34;购物\u0026#34;) acc1.transfer(acc2, 3000, \u0026#34;借款\u0026#34;) print(acc1) print(acc2) print(\u0026#34;\\n张三的交易记录：\u0026#34;) for t in acc1.get_transactions(): print(f\u0026#34; {t}\u0026#34;) print(\u0026#34;\\n李四的交易记录：\u0026#34;) for t in acc2.get_transactions(): print(f\u0026#34; {t}\u0026#34;) 练习 2：实现带验证的列表类 class ValidatedList: \u0026#34;\u0026#34;\u0026#34;带验证的列表，只能包含指定类型的元素\u0026#34;\u0026#34;\u0026#34; def __init__(self, item_type): self._item_type = item_type self._items = [] def __len__(self): return len(self._items) def __getitem__(self, index): return self._items[index] def __iter__(self): return iter(self._items) def __repr__(self): return f\u0026#34;ValidatedList({self._item_type.__name__})({self._items!r})\u0026#34; def __str__(self): return str(self._items) def append(self, item): if not isinstance(item, self._item_type): raise TypeError(f\u0026#34;期望 {self._item_type.__name__} 类型，得到 {type(item).__name__}\u0026#34;) self._items.append(item) def insert(self, index, item): if not isinstance(item, self._item_type): raise TypeError(f\u0026#34;期望 {self._item_type.__name__} 类型，得到 {type(item).__name__}\u0026#34;) self._items.insert(index, item) def pop(self, index=-1): return self._items.pop(index) # 测试 int_list = ValidatedList(int) int_list.append(1) int_list.append(2) int_list.append(3) print(int_list) # [1, 2, 3] try: int_list.append(\u0026#34;字符串\u0026#34;) # TypeError except TypeError as e: print(f\u0026#34;错误：{e}\u0026#34;) str_list = ValidatedList(str) str_list.append(\u0026#34;hello\u0026#34;) str_list.append(\u0026#34;world\u0026#34;) print(str_list) # [\u0026#39;hello\u0026#39;, \u0026#39;world\u0026#39;] 练习 3：实现只读的属性集合 class ReadOnlyDict: \u0026#34;\u0026#34;\u0026#34;只读字典\u0026#34;\u0026#34;\u0026#34; def __init__(self, **kwargs): self._data = dict(kwargs) def __getitem__(self, key): return self._data[key] def __len__(self): return len(self._data) def __iter__(self): return iter(self._data) def __contains__(self, key): return key in self._data def get(self, key, default=None): return self._data.get(key, default) def keys(self): return self._data.keys() def values(self): return self._data.values() def items(self): return self._data.items() def __repr__(self): return f\u0026#34;ReadOnlyDict({self._data!r})\u0026#34; # 禁止修改操作 def __setitem__(self, key, value): raise TypeError(\u0026#34;只读字典不支持写操作\u0026#34;) def __delitem__(self, key): raise TypeError(\u0026#34;只读字典不支持删除操作\u0026#34;) def clear(self): raise TypeError(\u0026#34;只读字典不支持清空操作\u0026#34;) def pop(self, *args): raise TypeError(\u0026#34;只读字典不支持 pop 操作\u0026#34;) def update(self, *args, **kwargs): raise TypeError(\u0026#34;只读字典不支持更新操作\u0026#34;) # 测试 config = ReadOnlyDict(host=\u0026#34;localhost\u0026#34;, port=3306, debug=True) print(config) print(f\u0026#34;host = {config[\u0026#39;host\u0026#39;]}\u0026#34;) print(f\u0026#34;debug = {config.get(\u0026#39;debug\u0026#39;)}\u0026#34;) print(f\u0026#34;nonexistent = {config.get(\u0026#39;nonexistent\u0026#39;, \u0026#39;default\u0026#39;)}\u0026#34;) try: config[\u0026#34;host\u0026#34;] = \u0026#34;remote\u0026#34; # TypeError except TypeError as e: print(f\u0026#34;错误：{e}\u0026#34;) 总结 今天我们学习了 Python 中封装的概念和实现方式：\n命名约定：\n_name：受保护属性，约定不直接外部访问 __name：私有属性，使用名称改写机制 name_：避免与 Python 关键字冲突的命名方式 @property 装饰器：\n创建属性访问器的 Pythonic 方式 可以创建计算属性（只读属性） 可以同时定义 getter、setter、deleter 封装的好处：\n保护数据不被意外或恶意修改 在访问和修改属性时执行验证逻辑 提供清晰的公共接口，隐藏内部实现细节 提高代码的可维护性和可扩展性 __slots__：\n限制类可以拥有的属性 节省内存 防止动态添加新属性 掌握封装是编写高质量面向对象代码的基础。在后续的学习中，我们将学习继承和派生类的概念。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-24-private-encapsulation/","summary":"\u003ch1 id=\"day-24---私有属性与封装\"\u003eDay 24 - 私有属性与封装\u003c/h1\u003e\n\u003ch2 id=\"什么是封装\"\u003e什么是封装？\u003c/h2\u003e\n\u003cp\u003e封装（Encapsulation）是面向对象编程的三大基本特性之一（另外两个是继承和多态）。封装的核心理念是将数据（属性）和操作数据的方法（行为）打包在一起，对外隐藏内部实现细节，只暴露必要的接口。这样做的好处是：提高代码的可维护性、降低模块间的耦合度、保护数据不被意外或恶意修改。\u003c/p\u003e\n\u003cp\u003e在 Python 中，封装并不是像 Java 或 C++ 那样通过严格的访问控制关键字（public、private、protected）来实现的。Python 采用了一种\u0026quot;约定优于配置\u0026quot;的方式，通过命名规范来标识成员的访问级别。\u003c/p\u003e\n\u003ch2 id=\"python-的命名规范\"\u003ePython 的命名规范\u003c/h2\u003e\n\u003cp\u003ePython 中以下划线的前缀和数量来表示属性的访问级别：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e_name\u003c/code\u003e\u003c/strong\u003e（单下划线）：受保护的属性，按照约定，外部代码不应该直接访问，但 Python 不会阻止这种访问。这是一种\u0026quot;软私有\u0026quot;的约定。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e__name\u003c/code\u003e\u003c/strong\u003e（双下划线开头）：名称改写（Name Mangling）机制，会将属性名改写为 \u003ccode\u003e_类名__name\u003c/code\u003e 的形式。这提供了一定程度的\u0026quot;硬私有\u0026quot;保护，但通过改写后的名称仍然可以访问。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e__name__\u003c/code\u003e\u003c/strong\u003e（双下划线开头和结尾）：这是魔术方法/属性的保留命名空间，如 \u003ccode\u003e__init__\u003c/code\u003e、\u003ccode\u003e__str__\u003c/code\u003e、\u003ccode\u003e__dict__\u003c/code\u003e 等。普通属性不应该使用这种命名方式。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eBankAccount\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e __init__(self, account_id, initial_balance):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eaccount_id \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e account_id      \u003cspan style=\"color:#75715e\"\u003e# 公开属性\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e_transactions \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []            \u003cspan style=\"color:#75715e\"\u003e# 受保护属性（约定不直接访问）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e__balance \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e initial_balance   \u003cspan style=\"color:#75715e\"\u003e# 私有属性（名称改写）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edeposit\u003c/span\u003e(self, amount):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e amount \u003cspan style=\"color:#f92672\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eraise\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;存款金额必须为正数\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e__balance \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e amount\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e_transactions\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend((\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;存款\u0026#34;\u003c/span\u003e, amount))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ewithdraw\u003c/span\u003e(self, amount):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e amount \u003cspan style=\"color:#f92672\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eraise\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;取款金额必须为正数\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e amount \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e__balance:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eraise\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;余额不足\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e__balance \u003cspan style=\"color:#f92672\"\u003e-=\u003c/span\u003e amount\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e_transactions\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend((\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;取款\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eamount))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget_balance\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;获取余额（受控访问）\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e__balance\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget_transactions\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;获取交易记录\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e_transactions\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecopy()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 创建账户\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eaccount \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e BankAccount(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;ACC001\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1000\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 公开属性可以直接访问\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;账号：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eaccount\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eaccount_id\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 受保护属性（可以访问，但不推荐）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;交易记录：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eaccount\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e_transactions\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 私有属性（访问会报错）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# print(account.__balance)  # AttributeError\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 但可以通过改写后的名称访问（不推荐）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(account\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e_BankAccount__balance)  \u003cspan style=\"color:#75715e\"\u003e# 1000\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 通过方法访问私有属性（推荐方式）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;余额：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eaccount\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget_balance()\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 存款和取款\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eaccount\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edeposit(\u003cspan style=\"color:#ae81ff\"\u003e500\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eaccount\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewithdraw(\u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;交易记录：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eaccount\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget_transactions()\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# [(\u0026#39;存款\u0026#39;, 500), (\u0026#39;取款\u0026#39;, -200)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"为什么要使用私有属性\"\u003e为什么要使用私有属性？\u003c/h2\u003e\n\u003cp\u003e假设我们有一个 \u003ccode\u003eBankAccount\u003c/code\u003e 类，余额是一个私有属性。如果允许外部代码直接访问和修改余额，那么可能会出现以下问题：\u003c/p\u003e","tags":"Python, 编程","title":"Day 24 - 私有属性与封装"},{"columns":"python-course","content":"Day 25 - 继承与 super 函数 什么是继承？ 继承（Inheritance）是面向对象编程中最核心的概念之一，它允许我们定义一个类（子类）作为另一个类（父类或基类）的扩展。子类继承了父类的属性和方法，同时可以添加自己特有的属性和方法，或者重写（override）父类的方法来改变行为。\n继承的主要好处是代码复用：公共的属性和方法只需要在父类中定义一次，子类自动拥有这些特性。此外，继承还体现了\u0026quot;是一个\u0026quot;（is-a）的关系，例如：狗是一种动物，学生是一个人，苹果是一种水果。\n在 Python 中，使用圆括号 () 在类名后指定父类来实现继承。\n继承的基本语法 class 父类: # 父类的定义 class 子类(父类): # 子类的定义 class Animal: \u0026#34;\u0026#34;\u0026#34;动物基类\u0026#34;\u0026#34;\u0026#34; def __init__(self, name, age): self.name = name self.age = age def speak(self): raise NotImplementedError(\u0026#34;子类必须实现 speak 方法\u0026#34;) def info(self): print(f\u0026#34;名字：{self.name}，年龄：{self.age}\u0026#34;) class Dog(Animal): \u0026#34;\u0026#34;\u0026#34;狗类，继承自动物类\u0026#34;\u0026#34;\u0026#34; def speak(self): print(f\u0026#34;{self.name} 在叫：汪汪汪！\u0026#34;) class Cat(Animal): \u0026#34;\u0026#34;\u0026#34;猫类，继承自动物类\u0026#34;\u0026#34;\u0026#34; def speak(self): print(f\u0026#34;{self.name} 在叫：喵喵喵！\u0026#34;) # 创建子类对象 dog = Dog(\u0026#34;旺财\u0026#34;, 3) cat = Cat(\u0026#34;小白\u0026#34;, 2) dog.info() # 名字：旺财，年龄：3 dog.speak() # 旺财 在叫：汪汪汪！ cat.info() # 名字：小白，年龄：2 cat.speak() # 小白 在叫：喵喵喵！ 单继承与多继承 Python 支持两种继承方式：单继承（一个类只继承一个父类）和多继承（一个类继承多个父类）。虽然多继承功能强大，但容易导致代码复杂度增加和菱形继承问题，因此在使用时需要特别小心。\n# 单继承示例 class Vehicle: def __init__(self, brand, speed): self.brand = brand self.speed = speed def display(self): print(f\u0026#34;品牌：{self.brand}，速度：{self.speed}km/h\u0026#34;) class Car(Vehicle): \u0026#34;\u0026#34;\u0026#34;汽车类，单继承自 Vehicle\u0026#34;\u0026#34;\u0026#34; def __init__(self, brand, speed, doors): super().__init__(brand, speed) # 调用父类的 __init__ self.doors = doors def display(self): super().display() # 调用父类的方法 print(f\u0026#34;车门数：{self.doors}\u0026#34;) car = Car(\u0026#34;丰田\u0026#34;, 180, 4) car.display() # 品牌：丰田，速度：180km/h # 车门数：4 super() 函数详解 super() 函数是 Python 中调用父类方法的标准方式。它返回一个代理对象，将方法调用转发给父类。使用 super() 的好处是：\n避免直接引用父类，使代码更灵活 自动处理方法解析顺序（MRO） 支持协作式多继承调用 class Person: def __init__(self, name, age): self.name = name self.age = age print(f\u0026#34;Person.__init__ 被调用：{name}, {age}\u0026#34;) def greet(self): print(f\u0026#34;你好，我叫 {self.name}\u0026#34;) class Student(Person): def __init__(self, name, age, student_id): super().__init__(name, age) # 调用父类的 __init__ self.student_id = student_id print(f\u0026#34;Student.__init__ 被调用：{student_id}\u0026#34;) def greet(self): super().greet() # 调用父类的 greet print(f\u0026#34;我的学号是 {self.student_id}\u0026#34;) student = Student(\u0026#34;张三\u0026#34;, 20, \u0026#34;2023001\u0026#34;) # Person.__init__ 被调用：张三, 20 # Student.__init__ 被调用：2023001 student.greet() # 你好，我叫 张三 # 我的学号是 2023001 在子类中扩展父类的方法 子类可以在继承父类方法的基础上进行扩展或修改。常见的模式是：在子类的重写方法中先调用父类的方法，然后添加子类特有的逻辑。\nclass Shape: def __init__(self, color=\u0026#34;黑色\u0026#34;): self.color = color def area(self): \u0026#34;\u0026#34;\u0026#34;计算面积，子类应重写此方法\u0026#34;\u0026#34;\u0026#34; return 0 def describe(self): print(f\u0026#34;这是一个{self.color}的形状\u0026#34;) class Rectangle(Shape): def __init__(self, width, height, color=\u0026#34;蓝色\u0026#34;): super().__init__(color) # 调用父类构造器 self.width = width self.height = height def area(self): \u0026#34;\u0026#34;\u0026#34;重写父类的 area 方法\u0026#34;\u0026#34;\u0026#34; return self.width * self.height def describe(self): \u0026#34;\u0026#34;\u0026#34;扩展父类的 describe 方法\u0026#34;\u0026#34;\u0026#34; super().describe() # 先调用父类的方法 print(f\u0026#34;宽：{self.width}，高：{self.height}，面积：{self.area()}\u0026#34;) class Circle(Shape): def __init__(self, radius, color=\u0026#34;红色\u0026#34;): super().__init__(color) self.radius = radius def area(self): \u0026#34;\u0026#34;\u0026#34;重写父类的 area 方法\u0026#34;\u0026#34;\u0026#34; import math return math.pi * self.radius ** 2 def describe(self): \u0026#34;\u0026#34;\u0026#34;扩展父类的 describe 方法\u0026#34;\u0026#34;\u0026#34; super().describe() print(f\u0026#34;半径：{self.radius}，面积：{self.area():.2f}\u0026#34;) rect = Rectangle(10, 5, \u0026#34;绿色\u0026#34;) rect.describe() # 这是一个绿色的形状 # 宽：10，高：5，面积：50 circle = Circle(5) circle.describe() # 这是一个红色的形状 # 半径：5，面积：78.54 issubclass() 和 isinstance() Python 提供了两个内置函数来检查类的继承关系：\nissubclass(cls, classinfo)：检查 cls 是否是 classinfo 的子类 isinstance(obj, classinfo)：检查 obj 是否是 classinfo 的实例 class Animal: pass class Dog(Animal): pass class Cat(Animal): pass class Labrador(Dog): pass # issubclass 检查 print(issubclass(Dog, Animal)) # True：Dog 是 Animal 的子类 print(issubclass(Labrador, Dog)) # True：Labrador 是 Dog 的子类 print(issubclass(Labrador, Animal)) # True：Labrador 也是 Animal 的子类（传递性） print(issubclass(Dog, (Dog, Cat))) # True：Dog 是 (Dog, Cat) 元组中任意一个的子类 # isinstance 检查 dog = Dog() cat = Cat() lab = Labrador() print(isinstance(dog, Dog)) # True print(isinstance(dog, Animal)) # True：Dog 实例也是 Animal 实例 print(isinstance(lab, Labrador)) # True print(isinstance(lab, Dog)) # True print(isinstance(lab, (Dog, Cat))) # True # 常见错误 print(isinstance(dog, Labrador)) # False：Dog 实例不是 Labrador 继承与属性访问 当访问对象的属性时，Python 会按照特定的顺序在继承链中查找，这个顺序叫做\u0026quot;方法解析顺序\u0026quot;（Method Resolution Order, MRO）。对于单继承，MRO 是从子类到父类，再到父类的父类，直到 object 类。\nclass A: x = 1 class B(A): pass class C(A): x = 2 class D(B, C): pass print(D.x) # 1（继承自 A） print(D.__mro__) # 查看完整的 MRO # (\u0026lt;class \u0026#39;D\u0026#39;\u0026gt;, \u0026lt;class \u0026#39;B\u0026#39;\u0026gt;, \u0026lt;class \u0026#39;C\u0026#39;\u0026gt;, \u0026lt;class \u0026#39;A\u0026#39;\u0026gt;, \u0026lt;class \u0026#39;object\u0026#39;\u0026gt;) # 修改 C 的 x C.x = 3 print(D.x) # 1（仍然是 1，因为 D 直接继承 B，B 继承 A） 父类方法的可访问性 子类可以访问父类的公共（public）和受保护（protected）成员，但不能直接访问父类的私有成员。不过，私有成员可以通过父类提供的公共方法来访问。\nclass Base: def __init__(self): self.public = \u0026#34;公开\u0026#34; self._protected = \u0026#34;受保护\u0026#34; self.__private = \u0026#34;私有\u0026#34; # 名称改写为 _Base__private def public_method(self): return \u0026#34;公共方法\u0026#34; def _protected_method(self): return \u0026#34;受保护方法\u0026#34; def __private_method(self): return \u0026#34;私有方法\u0026#34; def access_private(self): \u0026#34;\u0026#34;\u0026#34;通过公共方法访问私有成员\u0026#34;\u0026#34;\u0026#34; return self.__private class Derived(Base): def access_base(self): print(self.public) # OK print(self._protected) # OK（约定可以访问） # print(self.__private) # 错误：AttributeError print(self._Base__private) # 技术上可行，但不推荐 print(self.access_private()) # OK：通过公共方法访问 多继承中的 super() 在多继承情况下，super() 的行为会更加复杂。它遵循 C3 线性化算法来确定方法解析顺序。关键点是：super() 不一定调用直接父类的方法，而是调用 MRO 中的下一个类。\nclass A: def __init__(self): print(\u0026#34;A.__init__\u0026#34;) super().__init__() class B: def __init__(self): print(\u0026#34;B.__init__\u0026#34;) super().__init__() class C(A, B): def __init__(self): print(\u0026#34;C.__init__\u0026#34;) super().__init__() # 注意调用顺序 print(\u0026#34;创建 C 对象：\u0026#34;) c = C() # 输出： # C.__init__ # A.__init__ # B.__init__ print(\u0026#34;\\nC 的 MRO：\u0026#34;) for cls in C.__mro__: print(f\u0026#34; {cls.__name__}\u0026#34;) Mixin 模式 Mixin（混入）是一种设计模式，用于在多继承中向类添加可选功能。Mixin 类通常：\n提供某个特定方面的功能 不需要自己的构造函数（或构造函数很简单） 设计为与其他类组合使用 class FlyMixin: \u0026#34;\u0026#34;\u0026#34;飞行能力混入\u0026#34;\u0026#34;\u0026#34; def fly(self): print(f\u0026#34;{self.name} 正在飞翔\u0026#34;) class SwinMixin: \u0026#34;\u0026#34;\u0026#34;游泳能力混入\u0026#34;\u0026#34;\u0026#34; def swim(self): print(f\u0026#34;{self.name} 正在游泳\u0026#34;) class WalkMixin: \u0026#34;\u0026#34;\u0026#34;行走能力混入\u0026#34;\u0026#34;\u0026#34; def walk(self): print(f\u0026#34;{self.name} 正在行走\u0026#34;) class Animal: def __init__(self, name): self.name = name class Duck(Animal, FlyMixin, SwinMixin, WalkMixin): \u0026#34;\u0026#34;\u0026#34;鸭子：会飞、会游泳、会走\u0026#34;\u0026#34;\u0026#34; pass class Dog(Animal, WalkMixin, SwinMixin): \u0026#34;\u0026#34;\u0026#34;狗：会走、会游泳\u0026#34;\u0026#34;\u0026#34; pass class Penguin(Animal, SwinMixin, WalkMixin): \u0026#34;\u0026#34;\u0026#34;企鹅：会游泳、会走（但不会飞）\u0026#34;\u0026#34;\u0026#34; pass duck = Duck(\u0026#34;唐老鸭\u0026#34;) duck.fly() # 唐老鸭 正在飞翔 duck.swim() # 唐老鸭 正在游泳 duck.walk() # 唐老鸭 正在行走 dog = Dog(\u0026#34;旺财\u0026#34;) # dog.fly() # AttributeError dog.swim() # 旺财 正在游泳 dog.walk() # 旺财 正在行走 抽象基类（ABC） 抽象基类（Abstract Base Class）用于定义接口规范，强制子类实现某些方法。Python 的 abc 模块提供了 ABC 类和 @abstractmethod 装饰器来实现抽象基类。\nfrom abc import ABC, abstractmethod class Shape(ABC): \u0026#34;\u0026#34;\u0026#34;抽象基类：形状\u0026#34;\u0026#34;\u0026#34; def __init__(self, color=\u0026#34;黑色\u0026#34;): self.color = color @abstractmethod def area(self): \u0026#34;\u0026#34;\u0026#34;抽象方法：计算面积，子类必须实现\u0026#34;\u0026#34;\u0026#34; pass @abstractmethod def perimeter(self): \u0026#34;\u0026#34;\u0026#34;抽象方法：计算周长，子类必须实现\u0026#34;\u0026#34;\u0026#34; pass def describe(self): \u0026#34;\u0026#34;\u0026#34;普通方法：描述形状\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;这是一个{self.color}的{self.__class__.__name__}\u0026#34;) class Rectangle(Shape): def __init__(self, width, height, color=\u0026#34;蓝色\u0026#34;): super().__init__(color) self.width = width self.height = height def area(self): return self.width * self.height def perimeter(self): return 2 * (self.width + self.height) # 不能直接实例化抽象基类 # shape = Shape() # TypeError rect = Rectangle(10, 5) print(f\u0026#34;面积：{rect.area()}\u0026#34;) # 50 print(f\u0026#34;周长：{rect.perimeter()}\u0026#34;) # 30 rect.describe() # 这是一个蓝色的Rectangle 练习题 练习 1：员工管理系统 from abc import ABC, abstractmethod class Employee(ABC): \u0026#34;\u0026#34;\u0026#34;员工抽象基类\u0026#34;\u0026#34;\u0026#34; def __init__(self, emp_id, name): self.emp_id = emp_id self.name = name @abstractmethod def calculate_salary(self): \u0026#34;\u0026#34;\u0026#34;计算月薪（抽象方法）\u0026#34;\u0026#34;\u0026#34; pass def display(self): \u0026#34;\u0026#34;\u0026#34;显示员工信息\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;工号：{self.emp_id}，姓名：{self.name}，月薪：{self.calculate_salary():.2f}\u0026#34;) class FullTimeEmployee(Employee): \u0026#34;\u0026#34;\u0026#34;全职员工\u0026#34;\u0026#34;\u0026#34; def __init__(self, emp_id, name, base_salary): super().__init__(emp_id, name) self.base_salary = base_salary def calculate_salary(self): return self.base_salary class PartTimeEmployee(Employee): \u0026#34;\u0026#34;\u0026#34;兼职员工\u0026#34;\u0026#34;\u0026#34; def __init__(self, emp_id, name, hours, hourly_rate): super().__init__(emp_id, name) self.hours = hours self.hourly_rate = hourly_rate def calculate_salary(self): return self.hours * self.hourly_rate class SalesEmployee(Employee): \u0026#34;\u0026#34;\u0026#34;销售员工\u0026#34;\u0026#34;\u0026#34; def __init__(self, emp_id, name, base_salary, commission, sales_amount): super().__init__(emp_id, name) self.base_salary = base_salary self.commission = commission self.sales_amount = sales_amount def calculate_salary(self): return self.base_salary + self.commission * self.sales_amount # 测试 employees = [ FullTimeEmployee(\u0026#34;E001\u0026#34;, \u0026#34;张三\u0026#34;, 8000), PartTimeEmployee(\u0026#34;E002\u0026#34;, \u0026#34;李四\u0026#34;, 80, 50), SalesEmployee(\u0026#34;E003\u0026#34;, \u0026#34;王五\u0026#34;, 5000, 0.1, 50000) ] for emp in employees: emp.display() # 工号：E001，姓名：张三，月薪：8000.00 # 工号：E002，姓名：李四，月薪：4000.00 # 工号：E003，姓名：王五，月薪：10000.00 练习 2：几何图形层次结构 from abc import ABC, abstractmethod import math class Shape(ABC): def __init__(self, color=\u0026#34;黑色\u0026#34;): self.color = color @abstractmethod def area(self): pass @abstractmethod def perimeter(self): pass def __str__(self): return f\u0026#34;{self.__class__.__name__}(color={self.color})\u0026#34; class Circle(Shape): def __init__(self, radius, color=\u0026#34;红色\u0026#34;): super().__init__(color) self.radius = radius def area(self): return math.pi * self.radius ** 2 def perimeter(self): return 2 * math.pi * self.radius class Triangle(Shape): def __init__(self, a, b, c, color=\u0026#34;蓝色\u0026#34;): super().__init__(color) self.a = a self.b = b self.c = c def area(self): # 海伦公式 s = (self.a + self.b + self.c) / 2 return math.sqrt(s * (s - self.a) * (s - self.b) * (s - self.c)) def perimeter(self): return self.a + self.b + self.c class Rectangle(Shape): def __init__(self, width, height, color=\u0026#34;绿色\u0026#34;): super().__init__(color) self.width = width self.height = height def area(self): return self.width * self.height def perimeter(self): return 2 * (self.width + self.height) # 测试 shapes = [ Circle(5, \u0026#34;红色\u0026#34;), Triangle(3, 4, 5, \u0026#34;蓝色\u0026#34;), Rectangle(10, 5, \u0026#34;绿色\u0026#34;) ] for shape in shapes: print(f\u0026#34;{shape}\u0026#34;) print(f\u0026#34; 面积：{shape.area():.2f}\u0026#34;) print(f\u0026#34; 周长：{shape.perimeter():.2f}\u0026#34;) 总结 继承是面向对象编程的核心概念之一：\n继承基础：子类继承父类的属性和方法 super() 函数：调用父类的方法，处理 MRO 方法重写：子类可以重写父类的方法来改变行为 isinstance 和 issubclass：检查对象和类的继承关系 多继承：支持一个类继承多个父类，但需要注意 MRO Mixin 模式：通过多继承添加可选功能 抽象基类：使用 @abstractmethod 定义接口规范 继承使得代码复用成为可能，同时支持多态（不同子类可以以相同的方式使用）。在下一节中，我们将继续学习多重继承和方法解析顺序（MRO）的深入内容。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-25-inheritance-super/","summary":"\u003ch1 id=\"day-25---继承与-super-函数\"\u003eDay 25 - 继承与 super 函数\u003c/h1\u003e\n\u003ch2 id=\"什么是继承\"\u003e什么是继承？\u003c/h2\u003e\n\u003cp\u003e继承（Inheritance）是面向对象编程中最核心的概念之一，它允许我们定义一个类（子类）作为另一个类（父类或基类）的扩展。子类继承了父类的属性和方法，同时可以添加自己特有的属性和方法，或者重写（override）父类的方法来改变行为。\u003c/p\u003e\n\u003cp\u003e继承的主要好处是代码复用：公共的属性和方法只需要在父类中定义一次，子类自动拥有这些特性。此外，继承还体现了\u0026quot;是一个\u0026quot;（is-a）的关系，例如：狗是一种动物，学生是一个人，苹果是一种水果。\u003c/p\u003e\n\u003cp\u003e在 Python 中，使用圆括号 \u003ccode\u003e()\u003c/code\u003e 在类名后指定父类来实现继承。\u003c/p\u003e\n\u003ch2 id=\"继承的基本语法\"\u003e继承的基本语法\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e父类\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 父类的定义\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e子类\u003c/span\u003e(父类):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 子类的定义\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eAnimal\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;动物基类\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e __init__(self, name, age):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ename \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e name\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eage \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e age\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003espeak\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eraise\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eNotImplementedError\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;子类必须实现 speak 方法\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003einfo\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;名字：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e，年龄：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eage\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eDog\u003c/span\u003e(Animal):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;狗类，继承自动物类\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003espeak\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 在叫：汪汪汪！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eCat\u003c/span\u003e(Animal):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;猫类，继承自动物类\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003espeak\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 在叫：喵喵喵！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 创建子类对象\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edog \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Dog(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;旺财\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecat \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Cat(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;小白\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edog\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003einfo()   \u003cspan style=\"color:#75715e\"\u003e# 名字：旺财，年龄：3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edog\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003espeak()  \u003cspan style=\"color:#75715e\"\u003e# 旺财 在叫：汪汪汪！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecat\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003einfo()   \u003cspan style=\"color:#75715e\"\u003e# 名字：小白，年龄：2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecat\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003espeak()  \u003cspan style=\"color:#75715e\"\u003e# 小白 在叫：喵喵喵！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"单继承与多继承\"\u003e单继承与多继承\u003c/h2\u003e\n\u003cp\u003ePython 支持两种继承方式：单继承（一个类只继承一个父类）和多继承（一个类继承多个父类）。虽然多继承功能强大，但容易导致代码复杂度增加和菱形继承问题，因此在使用时需要特别小心。\u003c/p\u003e","tags":"Python, 编程","title":"Day 25 - 继承与 super 函数"},{"columns":"python-course","content":"Day 26 - 多重继承与方法解析顺序（MRO） 多重继承的概念 多重继承（Multiple Inheritance）是指一个类可以直接继承多个父类。Python 完整地支持多重继承，这使得类可以从多个不相关的类中继承功能。然而，多重继承也带来了复杂性，特别是在方法解析顺序（Method Resolution Order，MRO）和菱形继承问题上。\nclass Flyer: def fly(self): print(\u0026#34;我可以飞翔\u0026#34;) class Swimmer: def swim(self): print(\u0026#34;我可以游泳\u0026#34;) class Walker: def walk(self): print(\u0026#34;我可以行走\u0026#34;) class Duck(Flyer, Swimmer, Walker): \u0026#34;\u0026#34;\u0026#34;鸭子继承三种能力\u0026#34;\u0026#34;\u0026#34; pass duck = Duck() duck.fly() # 我可以飞翔 duck.swim() # 我可以游泳 duck.walk() # 我可以行走 菱形继承问题 菱形继承（Diamond Inheritance）是指两个类继承自同一个基类，然后又有一个类同时继承这两个类，形成菱形结构。这种结构在多重继承中容易引发问题：如果基类有实例属性或方法，在子类中应该如何访问？\nclass A: def greet(self): print(\u0026#34;A 的 greet 方法\u0026#34;) class B(A): def greet(self): print(\u0026#34;B 的 greet 方法\u0026#34;) super().greet() class C(A): def greet(self): print(\u0026#34;C 的 greet 方法\u0026#34;) super().greet() class D(B, C): def greet(self): print(\u0026#34;D 的 greet 方法\u0026#34;) super().greet() # 创建 D 的实例并调用 greet d = D() d.greet() 输出：\nD 的 greet 方法 B 的 greet 方法 C 的 greet 方法 A 的 greet 方法方法解析顺序（MRO） Python 使用 C3 线性化算法来计算方法解析顺序。MRO 是一个确定性算法，确保在多重继承中方法的调用顺序是明确且一致的。\n每个类都有一个 __mro__ 属性，是一个元组，包含类的方法解析顺序（不包括类自己）。\nclass A: pass class B(A): pass class C(A): pass class D(B, C): pass # 查看 MRO print(D.__mro__) # (\u0026lt;class \u0026#39;D\u0026#39;\u0026gt;, \u0026lt;class \u0026#39;B\u0026#39;\u0026gt;, \u0026lt;class \u0026#39;C\u0026#39;\u0026gt;, \u0026lt;class \u0026#39;A\u0026#39;\u0026gt;, \u0026lt;class \u0026#39;object\u0026#39;\u0026gt;) # 使用 mro() 方法 print(D.mro()) # [\u0026lt;class \u0026#39;D\u0026#39;\u0026gt;, \u0026lt;class \u0026#39;B\u0026#39;\u0026gt;, \u0026lt;class \u0026#39;C\u0026#39;\u0026gt;, \u0026lt;class \u0026#39;A\u0026#39;\u0026gt;, \u0026lt;class \u0026#39;object\u0026#39;\u0026gt;] super() 在多重继承中的行为 super() 的行为与 MRO 密切相关。super() 不是简单调用\u0026quot;直接父类\u0026quot;的方法，而是调用 MRO 中当前类\u0026quot;之后\u0026quot;的下一个类。\nclass Base: def __init__(self): print(\u0026#34;Base.__init__\u0026#34;) super().__init__() class Left(Base): def __init__(self): print(\u0026#34;Left.__init__\u0026#34;) super().__init__() class Right(Base): def __init__(self): print(\u0026#34;Right.__init__\u0026#34;) super().__init__() class Child(Left, Right): def __init__(self): print(\u0026#34;Child.__init__\u0026#34;) super().__init__() print(\u0026#34;创建 Child 对象：\u0026#34;) child = Child() print(\u0026#34;\\nChild 的 MRO：\u0026#34;) for cls in Child.__mro__: print(f\u0026#34; {cls.__name__}\u0026#34;) 输出：\n创建 Child 对象： Child.__init__ Left.__init__ Right.__init__ Base.__init__ Child 的 MRO： Child Left Right Base object深入理解 MRO MRO 的计算遵循以下原则：\n子类优先于父类 多个父类按照它们的声明顺序排序 对于每个父类，只处理一次（不会重复） 如果是菱形继承，基类只出现一次 class X: pass class Y: pass class A(X, Y): pass class B(Y, X): # 注意顺序与 A 相反 pass class C(A, B): pass print(\u0026#34;C 的 MRO：\u0026#34;) for cls in C.__mro__: print(f\u0026#34; {cls.__name__}\u0026#34;) Mixin 类的设计 Mixin 是一种设计模式，用于在多重继承中添加可选功能。Mixin 类的特点是：\n提供某个特定方面的功能 不需要复杂的初始化 依赖于被混入的类提供某些属性或方法 class DistanceMixin: \u0026#34;\u0026#34;\u0026#34;距离计算混入\u0026#34;\u0026#34;\u0026#34; def distance_to(self, other): \u0026#34;\u0026#34;\u0026#34;计算到另一个点的距离（假设其他对象有 x, y 属性）\u0026#34;\u0026#34;\u0026#34; dx = self.x - other.x dy = self.y - other.y return (dx**2 + dy**2)**0.5 class ColorMixin: \u0026#34;\u0026#34;\u0026#34;颜色混入\u0026#34;\u0026#34;\u0026#34; def set_color(self, color): self.color = color def get_color(self): return getattr(self, \u0026#39;color\u0026#39;, \u0026#39;未设置\u0026#39;) class Point: def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return f\u0026#34;Point({self.x}, {self.y})\u0026#34; class ColoredPoint(Point, DistanceMixin, ColorMixin): \u0026#34;\u0026#34;\u0026#34;带颜色的点，同时具有距离计算功能\u0026#34;\u0026#34;\u0026#34; pass p1 = ColoredPoint(0, 0) p2 = ColoredPoint(3, 4) p1.set_color(\u0026#34;红色\u0026#34;) print(f\u0026#34;p1 颜色：{p1.get_color()}\u0026#34;) # 红色 print(f\u0026#34;p1 到 p2 的距离：{p1.distance_to(p2):.2f}\u0026#34;) # 5.00 组合 vs 继承 在设计类层次结构时，我们应该优先考虑\u0026quot;组合（Composition）\u0026ldquo;还是\u0026quot;继承（Inheritance）\u0026quot;？这是一个重要的设计决策。\n继承的优点：\n代码复用 自然的\u0026quot;是一个\u0026quot;关系 多态支持 继承的缺点：\n类层次耦合度高 不够灵活 可能导致菱形继承问题 组合的优点：\n低耦合 更灵活 容易测试 组合的缺点：\n需要更多的代码来实现代理方法 # 继承方式 class Dog(Animal): def __init__(self, name): super().__init__(name) # 组合方式 class Dog: def __init__(self, name): self.animal = Animal(name) # 组合 钻石继承的完整示例 class BaseGeometry: \u0026#34;\u0026#34;\u0026#34;基础几何类\u0026#34;\u0026#34;\u0026#34; def __init__(self): print(\u0026#34;BaseGeometry.__init__\u0026#34;) super().__init__() class Polygon(BaseGeometry): \u0026#34;\u0026#34;\u0026#34;多边形类\u0026#34;\u0026#34;\u0026#34; def __init__(self, sides): print(f\u0026#34;Polygon.__init__ (sides={sides})\u0026#34;) self.sides = sides super().__init__() def area(self): raise NotImplementedError(\u0026#34;子类必须实现 area 方法\u0026#34;) class Quadrilateral(Polygon): \u0026#34;\u0026#34;\u0026#34;四边形类\u0026#34;\u0026#34;\u0026#34; def __init__(self, length, width): print(f\u0026#34;Quadrilateral.__init__ ({length}x{width})\u0026#34;) self.length = length self.width = width super().__init__(4) # 四边形有4条边 def area(self): return self.length * self.width class Rectangle(Quadrilateral): \u0026#34;\u0026#34;\u0026#34;矩形类\u0026#34;\u0026#34;\u0026#34; def __init__(self, length, width): print(f\u0026#34;Rectangle.__init__ ({length}x{width})\u0026#34;) super().__init__(length, width) def perimeter(self): return 2 * (self.length + self.width) class Square(Rectangle): \u0026#34;\u0026#34;\u0026#34;正方形类\u0026#34;\u0026#34;\u0026#34; def __init__(self, side): print(f\u0026#34;Square.__init__ (side={side})\u0026#34;) super().__init__(side, side) # 测试菱形继承 print(\u0026#34;创建正方形：\u0026#34;) sq = Square(5) print(f\u0026#34;边数：{sq.sides}\u0026#34;) # 4 print(f\u0026#34;面积：{sq.area()}\u0026#34;) # 25 print(f\u0026#34;周长：{sq.perimeter()}\u0026#34;) # 20 方法解析顺序的高级用法 可以使用 super(ClassName, self) 的形式来调用 MRO 中特定类之后的方法。\nclass A: def method(self): print(\u0026#34;A.method\u0026#34;) return \u0026#34;A\u0026#34; class B(A): def method(self): print(\u0026#34;B.method\u0026#34;) return super().method() class C(A): def method(self): print(\u0026#34;C.method\u0026#34;) return super().method() class D(B, C): def method(self): print(\u0026#34;D.method\u0026#34;) # 调用 B 之后的方法（也就是 C） return super(B, self).method() d = D() result = d.method() print(f\u0026#34;返回值：{result}\u0026#34;) # D.method # C.method # A.method # 返回值：A super 的等价形式 在 Python 3 中，super() 等价于 super(ClassName, self)，其中 ClassName 是定义 super() 调用的类的名称。\nclass Base: def greet(self): return \u0026#34;Base\u0026#34; class Left(Base): def greet(self): return f\u0026#34;Left({super().greet()})\u0026#34; class Right(Base): def greet(self): return f\u0026#34;Right({super().greet()})\u0026#34; class Child(Left, Right): def greet(self): return f\u0026#34;Child({super().greet()})\u0026#34; # 测试 child = Child() print(child.greet()) # Child(Left(Right(Base))) 避免多重继承的陷阱 避免过度使用多重继承：如果可能，优先使用组合或 Mixin 保持继承层次扁平：避免深层继承树 明确依赖顺序：当必须使用多重继承时，明确基类的顺序 使用 Mixin：将可选功能提取为 Mixin 类 # 不推荐：深层继承 class Level1: pass class Level2(Level1): pass class Level3(Level2): pass class Level4(Level3): pass # 推荐：扁平结构 + Mixin class FeatureMixin: pass class Base: pass class Child(FeatureMixin, Base): pass 练习题 练习 1：计算 MRO class A: pass class B(A): pass class C(A): pass class D(B, C): pass class E(C, B): pass class F(D, E): pass print(\u0026#34;各类的 MRO：\u0026#34;) print(f\u0026#34;D: {[c.__name__ for c in D.__mro__]}\u0026#34;) print(f\u0026#34;E: {[c.__name__ for c in E.__mro__]}\u0026#34;) print(f\u0026#34;F: {[c.__name__ for c in F.__mro__]}\u0026#34;) 练习 2：实现可排序的类 class ComparableMixin: \u0026#34;\u0026#34;\u0026#34;可比较混入\u0026#34;\u0026#34;\u0026#34; def _compare_to(self, other): raise NotImplementedError def __eq__(self, other): if other is None: return False return self._compare_to(other) == 0 def __ne__(self, other): return not self.__eq__(other) def __lt__(self, other): if other is None: return False return self._compare_to(other) \u0026lt; 0 def __le__(self, other): return self == other or self \u0026lt; other def __gt__(self, other): return other is not None and self._compare_to(other) \u0026gt; 0 def __ge__(self, other): return self == other or self \u0026gt; other class Person(ComparableMixin): def __init__(self, name, age): self.name = name self.age = age def _compare_to(self, other): if not isinstance(other, Person): return NotImplemented return self.age - other.age def __repr__(self): return f\u0026#34;Person({self.name}, {self.age})\u0026#34; # 测试 p1 = Person(\u0026#34;张三\u0026#34;, 25) p2 = Person(\u0026#34;李四\u0026#34;, 30) p3 = Person(\u0026#34;王五\u0026#34;, 25) print(p1 \u0026lt; p2) # True print(p1 == p3) # False（不同对象） print(p1 != p2) # True print(p1 \u0026lt; p3) # False（年龄相同） 练习 3：实现日志功能的 Mixin import logging from datetime import datetime class LogMixin: \u0026#34;\u0026#34;\u0026#34;日志混入：给类添加日志功能\u0026#34;\u0026#34;\u0026#34; def __init__(self): self.logger = logging.getLogger(self.__class__.__name__) self.logger.setLevel(logging.DEBUG) if not self.logger.handlers: handler = logging.StreamHandler() handler.setFormatter(logging.Formatter( \u0026#39;%(asctime)s - %(name)s - %(levelname)s - %(message)s\u0026#39; )) self.logger.addHandler(handler) def log_info(self, message): self.logger.info(message) def log_debug(self, message): self.logger.debug(message) def log_error(self, message): self.logger.error(message) class BankAccount(LogMixin): def __init__(self, account_id, balance=0): super().__init__() self.account_id = account_id self.balance = balance self.log_info(f\u0026#34;创建账户 {account_id}，初始余额 {balance}\u0026#34;) def deposit(self, amount): if amount \u0026lt;= 0: self.log_error(f\u0026#34;存款失败：金额 {amount} 无效\u0026#34;) return False self.balance += amount self.log_info(f\u0026#34;存款 {amount}，新余额 {self.balance}\u0026#34;) return True def withdraw(self, amount): if amount \u0026gt; self.balance: self.log_error(f\u0026#34;取款失败：余额不足（余额 {self.balance}，取款 {amount}）\u0026#34;) return False self.balance -= amount self.log_info(f\u0026#34;取款 {amount}，新余额 {self.balance}\u0026#34;) return True # 测试 account = BankAccount(\u0026#34;ACC001\u0026#34;, 1000) account.deposit(500) account.withdraw(200) account.withdraw(2000) # 会记录错误日志 总结 多重继承和方法解析顺序（MRO）是 Python 面向对象编程中的高级主题：\n多重继承：一个类可以继承多个父类 菱形继承：可能导致方法调用歧义 MRO：Python 使用 C3 线性化算法确定方法调用顺序 super()：调用 MRO 中当前类之后的方法 Mixin：通过多重继承添加可选功能的模式 组合 vs 继承：根据情况选择合适的设计方式 理解 MRO 对于正确使用多重继承至关重要。在下一节中，我们将学习多态和鸭子类型。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-26-mro-multiple-inheritance/","summary":"\u003ch1 id=\"day-26---多重继承与方法解析顺序mro\"\u003eDay 26 - 多重继承与方法解析顺序（MRO）\u003c/h1\u003e\n\u003ch2 id=\"多重继承的概念\"\u003e多重继承的概念\u003c/h2\u003e\n\u003cp\u003e多重继承（Multiple Inheritance）是指一个类可以直接继承多个父类。Python 完整地支持多重继承，这使得类可以从多个不相关的类中继承功能。然而，多重继承也带来了复杂性，特别是在方法解析顺序（Method Resolution Order，MRO）和菱形继承问题上。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eFlyer\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efly\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;我可以飞翔\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eSwimmer\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eswim\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;我可以游泳\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eWalker\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ewalk\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;我可以行走\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eDuck\u003c/span\u003e(Flyer, Swimmer, Walker):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;鸭子继承三种能力\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003epass\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003educk \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Duck()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003educk\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efly()   \u003cspan style=\"color:#75715e\"\u003e# 我可以飞翔\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003educk\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eswim()  \u003cspan style=\"color:#75715e\"\u003e# 我可以游泳\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003educk\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewalk()  \u003cspan style=\"color:#75715e\"\u003e# 我可以行走\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"菱形继承问题\"\u003e菱形继承问题\u003c/h2\u003e\n\u003cp\u003e菱形继承（Diamond Inheritance）是指两个类继承自同一个基类，然后又有一个类同时继承这两个类，形成菱形结构。这种结构在多重继承中容易引发问题：如果基类有实例属性或方法，在子类中应该如何访问？\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eA\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egreet\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;A 的 greet 方法\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eB\u003c/span\u003e(A):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egreet\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;B 的 greet 方法\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egreet()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eC\u003c/span\u003e(A):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egreet\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;C 的 greet 方法\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egreet()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eD\u003c/span\u003e(B, C):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egreet\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;D 的 greet 方法\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egreet()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 创建 D 的实例并调用 greet\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ed \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e D()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ed\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egreet()\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输出：\u003c/p\u003e","tags":"Python, 编程","title":"Day 26 - 多重继承与方法解析顺序（MRO）"},{"columns":"python-course","content":"Day 27 - 多态与鸭子类型 什么是多态？ 多态（Polymorphism）是面向对象编程的三大基本特性之一，意思是\u0026quot;多种形态\u0026quot;。在 Python 中，多态指的是同一种操作（如调用同一个方法）在不同类型的对象上会产生不同的行为。\n多态的核心思想是：关注对象的\u0026quot;行为\u0026quot;而非\u0026quot;类型\u0026quot;。当我们调用一个对象的方法时，不需要关心这个对象是什么类型的具体类，只需要知道它支持这个方法即可。这大大增强了代码的灵活性和可扩展性。\nclass Dog: def speak(self): return \u0026#34;汪汪汪\u0026#34; class Cat: def speak(self): return \u0026#34;喵喵喵\u0026#34; class Duck: def speak(self): return \u0026#34;嘎嘎嘎\u0026#34; # 多态：同一个方法调用，不同对象产生不同行为 animals = [Dog(), Cat(), Duck()] for animal in animals: print(f\u0026#34;{animal.__class__.__name__} 说：{animal.speak()}\u0026#34;) # 输出： # Dog 说：汪汪汪 # Cat 说：喵喵喵 # Duck 说：嘎嘎嘎 Python 中的多态实现 Python 是动态类型语言，天生支持多态。在静态类型语言（如 Java、C++）中，多态需要通过继承和接口来实现。但在 Python 中，任何定义了 speak() 方法的对象都可以被调用，而不需要继承关系。\nclass People: def speak(self): return \u0026#34;你好！\u0026#34; class Bird: def speak(self): return \u0026#34;叽叽喳喳\u0026#34; def make_speak(obj): \u0026#34;\u0026#34;\u0026#34;多态函数：接收任何有 speak 方法的对象\u0026#34;\u0026#34;\u0026#34; print(obj.speak()) person = People() bird = Bird() make_speak(person) # 你好！ make_speak(bird) # 叽叽喳喳 抽象基类与多态 虽然 Python 不强制使用抽象基类，但抽象基类（ABC）提供了一种方式来定义接口规范，确保子类实现了必要的方法。这在大型项目中很有用。\nfrom abc import ABC, abstractmethod class Shape(ABC): \u0026#34;\u0026#34;\u0026#34;抽象基类：形状\u0026#34;\u0026#34;\u0026#34; @abstractmethod def area(self): \u0026#34;\u0026#34;\u0026#34;计算面积\u0026#34;\u0026#34;\u0026#34; pass @abstractmethod def perimeter(self): \u0026#34;\u0026#34;\u0026#34;计算周长\u0026#34;\u0026#34;\u0026#34; pass def describe(self): \u0026#34;\u0026#34;\u0026#34;通用描述方法\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;面积：{self.area():.2f}，周长：{self.perimeter():.2f}\u0026#34; class Rectangle(Shape): def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height def perimeter(self): return 2 * (self.width + self.height) class Circle(Shape): def __init__(self, radius): self.radius = radius def area(self): import math return math.pi * self.radius ** 2 def perimeter(self): import math return 2 * math.pi * self.radius # 多态使用 shapes = [Rectangle(5, 3), Circle(5), Rectangle(10, 2), Circle(3)] total_area = sum(shape.area() for shape in shapes) total_perimeter = sum(shape.perimeter() for shape in shapes) print(f\u0026#34;总面积：{total_area:.2f}\u0026#34;) print(f\u0026#34;总周长：{total_perimeter:.2f}\u0026#34;) for shape in shapes: print(f\u0026#34;{shape.__class__.__name__}: {shape.describe()}\u0026#34;) 鸭子类型（Duck Typing） \u0026ldquo;Duck Typing\u0026rdquo; 这个术语来源于一句话：\u0026ldquo;如果它走起来像鸭子，叫起来像鸭子，那它就是鸭子\u0026rdquo;（If it walks like a duck and quacks like a duck, it\u0026rsquo;s a duck）。\n在 Python 中，鸭子类型是一种编程范式，它关注对象的方法和属性，而非对象的类型。只要对象具有所需的方法和属性，它就可以被使用，而不需要显式的继承或实现某个接口。\nclass Duck: def swim(self): print(\u0026#34;鸭子游泳\u0026#34;) def fly(self): print(\u0026#34;鸭子飞翔\u0026#34;) class Person: def swim(self): print(\u0026#34;人游泳\u0026#34;) def fly(self): print(\u0026#34;人不能飞，但人会坐飞机\u0026#34;) # 函数只要求对象有 swim 和 fly 方法 def make_it_do_things(obj): obj.swim() obj.fly() duck = Duck() person = Person() print(\u0026#34;Duck:\u0026#34;) make_it_do_things(duck) # 鸭子游泳 # 鸭子飞翔 print(\u0026#34;\\nPerson:\u0026#34;) make_it_do_things(person) # 人游泳 # 人不能飞，但人会坐飞机 鸭子类型的优势 鸭子类型的优势在于它的灵活性和松耦合性。不需要显式的继承关系，使得代码更加灵活。\nclass TextFile: def read(self): return \u0026#34;文本文件内容\u0026#34; class CSVFile: def read(self): return \u0026#34;CSV文件内容\u0026#34; class APIClient: def read(self): return \u0026#34;API返回的数据\u0026#34; class Database: def read(self): return \u0026#34;数据库查询结果\u0026#34; # 所有这些类都可以被同一个函数使用 def process_data(source): data = source.read() print(f\u0026#34;处理数据：{data}\u0026#34;) # 不需要继承共同的基类，只要实现了 read 方法就行 process_data(TextFile()) process_data(CSVFile()) process_data(APIClient()) process_data(Database()) 协议（Protocols）与结构子类型 Python 3.8 引入了 typing.Protocol，用于定义结构子类型（Structural Subtyping）。这提供了一种方式来明确指定接口，而不需要显式的继承。\nfrom typing import Protocol class Readable(Protocol): \u0026#34;\u0026#34;\u0026#34;可读协议\u0026#34;\u0026#34;\u0026#34; def read(self) -\u0026gt; str: ... class Writeable(Protocol): \u0026#34;\u0026#34;\u0026#34;可写协议\u0026#34;\u0026#34;\u0026#34; def write(self, data: str) -\u0026gt; None: ... class File: def read(self) -\u0026gt; str: return \u0026#34;文件内容\u0026#34; def write(self, data: str) -\u0026gt; None: print(f\u0026#34;写入数据：{data}\u0026#34;) class Console: def read(self) -\u0026gt; str: return \u0026#34;控制台输入\u0026#34; def write(self, data: str) -\u0026gt; None: print(data) def process_file(file: Readable) -\u0026gt; None: print(f\u0026#34;读取数据：{file.read()}\u0026#34;) def save_file(file: Writeable, data: str) -\u0026gt; None: file.write(data) # File 和 Console 都实现了 Readable 和 Writeable 协议 file = File() console = Console() process_file(file) # OK process_file(console) # OK save_file(file, \u0026#34;新数据\u0026#34;) save_file(console, \u0026#34;控制台输出\u0026#34;) 双分派（Double Dispatch） 双分派是一种多态技术，允许根据一个方法的多个参数类型来选择不同的实现。Python 本身不直接支持双分派，但可以通过一些技巧来实现。\nclass Node: def accept(self, visitor): \u0026#34;\u0026#34;\u0026#34;接受访问者\u0026#34;\u0026#34;\u0026#34; return visitor.visit(self) class TextNode(Node): def accept(self, visitor): return visitor.visit_text(self) def get_text(self): return \u0026#34;文本内容\u0026#34; class ImageNode(Node): def accept(self, visitor): return visitor.visit_image(self) def get_url(self): return \u0026#34;http://example.com/image.jpg\u0026#34; class Visitor: def visit(self, node): raise NotImplementedError def visit_text(self, node): return f\u0026#34;文本：{node.get_text()}\u0026#34; def visit_image(self, node): return f\u0026#34;图片：{node.get_url()}\u0026#34; # 使用 nodes = [TextNode(), ImageNode()] visitor = Visitor() for node in nodes: print(node.accept(visitor)) # 文本：文本内容 # 图片：http://example.com/image.jpg 多态的实际应用 示例 1：插件系统 class Plugin: \u0026#34;\u0026#34;\u0026#34;插件基类\u0026#34;\u0026#34;\u0026#34; def process(self, data): raise NotImplementedError class UpperCasePlugin(Plugin): def process(self, data): return data.upper() class ReversePlugin(Plugin): def process(self, data): return data[::-1] class AddPrefixPlugin(Plugin): def __init__(self, prefix): self.prefix = prefix def process(self, data): return f\u0026#34;{self.prefix}{data}\u0026#34; # 插件系统 class PluginSystem: def __init__(self): self.plugins = [] def register(self, plugin): self.plugins.append(plugin) def process(self, data): result = data for plugin in self.plugins: result = plugin.process(result) return result # 使用 system = PluginSystem() system.register(AddPrefixPlugin(\u0026#34;\u0026gt;\u0026gt;\u0026gt; \u0026#34;)) system.register(UpperCasePlugin()) system.register(ReversePlugin()) result = system.process(\u0026#34;hello\u0026#34;) print(result) # \u0026gt;\u0026gt;\u0026gt; OLLEH 示例 2：序列化系统 class Serializer: \u0026#34;\u0026#34;\u0026#34;序列化器基类\u0026#34;\u0026#34;\u0026#34; def serialize(self, obj): raise NotImplementedError class JSONSerializer(Serializer): def serialize(self, obj): import json return json.dumps(obj, ensure_ascii=False) class XMLSerializer(Serializer): def serialize(self, obj): items = \u0026#39;\u0026#39;.join(f\u0026#39;\u0026lt;item key=\u0026#34;{k}\u0026#34;\u0026gt;{v}\u0026lt;/item\u0026gt;\u0026#39; for k, v in obj.items()) return f\u0026#39;\u0026lt;dict\u0026gt;{items}\u0026lt;/dict\u0026gt;\u0026#39; class YAMLSerializer(Serializer): def serialize(self, obj): import yaml return yaml.dump(obj) def export_data(data, serializer: Serializer): \u0026#34;\u0026#34;\u0026#34;导出数据，使用任意序列化器\u0026#34;\u0026#34;\u0026#34; return serializer.serialize(data) data = {\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25, \u0026#34;city\u0026#34;: \u0026#34;北京\u0026#34;} print(\u0026#34;JSON:\u0026#34;, export_data(data, JSONSerializer())) print(\u0026#34;XML:\u0026#34;, export_data(data, XMLSerializer())) print(\u0026#34;YAML:\u0026#34;, export_data(data, YAMLSerializer())) 方法重写与方法重载 方法重写（Override）：子类重新定义父类的方法，改变行为。\n方法重载（Overload）：同一个方法名，根据参数类型或个数执行不同逻辑。Python 默认不支持方法重载（同一个类中不能有两个同名方法），但可以通过默认参数或类型检查实现类似功能。\nclass Math: def calculate(self, a, b=0, c=0): \u0026#34;\u0026#34;\u0026#34;使用默认参数实现类似重载的功能\u0026#34;\u0026#34;\u0026#34; if b == 0 and c == 0: return a elif c == 0: return a + b else: return a + b + c m = Math() print(m.calculate(5)) # 5 print(m.calculate(5, 3)) # 8 print(m.calculate(5, 3, 2)) # 10 多态与设计模式 多态是许多设计模式的基础：\n策略模式 class SortStrategy: def sort(self, data): raise NotImplementedError class BubbleSort(SortStrategy): def sort(self, data): arr = data.copy() n = len(arr) for i in range(n): for j in range(0, n-i-1): if arr[j] \u0026gt; arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] return arr class QuickSort(SortStrategy): def sort(self, data): arr = data.copy() arr.sort() return arr class Sorter: def __init__(self, strategy): self.strategy = strategy def set_strategy(self, strategy): self.strategy = strategy def sort(self, data): return self.strategy.sort(data) # 使用 sorter = Sorter(BubbleSort()) print(sorter.sort([3, 1, 4, 1, 5, 9, 2, 6])) sorter.set_strategy(QuickSort()) print(sorter.sort([3, 1, 4, 1, 5, 9, 2, 6])) 练习题 练习 1：实现银行账户的多态处理 class Account: def __init__(self, balance): self.balance = balance def withdraw(self, amount): if amount \u0026gt; self.balance: raise ValueError(\u0026#34;余额不足\u0026#34;) self.balance -= amount class SavingsAccount(Account): \u0026#34;\u0026#34;\u0026#34;储蓄账户：有利息\u0026#34;\u0026#34;\u0026#34; def __init__(self, balance, interest_rate): super().__init__(balance) self.interest_rate = interest_rate def add_interest(self): interest = self.balance * self.interest_rate self.balance += interest return interest class CheckingAccount(Account): \u0026#34;\u0026#34;\u0026#34;支票账户：有透支额度\u0026#34;\u0026#34;\u0026#34; def __init__(self, balance, overdraft_limit): super().__init__(balance) self.overdraft_limit = overdraft_limit def withdraw(self, amount): if amount \u0026gt; self.balance + self.overdraft_limit: raise ValueError(\u0026#34;超过透支额度\u0026#34;) self.balance -= amount def process_account(account: Account, withdraw_amount): \u0026#34;\u0026#34;\u0026#34;处理账户提款（多态）\u0026#34;\u0026#34;\u0026#34; try: account.withdraw(withdraw_amount) print(f\u0026#34;成功取款 {withdraw_amount}，余额：{account.balance}\u0026#34;) except ValueError as e: print(f\u0026#34;取款失败：{e}\u0026#34;) # 测试 savings = SavingsAccount(1000, 0.03) checking = CheckingAccount(1000, 500) process_account(savings, 200) # 余额不足 # 等等，这个设计有问题...让我们修正 savings.deposit = lambda x: setattr(savings, \u0026#39;balance\u0026#39;, savings.balance + x) if hasattr(savings, \u0026#39;deposit\u0026#39;) else None 练习 2：图形编辑器 from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def draw(self): pass @abstractmethod def move(self, dx, dy): pass class Circle(Shape): def __init__(self, x, y, radius): self.x = x self.y = y self.radius = radius def draw(self): print(f\u0026#34;绘制圆形：圆心({self.x},{self.y})，半径{self.radius}\u0026#34;) def move(self, dx, dy): self.x += dx self.y += dy print(f\u0026#34;移动圆形到：({self.x},{self.y})\u0026#34;) class Rectangle(Shape): def __init__(self, x, y, width, height): self.x = x self.y = y self.width = width self.height = height def draw(self): print(f\u0026#34;绘制矩形：左上角({self.x},{self.y})，宽{self.width}，高{self.height}\u0026#34;) def move(self, dx, dy): self.x += dx self.y += dy print(f\u0026#34;移动矩形到：({self.x},{self.y})\u0026#34;) class Canvas: def __init__(self): self.shapes = [] def add_shape(self, shape: Shape): self.shapes.append(shape) def draw_all(self): for shape in self.shapes: shape.draw() def move_all(self, dx, dy): for shape in self.shapes: shape.move(dx, dy) # 测试 canvas = Canvas() canvas.add_shape(Circle(0, 0, 5)) canvas.add_shape(Rectangle(10, 10, 20, 15)) canvas.draw_all() # 绘制圆形：圆心(0,0)，半径5 # 绘制矩形：左上角(10,10)，宽20，高15 print() canvas.move_all(5, 5) # 移动圆形到：(5,5) # 移动矩形到：(15,15) 练习 3：通知系统 from abc import ABC, abstractmethod class Notifier(ABC): @abstractmethod def send(self, message): pass class EmailNotifier(Notifier): def __init__(self, email): self.email = email def send(self, message): print(f\u0026#34;发送邮件到 {self.email}：{message}\u0026#34;) class SMSNotifier(Notifier): def __init__(self, phone): self.phone = phone def send(self, message): print(f\u0026#34;发送短信到 {self.phone}：{message}\u0026#34;) class WeChatNotifier(Notifier): def __init__(self, openid): self.openid = openid def send(self, message): print(f\u0026#34;发送微信到 {self.openid}：{message}\u0026#34;) class NotificationService: def __init__(self): self.notifiers = [] def add_notifier(self, notifier: Notifier): self.notifiers.append(notifier) def notify(self, message): for notifier in self.notifiers: notifier.send(message) # 测试 service = NotificationService() service.add_notifier(EmailNotifier(\u0026#34;user@example.com\u0026#34;)) service.add_notifier(SMSNotifier(\u0026#34;13800138000\u0026#34;)) service.add_notifier(WeChatNotifier(\u0026#34;wx_openid_123\u0026#34;)) service.notify(\u0026#34;您的订单已发货！\u0026#34;) # 发送邮件到 user@example.com：您的订单已发货！ # 发送短信到 13800138000：您的订单已发货！ # 发送微信到 wx_openid_123：您的订单已发货！ 总结 多态和鸭子类型是 Python 面向对象编程的核心概念：\n多态：同一种操作在不同对象上产生不同行为 鸭子类型：关注对象的行为而非类型 抽象基类：通过 @abstractmethod 定义接口规范 Protocol：Python 3.8+ 的结构子类型支持 设计模式：多态是策略模式、访问者模式等的基础 Python 的多态是动态的、运行时决定的，这使得代码更加灵活。在下一节中，我们将学习 @classmethod 装饰器。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-27-polymorphism-duck-typing/","summary":"\u003ch1 id=\"day-27---多态与鸭子类型\"\u003eDay 27 - 多态与鸭子类型\u003c/h1\u003e\n\u003ch2 id=\"什么是多态\"\u003e什么是多态？\u003c/h2\u003e\n\u003cp\u003e多态（Polymorphism）是面向对象编程的三大基本特性之一，意思是\u0026quot;多种形态\u0026quot;。在 Python 中，多态指的是同一种操作（如调用同一个方法）在不同类型的对象上会产生不同的行为。\u003c/p\u003e\n\u003cp\u003e多态的核心思想是：关注对象的\u0026quot;行为\u0026quot;而非\u0026quot;类型\u0026quot;。当我们调用一个对象的方法时，不需要关心这个对象是什么类型的具体类，只需要知道它支持这个方法即可。这大大增强了代码的灵活性和可扩展性。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eDog\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003espeak\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;汪汪汪\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eCat\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003espeak\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;喵喵喵\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eDuck\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003espeak\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;嘎嘎嘎\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 多态：同一个方法调用，不同对象产生不同行为\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eanimals \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [Dog(), Cat(), Duck()]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e animal \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e animals:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eanimal\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e__class__\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e__name__\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 说：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eanimal\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003espeak()\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 输出：\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Dog 说：汪汪汪\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Cat 说：喵喵喵\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Duck 说：嘎嘎嘎\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"python-中的多态实现\"\u003ePython 中的多态实现\u003c/h2\u003e\n\u003cp\u003ePython 是动态类型语言，天生支持多态。在静态类型语言（如 Java、C++）中，多态需要通过继承和接口来实现。但在 Python 中，任何定义了 \u003ccode\u003espeak()\u003c/code\u003e 方法的对象都可以被调用，而不需要继承关系。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePeople\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003espeak\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;你好！\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eBird\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003espeak\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;叽叽喳喳\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emake_speak\u003c/span\u003e(obj):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;多态函数：接收任何有 speak 方法的对象\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(obj\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003espeak())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eperson \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e People()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebird \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Bird()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emake_speak(person)  \u003cspan style=\"color:#75715e\"\u003e# 你好！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emake_speak(bird)    \u003cspan style=\"color:#75715e\"\u003e# 叽叽喳喳\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"抽象基类与多态\"\u003e抽象基类与多态\u003c/h2\u003e\n\u003cp\u003e虽然 Python 不强制使用抽象基类，但抽象基类（ABC）提供了一种方式来定义接口规范，确保子类实现了必要的方法。这在大型项目中很有用。\u003c/p\u003e","tags":"Python, 编程","title":"Day 27 - 多态与鸭子类型"},{"columns":"python-course","content":"Day 28 - @classmethod 装饰器详解 什么是类方法？ 类方法（Class Method）是绑定到类而不是实例的方法。类方法使用 @classmethod 装饰器装饰，第一个参数是类本身（通常命名为 cls），而不是实例（self）。\n类方法的主要用途包括：\n工厂方法：创建类的实例的不同方式 访问或修改类属性 不依赖于特定实例的功能 class MyClass: class_attr = \u0026#34;类属性值\u0026#34; def __init__(self, value): self.instance_attr = value @classmethod def class_method(cls): \u0026#34;\u0026#34;\u0026#34;类方法\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;类方法被调用\u0026#34;) print(f\u0026#34;cls 是：{cls}\u0026#34;) print(f\u0026#34;cls.class_attr = {cls.class_attr}\u0026#34;) return cls(\u0026#34;通过类方法创建\u0026#34;) # 可以使用 cls 创建实例 # 通过类调用类方法 MyClass.class_method() # 类方法被调用 # cls 是：\u0026lt;class \u0026#39;__main__.MyClass\u0026#39;\u0026gt; # cls.class_attr = 类属性值 # 通过实例调用类方法（不推荐，但可以） obj = MyClass(\u0026#34;实例值\u0026#34;) obj.class_method() # cls 仍然是 MyClass，不是 obj 的类 实例方法 vs 类方法 vs 静态方法 Python 中有三种类型的方法：\n实例方法：第一个参数是 self，只能通过实例调用 类方法：第一个参数是 cls，可以通过类或实例调用 静态方法：没有任何默认参数，可以通过类或实例调用 class Example: class_attr = \u0026#34;类属性\u0026#34; def __init__(self, value): self.value = value def instance_method(self): \u0026#34;\u0026#34;\u0026#34;实例方法：可以访问 self 和类\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;实例方法，value={self.value}\u0026#34; @classmethod def class_method(cls): \u0026#34;\u0026#34;\u0026#34;类方法：可以访问类属性，不能访问实例属性\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;类方法，class_attr={cls.class_attr}\u0026#34; @staticmethod def static_method(): \u0026#34;\u0026#34;\u0026#34;静态方法：不能访问 self 或 cls\u0026#34;\u0026#34;\u0026#34; return \u0026#34;静态方法\u0026#34; # 调用方式 obj = Example(\u0026#34;test\u0026#34;) print(Example.instance_method(obj)) # 实例方法，value=test print(obj.instance_method()) # 实例方法，value=test print(Example.class_method()) # 类方法，class_attr=类属性 print(obj.class_method()) # 类方法，class_attr=类属性 print(Example.static_method()) # 静态方法 print(obj.static_method()) # 静态方法 工厂方法模式 类方法最常见的用途是实现工厂方法（Factory Method），即用不同的方式创建类的实例。这比直接在 __init__ 中添加大量可选参数更加清晰和可扩展。\nimport math class Point: \u0026#34;\u0026#34;\u0026#34;点类\u0026#34;\u0026#34;\u0026#34; def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return f\u0026#34;Point({self.x}, {self.y})\u0026#34; @classmethod def from_cartesian(cls, x, y): \u0026#34;\u0026#34;\u0026#34;从笛卡尔坐标创建点\u0026#34;\u0026#34;\u0026#34; return cls(x, y) @classmethod def from_polar(cls, r, theta): \u0026#34;\u0026#34;\u0026#34;从极坐标创建点（弧度）\u0026#34;\u0026#34;\u0026#34; x = r * math.cos(theta) y = r * math.sin(theta) return cls(x, y) @classmethod def from_tuple(cls, coords): \u0026#34;\u0026#34;\u0026#34;从元组创建点\u0026#34;\u0026#34;\u0026#34; return cls(coords[0], coords[1]) @classmethod def origin(cls): \u0026#34;\u0026#34;\u0026#34;创建原点\u0026#34;\u0026#34;\u0026#34; return cls(0, 0) # 使用不同的工厂方法创建点 p1 = Point.from_cartesian(3, 4) p2 = Point.from_polar(5, math.atan2(4, 3)) # 距离5，角度 arctan(4/3) p3 = Point.from_tuple((1, 2)) p4 = Point.origin() print(p1) # Point(3.0, 4.0) print(p2) # Point(4.999999999999999, 3.0000000000000004) ≈ Point(5, 3) print(p3) # Point(1, 2) print(p4) # Point(0, 0) 替代构造函数 类方法可以提供多个构造函数，让类的使用者以不同的方式创建实例。\nfrom datetime import datetime class Person: def __init__(self, name, birth_year, birth_month, birth_day): self.name = name self.birth_date = datetime(birth_year, birth_month, birth_day) @classmethod def from_birthday_string(cls, name, birthday_str): \u0026#34;\u0026#34;\u0026#34;从 \u0026#39;YYYY-MM-DD\u0026#39; 格式的字符串创建\u0026#34;\u0026#34;\u0026#34; parts = birthday_str.split(\u0026#39;-\u0026#39;) if len(parts) != 3: raise ValueError(\u0026#34;日期格式必须是 YYYY-MM-DD\u0026#34;) year, month, day = map(int, parts) return cls(name, year, month, day) @classmethod def from_age(cls, name, age): \u0026#34;\u0026#34;\u0026#34;从年龄创建（假设今年生日已过）\u0026#34;\u0026#34;\u0026#34; current_year = datetime.now().year birth_year = current_year - age return cls(name, birth_year, 1, 1) # 假设1月1日出生 def age(self): \u0026#34;\u0026#34;\u0026#34;计算年龄\u0026#34;\u0026#34;\u0026#34; today = datetime.now() age = today.year - self.birth_date.year if (today.month, today.day) \u0026lt; (self.birth_date.month, self.birth_date.day): age -= 1 return age def __repr__(self): return f\u0026#34;Person(name={self.name}, birth={self.birth_date.date()}, age={self.age()})\u0026#34; # 使用 p1 = Person(\u0026#34;张三\u0026#34;, 1990, 5, 15) p2 = Person.from_birthday_string(\u0026#34;李四\u0026#34;, \u0026#34;1995-08-20\u0026#34;) p3 = Person.from_age(\u0026#34;王五\u0026#34;, 25) print(p1) # Person(name=张三, birth=1990-05-15, age=34) print(p2) # Person(name=李四, birth=1995-08-20, age=28) print(p3) # Person(name=王五, birth=1999-01-01, age=25) 类方法与类属性 类方法可以访问和修改类属性，但不能直接访问实例属性。\nclass Counter: count = 0 # 类属性 instances = [] # 存储所有实例 def __init__(self, name): self.name = name Counter.count += 1 Counter.instances.append(self) @classmethod def get_count(cls): \u0026#34;\u0026#34;\u0026#34;获取创建的实例数量\u0026#34;\u0026#34;\u0026#34; return cls.count @classmethod def get_instances(cls): \u0026#34;\u0026#34;\u0026#34;获取所有实例\u0026#34;\u0026#34;\u0026#34; return cls.instances.copy() @classmethod def reset_counter(cls): \u0026#34;\u0026#34;\u0026#34;重置计数器\u0026#34;\u0026#34;\u0026#34; cls.count = 0 cls.instances = [] # 测试 print(f\u0026#34;当前计数：{Counter.get_count()}\u0026#34;) # 0 c1 = Counter(\u0026#34;实例1\u0026#34;) c2 = Counter(\u0026#34;实例2\u0026#34;) c3 = Counter(\u0026#34;实例3\u0026#34;) print(f\u0026#34;当前计数：{Counter.get_count()}\u0026#34;) # 3 print(f\u0026#34;所有实例：{Counter.get_instances()}\u0026#34;) # 通过实例调用类方法 print(c1.get_count()) # 3 # 重置 Counter.reset_counter() print(f\u0026#34;重置后计数：{Counter.get_count()}\u0026#34;) # 0 类方法继承 类方法可以被继承，子类继承父类的类方法时，cls 参数会自动变成子类。\nclass Base: @classmethod def factory(cls): obj = cls() obj.created_by = cls.__name__ return obj class Derived(Base): pass # 测试 base_obj = Base.factory() print(f\u0026#34;base_obj.created_by = {base_obj.created_by}\u0026#34;) # Base print(f\u0026#34;type = {type(base_obj)}\u0026#34;) # \u0026lt;class \u0026#39;__main__.Base\u0026#39;\u0026gt; derived_obj = Derived.factory() print(f\u0026#34;derived_obj.created_by = {derived_obj.created_by}\u0026#34;) # Derived print(f\u0026#34;type = {type(derived_obj)}\u0026#34;) # \u0026lt;class \u0026#39;__main__.Derived\u0026#39;\u0026gt; 类方法在单例模式中的应用 单例模式（Singleton Pattern）确保一个类只有一个实例。类方法可以实现线程安全的单例模式。\nclass Singleton: _instance = None def __init__(self): if Singleton._instance is not None: raise RuntimeError(\u0026#34;请使用 get_instance() 方法获取实例\u0026#34;) @classmethod def get_instance(cls): \u0026#34;\u0026#34;\u0026#34;获取单例实例\u0026#34;\u0026#34;\u0026#34; if cls._instance is None: cls._instance = cls.__new__(cls) cls._instance._initialized = False return cls._instance def __init__(self): if not self._initialized: self.value = None self._initialized = True def set_value(self, value): self.value = value def get_value(self): return self.value # 测试 s1 = Singleton.get_instance() s2 = Singleton.get_instance() print(f\u0026#34;s1 is s2: {s1 is s2}\u0026#34;) # True print(f\u0026#34;s1.value: {s1.get_value()}\u0026#34;) s1.set_value(42) print(f\u0026#34;s2.value: {s2.get_value()}\u0026#34;) # 42 # 尝试直接创建实例会报错 try: s3 = Singleton() # RuntimeError except RuntimeError as e: print(f\u0026#34;错误：{e}\u0026#34;) 类方法与不可变对象 类方法对于创建不可变对象特别有用，因为可以在类方法中控制对象的创建过程。\nclass Color: \u0026#34;\u0026#34;\u0026#34;不可变颜色类\u0026#34;\u0026#34;\u0026#34; __slots__ = (\u0026#39;_r\u0026#39;, \u0026#39;_g\u0026#39;, \u0026#39;_b\u0026#39;) def __init__(self, r, g, b): if not all(0 \u0026lt;= v \u0026lt;= 255 for v in (r, g, b)): raise ValueError(\u0026#34;RGB 值必须在 0-255 之间\u0026#34;) self._r = r self._g = g self._b = b @classmethod def from_hex(cls, hex_string): \u0026#34;\u0026#34;\u0026#34;从十六进制字符串创建颜色\u0026#34;\u0026#34;\u0026#34; hex_string = hex_string.lstrip(\u0026#39;#\u0026#39;) if len(hex_string) != 6: raise ValueError(\u0026#34;十六进制颜色必须是 #RRGGBB 格式\u0026#34;) try: r, g, b = tuple(int(hex_string[i:i+2], 16) for i in (0, 2, 4)) except ValueError: raise ValueError(\u0026#34;无效的十六进制值\u0026#34;) return cls(r, g, b) @classmethod def from_hsv(cls, h, s, v): \u0026#34;\u0026#34;\u0026#34;从 HSV 创建颜色\u0026#34;\u0026#34;\u0026#34; import math c = v * s x = c * (1 - abs((h / 60) % 2 - 1)) m = v - c if 0 \u0026lt;= h \u0026lt; 60: r, g, b = c, x, 0 elif 60 \u0026lt;= h \u0026lt; 120: r, g, b = x, c, 0 elif 120 \u0026lt;= h \u0026lt; 180: r, g, b = 0, c, x elif 180 \u0026lt;= h \u0026lt; 240: r, g, b = 0, x, c elif 240 \u0026lt;= h \u0026lt; 300: r, g, b = x, 0, c else: r, g, b = c, 0, x return cls(int((r + m) * 255), int((g + m) * 255), int((b + m) * 255)) def to_hex(self): \u0026#34;\u0026#34;\u0026#34;转换为十六进制字符串\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;#{self._r:02x}{self._g:02x}{self._b:02x}\u0026#34; def __repr__(self): return f\u0026#34;Color({self._r}, {self._g}, {self._b})\u0026#34; # 测试 red = Color(255, 0, 0) print(red) # Color(255, 0, 0) blue = Color.from_hex(\u0026#34;#0000FF\u0026#34;) print(blue) # Color(0, 0, 255) green = Color.from_hsv(120, 1, 1) print(green) # Color(0, 255, 0) print(green.to_hex()) # #00ff00 练习题 练习 1：分数类 from math import gcd class Fraction: \u0026#34;\u0026#34;\u0026#34;分数类\u0026#34;\u0026#34;\u0026#34; def __init__(self, numerator, denominator=1): if denominator == 0: raise ValueError(\u0026#34;分母不能为零\u0026#34;) g = gcd(abs(numerator), abs(denominator)) self._numerator = numerator // g self._denominator = denominator // g if self._denominator \u0026lt; 0: self._numerator = -self._numerator self._denominator = -self._denominator @classmethod def from_decimal(cls, decimal, precision=1000000): \u0026#34;\u0026#34;\u0026#34;从小数创建分数（使用给定精度）\u0026#34;\u0026#34;\u0026#34; # 将小数转换为整数和分母 numerator = int(decimal * precision) denominator = precision return cls(numerator, denominator) @classmethod def from_string(cls, s): \u0026#34;\u0026#34;\u0026#34;从字符串创建分数，如 \u0026#39;3/4\u0026#39; 或 \u0026#39;5\u0026#39;\u0026#34;\u0026#34;\u0026#34; s = s.strip() if \u0026#39;/\u0026#39; in s: num, den = s.split(\u0026#39;/\u0026#39;) return cls(int(num.strip()), int(den.strip())) else: return cls(int(s)) def __repr__(self): if self._denominator == 1: return f\u0026#34;Fraction({self._numerator})\u0026#34; return f\u0026#34;Fraction({self._numerator}/{self._denominator})\u0026#34; def __str__(self): if self._denominator == 1: return str(self._numerator) return f\u0026#34;{self._numerator}/{self._denominator}\u0026#34; def __eq__(self, other): if isinstance(other, int): other = Fraction(other) if not isinstance(other, Fraction): return False return (self._numerator == other._numerator and self._denominator == other._denominator) # 测试 f1 = Fraction(3, 6) # 自动简化为 1/2 f2 = Fraction.from_decimal(0.5) f3 = Fraction.from_string(\u0026#34;1/2\u0026#34;) f4 = Fraction.from_string(\u0026#34;3\u0026#34;) print(f1) # 1/2 print(f2) # 500000/1000000 print(f3) # 1/2 print(f4) # 3 print(f1 == f2) # False（但值相同） 练习 2：配置管理器 import json from pathlib import Path class Config: \u0026#34;\u0026#34;\u0026#34;配置管理器\u0026#34;\u0026#34;\u0026#34; _instance = None _config = {} def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance def __init__(self): self._initialized = False @classmethod def load_from_file(cls, filepath): \u0026#34;\u0026#34;\u0026#34;从文件加载配置\u0026#34;\u0026#34;\u0026#34; path = Path(filepath) if not path.exists(): raise FileNotFoundError(f\u0026#34;配置文件不存在：{filepath}\u0026#34;) with open(path, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: config_dict = json.load(f) instance = cls() instance._config = config_dict instance._initialized = True return instance @classmethod def load_from_dict(cls, config_dict): \u0026#34;\u0026#34;\u0026#34;从字典加载配置\u0026#34;\u0026#34;\u0026#34; instance = cls() instance._config = config_dict instance._initialized = True return instance @classmethod def get_instance(cls): \u0026#34;\u0026#34;\u0026#34;获取配置实例\u0026#34;\u0026#34;\u0026#34; if cls._instance is None or not cls._instance._initialized: raise RuntimeError(\u0026#34;配置未初始化，请先调用 load_from_file 或 load_from_dict\u0026#34;) return cls._instance def get(self, key, default=None): \u0026#34;\u0026#34;\u0026#34;获取配置值\u0026#34;\u0026#34;\u0026#34; keys = key.split(\u0026#39;.\u0026#39;) value = self._config for k in keys: if isinstance(value, dict): value = value.get(k) if value is None: return default else: return default return value def __getitem__(self, key): \u0026#34;\u0026#34;\u0026#34;支持字典式访问\u0026#34;\u0026#34;\u0026#34; value = self.get(key) if value is None: raise KeyError(f\u0026#34;配置项不存在：{key}\u0026#34;) return value # 测试 config_data = { \u0026#34;database\u0026#34;: { \u0026#34;host\u0026#34;: \u0026#34;localhost\u0026#34;, \u0026#34;port\u0026#34;: 3306, \u0026#34;name\u0026#34;: \u0026#34;testdb\u0026#34; }, \u0026#34;app\u0026#34;: { \u0026#34;debug\u0026#34;: True, \u0026#34;port\u0026#34;: 8080 } } config = Config.load_from_dict(config_data) print(config.get(\u0026#34;database.host\u0026#34;)) # localhost print(config.get(\u0026#34;app.debug\u0026#34;)) # True print(config.get(\u0026#34;nonexistent\u0026#34;, \u0026#34;default\u0026#34;)) # default 练习 3：事件系统 class Event: \u0026#34;\u0026#34;\u0026#34;事件类\u0026#34;\u0026#34;\u0026#34; def __init__(self, name, **kwargs): self.name = name self.data = kwargs self.timestamp = None def __repr__(self): return f\u0026#34;Event({self.name}, {self.data})\u0026#34; class EventEmitter: \u0026#34;\u0026#34;\u0026#34;事件发射器\u0026#34;\u0026#34;\u0026#34; def __init__(self): self._listeners = {} def on(self, event_name, listener): \u0026#34;\u0026#34;\u0026#34;注册事件监听器\u0026#34;\u0026#34;\u0026#34; if event_name not in self._listeners: self._listeners[event_name] = [] self._listeners[event_name].append(listener) return listener # 返回监听器，方便后续移除 def off(self, event_name, listener): \u0026#34;\u0026#34;\u0026#34;移除事件监听器\u0026#34;\u0026#34;\u0026#34; if event_name in self._listeners: self._listeners[event_name].remove(listener) def emit(self, event): \u0026#34;\u0026#34;\u0026#34;发射事件\u0026#34;\u0026#34;\u0026#34; if isinstance(event, str): event = Event(event) if event.name in self._listeners: for listener in self._listeners[event.name]: listener(event) # 也触发 \u0026#39;*\u0026#39; 监听器 if \u0026#39;*\u0026#39; in self._listeners: for listener in self._listeners[\u0026#39;*\u0026#39;]: listener(event) @classmethod def create_with_handlers(cls, handlers): \u0026#34;\u0026#34;\u0026#34;工厂方法：从处理器字典创建发射器\u0026#34;\u0026#34;\u0026#34; emitter = cls() for event_name, handler in handlers.items(): emitter.on(event_name, handler) return emitter # 使用 def on_click(event): print(f\u0026#34;点击事件：按钮={event.data.get(\u0026#39;button\u0026#39;)}\u0026#34;) def on_keypress(event): print(f\u0026#34;按键事件：键={event.data.get(\u0026#39;key\u0026#39;)}\u0026#34;) def on_any(event): print(f\u0026#34;任意事件：{event.name}\u0026#34;) emitter = EventEmitter.create_with_handlers({ \u0026#39;click\u0026#39;: on_click, \u0026#39;keypress\u0026#39;: on_keypress, \u0026#39;*\u0026#39;: on_any }) emitter.emit(Event(\u0026#39;click\u0026#39;, button=\u0026#39;submit\u0026#39;)) emitter.emit(Event(\u0026#39;keypress\u0026#39;, key=\u0026#39;Enter\u0026#39;)) emitter.emit(\u0026#39;custom_event\u0026#39;) # 输出： # 点击事件：按钮=submit # 任意事件：Event(click, {\u0026#39;button\u0026#39;: \u0026#39;submit\u0026#39;}) # 按键事件：键=Enter # 任意事件：Event(keypress, {\u0026#39;key\u0026#39;: \u0026#39;Enter\u0026#39;}) # 任意事件：Event(custom_event, {}) 总结 @classmethod 是 Python 中重要的装饰器：\n第一个参数是 cls：指向类本身，而非实例 可用于创建工厂方法：提供多种方式创建实例 可访问类属性：但不能直接访问实例属性 可被继承：子类调用时 cls 是子类 应用场景：替代构造函数、单例模式、配置管理等 在下一节中，我们将学习 @staticmethod 装饰器和单例模式的更多内容。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-28-classmethod/","summary":"\u003ch1 id=\"day-28---classmethod-装饰器详解\"\u003eDay 28 - @classmethod 装饰器详解\u003c/h1\u003e\n\u003ch2 id=\"什么是类方法\"\u003e什么是类方法？\u003c/h2\u003e\n\u003cp\u003e类方法（Class Method）是绑定到类而不是实例的方法。类方法使用 \u003ccode\u003e@classmethod\u003c/code\u003e 装饰器装饰，第一个参数是类本身（通常命名为 \u003ccode\u003ecls\u003c/code\u003e），而不是实例（\u003ccode\u003eself\u003c/code\u003e）。\u003c/p\u003e\n\u003cp\u003e类方法的主要用途包括：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e工厂方法：创建类的实例的不同方式\u003c/li\u003e\n\u003cli\u003e访问或修改类属性\u003c/li\u003e\n\u003cli\u003e不依赖于特定实例的功能\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eMyClass\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    class_attr \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;类属性值\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e __init__(self, value):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003einstance_attr \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e value\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@classmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass_method\u003c/span\u003e(cls):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;类方法\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;类方法被调用\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;cls 是：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecls\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;cls.class_attr = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecls\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eclass_attr\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e cls(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;通过类方法创建\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 可以使用 cls 创建实例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 通过类调用类方法\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eMyClass\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eclass_method()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 类方法被调用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# cls 是：\u0026lt;class \u0026#39;__main__.MyClass\u0026#39;\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# cls.class_attr = 类属性值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 通过实例调用类方法（不推荐，但可以）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eobj \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e MyClass(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;实例值\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eobj\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eclass_method()  \u003cspan style=\"color:#75715e\"\u003e# cls 仍然是 MyClass，不是 obj 的类\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"实例方法-vs-类方法-vs-静态方法\"\u003e实例方法 vs 类方法 vs 静态方法\u003c/h2\u003e\n\u003cp\u003ePython 中有三种类型的方法：\u003c/p\u003e","tags":"Python, 编程","title":"Day 28 - @classmethod 装饰器详解"},{"columns":"python-course","content":"Day 29 - @staticmethod 装饰器与单例模式 什么是静态方法？ 静态方法（Static Method）是使用 @staticmethod 装饰器装饰的方法。它不需要 self 或 cls 参数，可以像普通函数一样定义，但在类内部定义，属于类的命名空间。\n静态方法的主要用途：\n将一些与类相关的功能封装在类内部，使代码更组织化 不需要访问类属性或实例属性的功能 可以被子类继承（但不能通过 super() 调用父类的静态方法） class MathUtils: \u0026#34;\u0026#34;\u0026#34;数学工具类\u0026#34;\u0026#34;\u0026#34; @staticmethod def add(a, b): \u0026#34;\u0026#34;\u0026#34;加法\u0026#34;\u0026#34;\u0026#34; return a + b @staticmethod def multiply(a, b): \u0026#34;\u0026#34;\u0026#34;乘法\u0026#34;\u0026#34;\u0026#34; return a * b @staticmethod def is_prime(n): \u0026#34;\u0026#34;\u0026#34;判断素数\u0026#34;\u0026#34;\u0026#34; if n \u0026lt; 2: return False for i in range(2, int(n**0.5) + 1): if n % i == 0: return False return True # 调用静态方法 print(MathUtils.add(3, 5)) # 8 print(MathUtils.multiply(4, 7)) # 28 print(MathUtils.is_prime(17)) # True print(MathUtils.is_prime(15)) # False # 也可以通过实例调用 utils = MathUtils() print(utils.add(2, 3)) # 5 三种方法的对比 class Example: class_attr = \u0026#34;类属性\u0026#34; def __init__(self, value): self.value = value def instance_method(self): \u0026#34;\u0026#34;\u0026#34;实例方法：需要 self\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;实例方法，value={self.value}\u0026#34; @classmethod def class_method(cls): \u0026#34;\u0026#34;\u0026#34;类方法：需要 cls\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;类方法，class_attr={cls.class_attr}\u0026#34; @staticmethod def static_method(): \u0026#34;\u0026#34;\u0026#34;静态方法：不需要 self 或 cls\u0026#34;\u0026#34;\u0026#34; return \u0026#34;静态方法，不依赖类或实例\u0026#34; # 对比 obj = Example(\u0026#34;test\u0026#34;) # 实例方法：需要实例调用 print(obj.instance_method()) # Example.instance_method(obj) # 需要显式传递实例 # 类方法：类或实例都可以调用 print(Example.class_method()) print(obj.class_method()) # 静态方法：类或实例都可以调用 print(Example.static_method()) print(obj.static_method()) 静态方法与命名空间 静态方法的一个重要作用是将相关的函数组织在类的命名空间中，避免污染全局命名空间。\nimport math # 不推荐：所有函数都在全局命名空间 def calculate_circle_area(r): return math.pi * r ** 2 def calculate_circle_circumference(r): return 2 * math.pi * r # 推荐：将相关函数组织在类中 class Circle: def __init__(self, radius): self.radius = radius @staticmethod def area(radius): \u0026#34;\u0026#34;\u0026#34;计算圆面积\u0026#34;\u0026#34;\u0026#34; return math.pi * radius ** 2 @staticmethod def circumference(radius): \u0026#34;\u0026#34;\u0026#34;计算圆周长\u0026#34;\u0026#34;\u0026#34; return 2 * math.pi * radius def total_area(self, other): \u0026#34;\u0026#34;\u0026#34;计算两个圆的总面积\u0026#34;\u0026#34;\u0026#34; return Circle.area(self.radius) + Circle.area(other.radius) c1 = Circle(5) c2 = Circle(3) # 静态方法可以直接通过类调用 print(Circle.area(5)) # 78.54 print(Circle.circumference(5)) # 31.42 # 也可以通过实例调用 print(c1.area(5)) # 78.54 # 在实例方法中调用静态方法 print(c1.total_area(c2)) # 98.96 静态方法与继承 静态方法可以被继承，但调用方式与类方法不同。\nclass Base: @staticmethod def static_method(): print(\u0026#34;Base.static_method\u0026#34;) class Derived(Base): @staticmethod def static_method(): print(\u0026#34;Derived.static_method\u0026#34;) # 测试 Base.static_method() # Base.static_method Derived.static_method() # Derived.static_method base = Base() base.static_method() # Base.static_method derived = Derived() derived.static_method() # Derived.static_method # 通过子类调用父类的静态方法（不推荐） base.static_method() # 仍然是 Base 的版本 单例模式详解 单例模式（Singleton Pattern）是一种设计模式，确保一个类只有一个实例，并提供一个全局访问点。\n方法1：使用 __new__ class Singleton: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) cls._instance._initialized = False return cls._instance def __init__(self): if not self._initialized: self.data = None Singleton._instance._initialized = True def set_data(self, data): self.data = data def get_data(self): return self.data # 测试 s1 = Singleton() s2 = Singleton() print(s1 is s2) # True s1.set_data(42) print(s2.get_data()) # 42 方法2：使用装饰器 def singleton(cls): \u0026#34;\u0026#34;\u0026#34;单例装饰器\u0026#34;\u0026#34;\u0026#34; instances = {} def get_instance(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return get_instance @singleton class Database: def __init__(self, host, port): self.host = host self.port = port print(f\u0026#34;连接数据库：{host}:{port}\u0026#34;) # 测试 db1 = Database(\u0026#34;localhost\u0026#34;, 3306) db2 = Database(\u0026#34;remote\u0026#34;, 5432) print(db1 is db2) # True print(db1.host) # localhost print(db2.host) # localhost（来自第一次创建） 方法3：使用元类（Metaclass） class SingletonMeta(type): \u0026#34;\u0026#34;\u0026#34;单例元类\u0026#34;\u0026#34;\u0026#34; _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls] class Database(metaclass=SingletonMeta): def __init__(self, host, port): self.host = host self.port = port def query(self, sql): print(f\u0026#34;执行查询：{sql}\u0026#34;) # 测试 db1 = Database(\u0026#34;localhost\u0026#34;, 3306) db2 = Database(\u0026#34;remote\u0026#34;, 5432) print(db1 is db2) # True db1.query(\u0026#34;SELECT * FROM users\u0026#34;) 方法4：使用模块 Python 的模块本身就是单例，因为模块只会被导入一次。\n# my_singleton.py class Singleton: def __init__(self): self.data = None _instance = Singleton() def get_instance(): return _instance # 在其他文件中使用 # from my_singleton import get_instance # db = get_instance() 单例模式的线程安全 基础的单例实现在多线程环境下可能有问题。使用线程锁可以解决这个问题。\nimport threading class ThreadSafeSingleton: _instance = None _lock = threading.Lock() def __new__(cls, *args, **kwargs): if cls._instance is None: with cls._lock: # 双重检查锁定 if cls._instance is None: cls._instance = super().__new__(cls) cls._instance._initialized = False return cls._instance def __init__(self, value=None): if not self._initialized: self.value = value ThreadSafeSingleton._instance._initialized = True # 测试多线程创建 def create_singleton(): s = ThreadSafeSingleton(\u0026#34;test\u0026#34;) print(f\u0026#34;线程创建的实例：{id(s)}, value={s.value}\u0026#34;) threads = [threading.Thread(target=create_singleton) for _ in range(5)] for t in threads: t.start() for t in threads: t.join() Borg 模式（共享状态单例） Borg 模式不是让所有实例都是同一个对象，而是让所有实例共享同一个状态。\nclass Borg: \u0026#34;\u0026#34;\u0026#34;Borg 模式：所有实例共享同一个状态\u0026#34;\u0026#34;\u0026#34; _shared_state = {} def __init__(self): self.__dict__ = self._shared_state if not hasattr(self, \u0026#39;initialized\u0026#39;): self.initialized = True self.data = None def set_data(self, data): self.data = data def get_data(self): return self.data # 测试 b1 = Borg() b2 = Borg() print(b1 is b2) # False（不同的对象） b1.set_data(42) print(b2.get_data()) # 42（共享状态） b2.data = \u0026#34;shared\u0026#34; print(b1.data) # shared 静态方法在实际项目中的应用 示例1：验证器 class Validator: \u0026#34;\u0026#34;\u0026#34;数据验证器\u0026#34;\u0026#34;\u0026#34; @staticmethod def is_valid_email(email): import re pattern = r\u0026#39;^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$\u0026#39; return re.match(pattern, email) is not None @staticmethod def is_valid_phone(phone): import re pattern = r\u0026#39;^1[3-9]\\d{9}$\u0026#39; return re.match(pattern, phone) is not None @staticmethod def is_valid_id_card(id_card): import re pattern = r\u0026#39;^\\d{17}[\\dXx]$\u0026#39; return re.match(pattern, id_card) is not None @staticmethod def validate_range(value, min_val, max_val): \u0026#34;\u0026#34;\u0026#34;验证值是否在指定范围内\u0026#34;\u0026#34;\u0026#34; return min_val \u0026lt;= value \u0026lt;= max_val # 使用 print(Validator.is_valid_email(\u0026#34;user@example.com\u0026#34;)) # True print(Validator.is_valid_email(\u0026#34;invalid-email\u0026#34;)) # False print(Validator.is_valid_phone(\u0026#34;13800138000\u0026#34;)) # True print(Validator.is_valid_id_card(\u0026#34;11010119900101123X\u0026#34;)) # True print(Validator.validate_range(5, 1, 10)) # True 示例2：转换工具 class Converter: \u0026#34;\u0026#34;\u0026#34;数据转换工具\u0026#34;\u0026#34;\u0026#34; @staticmethod def celsius_to_fahrenheit(c): return c * 9/5 + 32 @staticmethod def fahrenheit_to_celsius(f): return (f - 32) * 5/9 @staticmethod def meters_to_feet(m): return m * 3.28084 @staticmethod def feet_to_meters(ft): return ft / 3.28084 @staticmethod def kg_to_pounds(kg): return kg * 2.20462 @staticmethod def pounds_to_kg(lb): return lb / 2.20462 # 使用 print(f\u0026#34;25°C = {Converter.celsius_to_fahrenheit(25):.2f}°F\u0026#34;) print(f\u0026#34;77°F = {Converter.fahrenheit_to_celsius(77):.2f}°C\u0026#34;) print(f\u0026#34;100m = {Converter.meters_to_feet(100):.2f}ft\u0026#34;) print(f\u0026#34;328ft = {Converter.feet_to_meters(328):.2f}m\u0026#34;) 示例3：配置常量 class AppConfig: \u0026#34;\u0026#34;\u0026#34;应用配置常量\u0026#34;\u0026#34;\u0026#34; DEBUG = False TESTING = False PRODUCTION = True # 数据库配置 DB_HOST = \u0026#34;localhost\u0026#34; DB_PORT = 3306 DB_NAME = \u0026#34;myapp\u0026#34; # API 配置 API_VERSION = \u0026#34;v1\u0026#34; API_TIMEOUT = 30 @staticmethod def is_production(): return AppConfig.PRODUCTION @staticmethod def is_debug(): return AppConfig.DEBUG @classmethod def get_db_url(cls): \u0026#34;\u0026#34;\u0026#34;获取数据库 URL\u0026#34;\u0026#34;\u0026#34; return f\u0026#34;mysql://{cls.DB_HOST}:{cls.DB_PORT}/{cls.DB_NAME}\u0026#34; # 使用 print(f\u0026#34;运行环境：{\u0026#39;生产\u0026#39; if AppConfig.is_production() else \u0026#39;开发\u0026#39;}\u0026#34;) print(f\u0026#34;数据库URL：{AppConfig.get_db_url()}\u0026#34;) 练习题 练习 1：实现字符串工具类 class StringUtils: \u0026#34;\u0026#34;\u0026#34;字符串工具类\u0026#34;\u0026#34;\u0026#34; @staticmethod def reverse(s): \u0026#34;\u0026#34;\u0026#34;反转字符串\u0026#34;\u0026#34;\u0026#34; return s[::-1] @staticmethod def is_palindrome(s): \u0026#34;\u0026#34;\u0026#34;判断回文数\u0026#34;\u0026#34;\u0026#34; s = \u0026#39;\u0026#39;.join(c.lower() for c in s if c.isalnum()) return s == s[::-1] @staticmethod def count_vowels(s): \u0026#34;\u0026#34;\u0026#34;统计元音字母数量\u0026#34;\u0026#34;\u0026#34; vowels = set(\u0026#39;aeiouAEIOU\u0026#39;) return sum(1 for c in s if c in vowels) @staticmethod def remove_whitespace(s): \u0026#34;\u0026#34;\u0026#34;移除所有空白字符\u0026#34;\u0026#34;\u0026#34; return \u0026#39;\u0026#39;.join(c for c in s if not c.isspace()) @staticmethod def truncate(s, length, suffix=\u0026#34;...\u0026#34;): \u0026#34;\u0026#34;\u0026#34;截断字符串\u0026#34;\u0026#34;\u0026#34; if len(s) \u0026lt;= length: return s return s[:length - len(suffix)] + suffix # 测试 print(StringUtils.reverse(\u0026#34;hello\u0026#34;)) # olleh print(StringUtils.is_palindrome(\u0026#34;A man a plan a canal Panama\u0026#34;)) # True print(StringUtils.is_palindrome(\u0026#34;hello\u0026#34;)) # False print(StringUtils.count_vowels(\u0026#34;Hello World\u0026#34;)) # 3 print(StringUtils.remove_whitespace(\u0026#34; a b c \u0026#34;)) # abc print(StringUtils.truncate(\u0026#34;Hello, World!\u0026#34;, 8)) # Hello... 练习 2：实现简单的缓存（单例） class Cache: \u0026#34;\u0026#34;\u0026#34;简单的内存缓存（单例）\u0026#34;\u0026#34;\u0026#34; _instance = None _lock = threading.Lock() def __new__(cls): if cls._instance is None: with cls._lock: if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance def __init__(self): if not hasattr(self, \u0026#39;_data\u0026#39;): self._data = {} @staticmethod def get(key, default=None): \u0026#34;\u0026#34;\u0026#34;获取缓存值\u0026#34;\u0026#34;\u0026#34; instance = Cache() return instance._data.get(key, default) @staticmethod def set(key, value): \u0026#34;\u0026#34;\u0026#34;设置缓存值\u0026#34;\u0026#34;\u0026#34; instance = Cache() instance._data[key] = value @staticmethod def delete(key): \u0026#34;\u0026#34;\u0026#34;删除缓存值\u0026#34;\u0026#34;\u0026#34; instance = Cache() if key in instance._data: del instance._data[key] @staticmethod def clear(): \u0026#34;\u0026#34;\u0026#34;清空缓存\u0026#34;\u0026#34;\u0026#34; instance = Cache() instance._data.clear() @staticmethod def keys(): \u0026#34;\u0026#34;\u0026#34;获取所有缓存键\u0026#34;\u0026#34;\u0026#34; instance = Cache() return list(instance._data.keys()) import threading # 测试 Cache.set(\u0026#34;name\u0026#34;, \u0026#34;张三\u0026#34;) Cache.set(\u0026#34;age\u0026#34;, 25) print(Cache.get(\u0026#34;name\u0026#34;)) # 张三 print(Cache.get(\u0026#34;age\u0026#34;)) # 25 print(Cache.keys()) # [\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;] Cache.delete(\u0026#34;age\u0026#34;) print(Cache.keys()) # [\u0026#39;name\u0026#39;] # 多线程测试 def worker(): for i in range(10): Cache.set(f\u0026#34;key_{threading.current_thread().name}_{i}\u0026#34;, i*i) threads = [threading.Thread(target=worker, name=f\u0026#34;T{i}\u0026#34;) for i in range(3)] for t in threads: t.start() for t in threads: t.join() print(f\u0026#34;缓存条目数：{len(Cache.keys())}\u0026#34;) # 应该是 30 练习 3：实现类工厂 class Animal: \u0026#34;\u0026#34;\u0026#34;动物基类\u0026#34;\u0026#34;\u0026#34; pass class AnimalFactory: \u0026#34;\u0026#34;\u0026#34;动物工厂\u0026#34;\u0026#34;\u0026#34; _registry = {} @classmethod def register(cls, animal_type, animal_class): \u0026#34;\u0026#34;\u0026#34;注册动物类\u0026#34;\u0026#34;\u0026#34; cls._registry[animal_type] = animal_class @classmethod def create(cls, animal_type, *args, **kwargs): \u0026#34;\u0026#34;\u0026#34;创建动物实例\u0026#34;\u0026#34;\u0026#34; if animal_type not in cls._registry: raise ValueError(f\u0026#34;未知的动物类型：{animal_type}\u0026#34;) return cls._registry[animal_type](*args, **kwargs) @staticmethod def list_types(): \u0026#34;\u0026#34;\u0026#34;列出所有已注册的动物类型\u0026#34;\u0026#34;\u0026#34; return list(AnimalFactory._registry.keys()) class Dog(Animal): def __init__(self, name): self.name = name def speak(self): return \u0026#34;汪汪汪\u0026#34; class Cat(Animal): def __init__(self, name): self.name = name def speak(self): return \u0026#34;喵喵喵\u0026#34; # 注册动物类型 AnimalFactory.register(\u0026#34;dog\u0026#34;, Dog) AnimalFactory.register(\u0026#34;cat\u0026#34;, Cat) # 创建动物实例 dog = AnimalFactory.create(\u0026#34;dog\u0026#34;, \u0026#34;旺财\u0026#34;) cat = AnimalFactory.create(\u0026#34;cat\u0026#34;, \u0026#34;小白\u0026#34;) print(f\u0026#34;{dog.name}：{dog.speak()}\u0026#34;) # 旺财：汪汪汪 print(f\u0026#34;{cat.name}：{cat.speak()}\u0026#34;) # 小白：喵喵喵 print(f\u0026#34;已注册的动物类型：{AnimalFactory.list_types()}\u0026#34;) # [\u0026#39;dog\u0026#39;, \u0026#39;cat\u0026#39;] 总结 @staticmethod 和单例模式是 Python 面向对象编程的重要内容：\n静态方法：不需要 self 或 cls 的方法，用于组织相关功能 与类方法的对比：静态方法不能访问类属性或实例属性 单例模式：确保类只有一个实例 实现方式：__new__、装饰器、元类、模块 线程安全：多线程环境下需要注意线程安全 Borg 模式：共享状态的单例变体 在下一节中，我们将学习异常处理：try-except-else-finally。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-29-staticmethod-singleton/","summary":"\u003ch1 id=\"day-29---staticmethod-装饰器与单例模式\"\u003eDay 29 - @staticmethod 装饰器与单例模式\u003c/h1\u003e\n\u003ch2 id=\"什么是静态方法\"\u003e什么是静态方法？\u003c/h2\u003e\n\u003cp\u003e静态方法（Static Method）是使用 \u003ccode\u003e@staticmethod\u003c/code\u003e 装饰器装饰的方法。它不需要 \u003ccode\u003eself\u003c/code\u003e 或 \u003ccode\u003ecls\u003c/code\u003e 参数，可以像普通函数一样定义，但在类内部定义，属于类的命名空间。\u003c/p\u003e\n\u003cp\u003e静态方法的主要用途：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e将一些与类相关的功能封装在类内部，使代码更组织化\u003c/li\u003e\n\u003cli\u003e不需要访问类属性或实例属性的功能\u003c/li\u003e\n\u003cli\u003e可以被子类继承（但不能通过 \u003ccode\u003esuper()\u003c/code\u003e 调用父类的静态方法）\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eMathUtils\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;数学工具类\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eadd\u003c/span\u003e(a, b):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;加法\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e b\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emultiply\u003c/span\u003e(a, b):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;乘法\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e b\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eis_prime\u003c/span\u003e(n):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;判断素数\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e n \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, int(n\u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e0.5\u003c/span\u003e) \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e n \u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 调用静态方法\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(MathUtils\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eadd(\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e))      \u003cspan style=\"color:#75715e\"\u003e# 8\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(MathUtils\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emultiply(\u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e)) \u003cspan style=\"color:#75715e\"\u003e# 28\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(MathUtils\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eis_prime(\u003cspan style=\"color:#ae81ff\"\u003e17\u003c/span\u003e))   \u003cspan style=\"color:#75715e\"\u003e# True\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(MathUtils\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eis_prime(\u003cspan style=\"color:#ae81ff\"\u003e15\u003c/span\u003e))   \u003cspan style=\"color:#75715e\"\u003e# False\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 也可以通过实例调用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eutils \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e MathUtils()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(utils\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eadd(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"三种方法的对比\"\u003e三种方法的对比\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eExample\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    class_attr \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;类属性\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e __init__(self, value):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003evalue \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e value\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003einstance_method\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;实例方法：需要 self\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;实例方法，value=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003evalue\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@classmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass_method\u003c/span\u003e(cls):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;类方法：需要 cls\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;类方法，class_attr=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecls\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eclass_attr\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estatic_method\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;静态方法：不需要 self 或 cls\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;静态方法，不依赖类或实例\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 对比\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eobj \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Example(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;test\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 实例方法：需要实例调用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(obj\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003einstance_method())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Example.instance_method(obj)  # 需要显式传递实例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 类方法：类或实例都可以调用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(Example\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eclass_method())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(obj\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eclass_method())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 静态方法：类或实例都可以调用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(Example\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estatic_method())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(obj\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estatic_method())\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"静态方法与命名空间\"\u003e静态方法与命名空间\u003c/h2\u003e\n\u003cp\u003e静态方法的一个重要作用是将相关的函数组织在类的命名空间中，避免污染全局命名空间。\u003c/p\u003e","tags":"Python, 编程","title":"Day 29 - @staticmethod 装饰器与单例模式"},{"columns":"python-course","content":"Day 30 - 异常处理：try-except-else-finally 什么是异常？ 异常（Exception）是 Python 程序在运行过程中发生的错误。当异常发生时，程序会停止执行，并创建一个异常对象。如果异常没有被捕获和处理，程序会打印一个回溯（traceback）并终止。\nPython 的异常处理机制允许我们捕获异常并自定义处理方式，而不是让程序直接崩溃。这对于编写健壮的程序至关重要。\n# 常见的异常类型 print(10 / 0) # ZeroDivisionError: division by zero print(int(\u0026#34;abc\u0026#34;)) # ValueError: invalid literal for int() print([1, 2, 3][10]) # IndexError: list index out of range print({}[\u0026#34;key\u0026#34;]) # KeyError: \u0026#39;key\u0026#39; try-except 基本语法 try: # 可能发生异常的代码 result = 10 / 0 except ZeroDivisionError: # 处理 ZeroDivisionError 异常 print(\u0026#34;不能除以零！\u0026#34;) 完整的异常处理结构 try: # 可能发生异常的代码 num = int(input(\u0026#34;请输入一个数字：\u0026#34;)) result = 10 / num except ValueError: # 处理值错误（输入不是数字） print(\u0026#34;输入无效，请输入数字！\u0026#34;) except ZeroDivisionError: # 处理除以零错误 print(\u0026#34;不能除以零！\u0026#34;) else: # 只有在没有异常时才会执行 print(f\u0026#34;结果：{result}\u0026#34;) finally: # 无论是否有异常都会执行 print(\u0026#34;程序结束\u0026#34;) except 的多种写法 捕获特定异常 try: value = int(\u0026#34;abc\u0026#34;) except ValueError: print(\u0026#34;ValueError 被捕获\u0026#34;) try: lst = [1, 2, 3] value = lst[10] except IndexError: print(\u0026#34;IndexError 被捕获\u0026#34;) 捕获多种异常（方式1） try: value = int(\u0026#34;abc\u0026#34;) except (ValueError, TypeError): print(\u0026#34;ValueError 或 TypeError 被捕获\u0026#34;) 捕获多种异常（方式2） try: value = int(\u0026#34;abc\u0026#34;) except ValueError: print(\u0026#34;ValueError 被捕获\u0026#34;) except TypeError: print(\u0026#34;TypeError 被捕获\u0026#34;) 获取异常信息 try: result = 10 / 0 except ZeroDivisionError as e: print(f\u0026#34;异常信息：{e}\u0026#34;) print(f\u0026#34;异常类型：{type(e).__name__}\u0026#34;) 完整的 try-except-else-finally def divide(a, b): try: result = a / b except ZeroDivisionError: print(\u0026#34;错误：除数不能为零\u0026#34;) return None except TypeError: print(\u0026#34;错误：参数类型错误\u0026#34;) return None else: # 只有在没有异常时执行 print(f\u0026#34;计算成功：{a} / {b} = {result}\u0026#34;) return result finally: # 无论是否有异常都会执行 print(\u0026#34;divide 函数执行完毕\u0026#34;) print(\u0026#34;测试 10 / 2：\u0026#34;) divide(10, 2) print(\u0026#34;\\n测试 10 / 0：\u0026#34;) divide(10, 0) print(\u0026#34;\\n测试 \u0026#39;10\u0026#39; / 2：\u0026#34;) divide(\u0026#39;10\u0026#39;, 2) 异常对象的属性和方法 异常对象是 Python 的内置异常类的实例，具有以下常用属性：\ntry: raise ValueError(\u0026#34;这是一个错误信息\u0026#34;, \u0026#34;额外的参数\u0026#34;) except ValueError as e: print(f\u0026#34;异常类型：{type(e).__name__}\u0026#34;) print(f\u0026#34;异常消息：{e.args}\u0026#34;) # (\u0026#39;这是一个错误信息\u0026#39;, \u0026#39;额外的参数\u0026#39;) print(f\u0026#34;第一个参数：{e.args[0]}\u0026#34;) 自定义异常类 class ValidationError(Exception): \u0026#34;\u0026#34;\u0026#34;验证错误异常\u0026#34;\u0026#34;\u0026#34; def __init__(self, field, message): self.field = field self.message = message super().__init__(f\u0026#34;{field}: {message}\u0026#34;) class PositiveNumberError(Exception): \u0026#34;\u0026#34;\u0026#34;必须是正数错误\u0026#34;\u0026#34;\u0026#34; pass def validate_positive(value, name=\u0026#34;value\u0026#34;): if value \u0026lt;= 0: raise PositiveNumberError(f\u0026#34;{name} 必须是正数，当前值：{value}\u0026#34;) try: validate_positive(-5, \u0026#34;年龄\u0026#34;) except PositiveNumberError as e: print(f\u0026#34;捕获异常：{e}\u0026#34;) try: raise ValidationError(\u0026#34;email\u0026#34;, \u0026#34;邮箱格式不正确\u0026#34;) except ValidationError as e: print(f\u0026#34;字段：{e.field}，错误：{e.message}\u0026#34;) 异常的层次结构 Python 的异常有一个层次结构：\nBaseException ├── SystemExit ├── KeyboardInterrupt ├── GeneratorExit └── Exception ├── StopIteration ├── ArithmeticError │ ├── FloatingPointError │ ├── OverflowError │ └── ZeroDivisionError ├── LookupError │ ├── IndexError │ └── KeyError ├── OSError │ ├── FileNotFoundError │ ├── PermissionError │ └── TimeoutError └── ...# 捕获所有非系统退出的异常 try: result = 10 / 0 except Exception as e: print(f\u0026#34;捕获异常：{type(e).__name__}: {e}\u0026#34;) # 捕获多个相关异常 try: result = 10 / 0 except (ZeroDivisionError, FloatingPointError) as e: print(f\u0026#34;算术错误：{e}\u0026#34;) # except 子句的顺序很重要！ # 应该先捕获具体异常，再捕获通用异常 try: result = 10 / 0 except Exception: # 这会捕获所有异常 print(\u0026#34;捕获 Exception\u0026#34;) except ZeroDivisionError: # 这个永远不会执行 print(\u0026#34;捕获 ZeroDivisionError\u0026#34;) raise 语句 # 重新抛出当前异常 try: try: raise ValueError(\u0026#34;原始错误\u0026#34;) except ValueError: print(\u0026#34;内部：捕获 ValueError，重新抛出\u0026#34;) raise # 重新抛出当前异常 except ValueError: print(\u0026#34;外部：再次捕获 ValueError\u0026#34;) # 手动抛出异常 raise ValueError(\u0026#34;手动抛出的异常\u0026#34;) # raise without argument（重新抛出当前异常） try: raise RuntimeError(\u0026#34;错误\u0026#34;) except RuntimeError: print(\u0026#34;处理错误\u0026#34;) raise # 重新抛出 异常链（Exception Chaining） Python 3 支持异常链，可以在抛出新异常时保留原始异常。\n# 显式异常链（from） try: raise ValueError(\u0026#34;原始错误\u0026#34;) except ValueError as e: raise RuntimeError(\u0026#34;新错误\u0026#34;) from e # 隐式异常链 try: raise ValueError(\u0026#34;原始错误\u0026#34;) except ValueError: print(\u0026#34;处理中发生新错误\u0026#34;) # 如果这里抛出异常，会自动链接 raise RuntimeError(\u0026#34;新错误\u0026#34;) # 抑制异常链 try: raise ValueError(\u0026#34;原始错误\u0026#34;) except ValueError as e: raise RuntimeError(\u0026#34;新错误\u0026#34;) from None # 不链接原始异常 使用 else 的场景 else 子句只在 try 块没有发生任何异常时执行。\n# 文件操作示例 def read_config(filename): try: with open(filename, \u0026#39;r\u0026#39;) as f: config = {} for line in f: line = line.strip() if line and not line.startswith(\u0026#39;#\u0026#39;): key, value = line.split(\u0026#39;=\u0026#39;, 1) config[key.strip()] = value.strip() except FileNotFoundError: print(f\u0026#34;配置文件不存在：{filename}\u0026#34;) return {} except PermissionError: print(f\u0026#34;没有读取权限：{filename}\u0026#34;) return {} else: # 只有成功读取并解析完才执行 print(\u0026#34;配置读取成功！\u0026#34;) return config finally: # 清理工作 print(\u0026#34;read_config 函数执行完毕\u0026#34;) 使用 finally 的场景 finally 子句无论是否发生异常都会执行，常用于资源清理。\n# 数据库连接示例 def fetch_data(query): conn = None cursor = None try: conn = create_connection() cursor = conn.cursor() cursor.execute(query) result = cursor.fetchall() return result except DatabaseError as e: print(f\u0026#34;数据库错误：{e}\u0026#34;) return None finally: # 确保资源被释放 if cursor: cursor.close() if conn: conn.close() print(\u0026#34;数据库连接已关闭\u0026#34;) 上下文管理器与异常 使用 with 语句可以更优雅地处理资源清理：\n# 手动关闭文件（不推荐） f = open(\u0026#39;file.txt\u0026#39;, \u0026#39;w\u0026#39;) try: f.write(\u0026#39;hello\u0026#39;) except IOError: print(\u0026#34;写入失败\u0026#34;) finally: f.close() # 使用上下文管理器（推荐） try: with open(\u0026#39;file.txt\u0026#39;, \u0026#39;w\u0026#39;) as f: f.write(\u0026#39;hello\u0026#39;) except IOError: print(\u0026#34;写入失败\u0026#34;) # 文件自动关闭，无需 finally 捕获异常的最佳实践 具体优先于通用：先捕获具体异常，再捕获通用异常 不过度捕获：不要用 except Exception 来隐藏所有错误 记录异常：在 except 块中记录错误日志 不要忽略异常：至少打印或记录异常信息 清理资源：使用 finally 或 with 语句 # 不推荐的写法 try: result = risky_operation() except Exception: # 太宽泛，隐藏了真实问题 pass # 推荐的写法 try: result = risky_operation() except SpecificError as e: logger.error(f\u0026#34;操作失败：{e}\u0026#34;) raise # 重新抛出，让调用者知道发生了错误 except AnotherError as e: logger.warning(f\u0026#34;操作警告：{e}\u0026#34;) return default_value 常见异常处理模式 模式1：重试机制 import time def retry_operation(func, max_attempts=3, delay=1): \u0026#34;\u0026#34;\u0026#34;重试操作\u0026#34;\u0026#34;\u0026#34; for attempt in range(max_attempts): try: return func() except TemporaryError as e: if attempt == max_attempts - 1: raise print(f\u0026#34;尝试 {attempt + 1} 失败：{e}，{delay}秒后重试...\u0026#34;) time.sleep(delay) # 使用 def fetch_data(): return api_call() result = retry_operation(fetch_data, max_attempts=3) 模式2：优雅降级 def get_config_value(key, default=None): \u0026#34;\u0026#34;\u0026#34;获取配置值，失败时返回默认值\u0026#34;\u0026#34;\u0026#34; try: return config[key] except (KeyError, TypeError): return default # 使用 timeout = get_config_value(\u0026#39;timeout\u0026#39;, 30) 模式3：验证后执行 def process_data(data): \u0026#34;\u0026#34;\u0026#34;处理数据，验证失败时跳过\u0026#34;\u0026#34;\u0026#34; results = [] for item in data: try: validate(item) results.append(transform(item)) except ValidationError: print(f\u0026#34;跳过无效项：{item}\u0026#34;) return results 练习题 练习 1：安全的除法计算器 def safe_divide(a, b): \u0026#34;\u0026#34;\u0026#34;安全的除法运算\u0026#34;\u0026#34;\u0026#34; try: result = a / b except ZeroDivisionError: print(\u0026#34;错误：除数不能为零\u0026#34;) return None except TypeError: print(\u0026#34;错误：参数必须是数字\u0026#34;) return None else: return result finally: print(\u0026#34;计算完成\u0026#34;) # 测试 print(f\u0026#34;10 / 2 = {safe_divide(10, 2)}\u0026#34;) print(f\u0026#34;10 / 0 = {safe_divide(10, 0)}\u0026#34;) print(f\u0026#34;\u0026#39;10\u0026#39; / 2 = {safe_divide(\u0026#39;10\u0026#39;, 2)}\u0026#34;) print(f\u0026#34;10 / \u0026#39;2\u0026#39; = {safe_divide(10, \u0026#39;2\u0026#39;)}\u0026#34;) 练习 2：配置解析器 class ConfigParseError(Exception): \u0026#34;\u0026#34;\u0026#34;配置解析错误\u0026#34;\u0026#34;\u0026#34; pass def parse_config_line(line): \u0026#34;\u0026#34;\u0026#34;解析配置行\u0026#34;\u0026#34;\u0026#34; line = line.strip() # 跳过空行和注释 if not line or line.startswith(\u0026#39;#\u0026#39;): return None # 解析键值对 if \u0026#39;=\u0026#39; not in line: raise ConfigParseError(f\u0026#34;无效的配置行：{line}\u0026#34;) key, value = line.split(\u0026#39;=\u0026#39;, 1) key = key.strip() value = value.strip() if not key: raise ConfigParseError(f\u0026#34;配置键不能为空\u0026#34;) return key, value def load_config(content): \u0026#34;\u0026#34;\u0026#34;加载配置\u0026#34;\u0026#34;\u0026#34; config = {} for line_num, line in enumerate(content.split(\u0026#39;\\n\u0026#39;), 1): try: result = parse_config_line(line) if result: key, value = result config[key] = value except ConfigParseError as e: print(f\u0026#34;第 {line_num} 行错误：{e}\u0026#34;) return config # 测试 config_text = \u0026#34;\u0026#34;\u0026#34; # 数据库配置 db_host=localhost db_port=3306 db_name=testdb # 应用配置 app_name=MyApp debug=true # 错误配置 invalid line \u0026#34;\u0026#34;\u0026#34; config = load_config(config_text) print(f\u0026#34;解析的配置：{config}\u0026#34;) 练习 3：带超时的函数执行 import time import threading class TimeoutError(Exception): \u0026#34;\u0026#34;\u0026#34;超时错误\u0026#34;\u0026#34;\u0026#34; pass def with_timeout(func, timeout, *args, **kwargs): \u0026#34;\u0026#34;\u0026#34;在指定超时时间内执行函数\u0026#34;\u0026#34;\u0026#34; result = [None] exception = [None] finished = [False] def worker(): try: result[0] = func(*args, **kwargs) except Exception as e: exception[0] = e finally: finished[0] = True thread = threading.Thread(target=worker) thread.start() thread.join(timeout) if not finished[0]: raise TimeoutError(f\u0026#34;函数执行超时（{timeout}秒）\u0026#34;) if exception[0]: raise exception[0] return result[0] # 测试 def slow_function(): time.sleep(2) return \u0026#34;完成\u0026#34; def fast_function(): return \u0026#34;快速完成\u0026#34; try: print(with_timeout(fast_function, 1)) except TimeoutError as e: print(f\u0026#34;超时：{e}\u0026#34;) try: print(with_timeout(slow_function, 1)) except TimeoutError as e: print(f\u0026#34;超时：{e}\u0026#34;) 总结 异常处理是 Python 编程中的重要组成部分：\ntry-except：捕获和处理异常 else：在没有异常时执行 finally：无论是否有异常都执行 raise：抛出异常 异常链：保留原始异常的上下文 自定义异常：创建自己的异常类型 最佳实践：具体异常优先、记录异常、清理资源 掌握异常处理对于编写健壮的 Python 程序至关重要。在下一节中，我们将学习如何自定义异常和使用 raise 语句。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-30-exception-handling/","summary":"\u003ch1 id=\"day-30---异常处理try-except-else-finally\"\u003eDay 30 - 异常处理：try-except-else-finally\u003c/h1\u003e\n\u003ch2 id=\"什么是异常\"\u003e什么是异常？\u003c/h2\u003e\n\u003cp\u003e异常（Exception）是 Python 程序在运行过程中发生的错误。当异常发生时，程序会停止执行，并创建一个异常对象。如果异常没有被捕获和处理，程序会打印一个回溯（traceback）并终止。\u003c/p\u003e\n\u003cp\u003ePython 的异常处理机制允许我们捕获异常并自定义处理方式，而不是让程序直接崩溃。这对于编写健壮的程序至关重要。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 常见的异常类型\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# ZeroDivisionError: division by zero\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(int(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;abc\u0026#34;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# ValueError: invalid literal for int()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint([\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e][\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e])  \u003cspan style=\"color:#75715e\"\u003e# IndexError: list index out of range\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint({}[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;key\u0026#34;\u003c/span\u003e])  \u003cspan style=\"color:#75715e\"\u003e# KeyError: \u0026#39;key\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"try-except-基本语法\"\u003etry-except 基本语法\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 可能发生异常的代码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    result \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eZeroDivisionError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 处理 ZeroDivisionError 异常\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;不能除以零！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"完整的异常处理结构\"\u003e完整的异常处理结构\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 可能发生异常的代码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    num \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e int(input(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;请输入一个数字：\u0026#34;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    result \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e num\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 处理值错误（输入不是数字）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;输入无效，请输入数字！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eZeroDivisionError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 处理除以零错误\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;不能除以零！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 只有在没有异常时才会执行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;结果：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresult\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efinally\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 无论是否有异常都会执行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;程序结束\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"except-的多种写法\"\u003eexcept 的多种写法\u003c/h2\u003e\n\u003ch3 id=\"捕获特定异常\"\u003e捕获特定异常\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    value \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e int(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;abc\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;ValueError 被捕获\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    lst \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    value \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e lst[\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eIndexError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;IndexError 被捕获\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"捕获多种异常方式1\"\u003e捕获多种异常（方式1）\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    value \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e int(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;abc\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e (\u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003eTypeError\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;ValueError 或 TypeError 被捕获\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"捕获多种异常方式2\"\u003e捕获多种异常（方式2）\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    value \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e int(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;abc\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;ValueError 被捕获\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eTypeError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;TypeError 被捕获\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"获取异常信息\"\u003e获取异常信息\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    result \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eZeroDivisionError\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;异常信息：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ee\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;异常类型：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etype(e)\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e__name__\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"完整的-try-except-else-finally\"\u003e完整的 try-except-else-finally\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edivide\u003c/span\u003e(a, b):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        result \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e b\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eZeroDivisionError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;错误：除数不能为零\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eTypeError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;错误：参数类型错误\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 只有在没有异常时执行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;计算成功：\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e / \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eb\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresult\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e result\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efinally\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 无论是否有异常都会执行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;divide 函数执行完毕\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;测试 10 / 2：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edivide(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e测试 10 / 0：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edivide(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e测试 \u0026#39;10\u0026#39; / 2：\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edivide(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;10\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"异常对象的属性和方法\"\u003e异常对象的属性和方法\u003c/h2\u003e\n\u003cp\u003e异常对象是 Python 的内置异常类的实例，具有以下常用属性：\u003c/p\u003e","tags":"Python, 编程","title":"Day 30 - 异常处理：try-except-else-finally"},{"columns":"python-course","content":"Day 31 - raise 语句与自定义异常 raise 语句基础 raise 语句用于显式地抛出异常。在 Python 中，你可以抛出任何继承自 BaseException 的对象，但通常我们应该抛出 Exception 的子类。\n# 基本语法 raise Exception(\u0026#34;错误信息\u0026#34;) # 重新抛出当前捕获的异常 try: raise ValueError(\u0026#34;原始错误\u0026#34;) except ValueError: print(\u0026#34;处理异常\u0026#34;) raise # 重新抛出 # 使用 raise from 链接异常 try: raise ValueError(\u0026#34;原始错误\u0026#34;) except ValueError as e: raise RuntimeError(\u0026#34;新错误\u0026#34;) from e 常见的内置异常 Python 提供了一系列内置异常，按层次结构组织：\nBaseException ├── SystemExit ├── KeyboardInterrupt ├── GeneratorExit └── Exception ├── StopIteration ├── ArithmeticError │ ├── FloatingPointError │ ├── OverflowError │ └── ZeroDivisionError ├── LookupError │ ├── IndexError │ └── KeyError ├── OSError (IOError) │ ├── FileNotFoundError │ ├── PermissionError │ └── TimeoutError ├── TypeError ├── ValueError ├── RuntimeError └── ...# 触发各种内置异常 print(10 / 0) # ZeroDivisionError print(int(\u0026#34;abc\u0026#34;)) # ValueError print([1,2][10]) # IndexError print({}[\u0026#34;key\u0026#34;]) # KeyError open(\u0026#34;nonexistent.txt\u0026#34;) # FileNotFoundError 自定义异常类 自定义异常应该继承自 Exception 或其子类。通常，自定义异常类比较简单，只需要定义构造函数和异常消息。\nclass MyError(Exception): \u0026#34;\u0026#34;\u0026#34;自定义错误\u0026#34;\u0026#34;\u0026#34; pass raise MyError(\u0026#34;这是一个自定义错误\u0026#34;) 带额外信息的异常 class ValidationError(Exception): \u0026#34;\u0026#34;\u0026#34;验证错误：包含字段名和错误信息\u0026#34;\u0026#34;\u0026#34; def __init__(self, field, message): self.field = field self.message = message super().__init__(f\u0026#34;{field}: {message}\u0026#34;) raise ValidationError(\u0026#34;email\u0026#34;, \u0026#34;邮箱格式不正确\u0026#34;) # ValidationError: email: 邮箱格式不正确 完整的企业级异常设计 class AppError(Exception): \u0026#34;\u0026#34;\u0026#34;应用基础异常类\u0026#34;\u0026#34;\u0026#34; def __init__(self, message, error_code=None, details=None): self.message = message self.error_code = error_code self.details = details or {} super().__init__(self.message) def __str__(self): parts = [self.message] if self.error_code: parts.append(f\u0026#34;[错误码: {self.error_code}]\u0026#34;) if self.details: parts.append(f\u0026#34;详情: {self.details}\u0026#34;) return \u0026#34; \u0026#34;.join(parts) class ValidationError(AppError): \u0026#34;\u0026#34;\u0026#34;验证错误\u0026#34;\u0026#34;\u0026#34; def __init__(self, field, message, value=None): details = {\u0026#34;field\u0026#34;: field, \u0026#34;value\u0026#34;: value} super().__init__(f\u0026#34;验证失败: {message}\u0026#34;, \u0026#34;VALIDATION_ERROR\u0026#34;, details) class DatabaseError(AppError): \u0026#34;\u0026#34;\u0026#34;数据库错误\u0026#34;\u0026#34;\u0026#34; pass class NetworkError(AppError): \u0026#34;\u0026#34;\u0026#34;网络错误\u0026#34;\u0026#34;\u0026#34; def __init__(self, message, url=None, status_code=None): details = {\u0026#34;url\u0026#34;: url, \u0026#34;status_code\u0026#34;: status_code} super().__init__(message, \u0026#34;NETWORK_ERROR\u0026#34;, details) # 使用 try: raise ValidationError(\u0026#34;username\u0026#34;, \u0026#34;用户名不能为空\u0026#34;, value=\u0026#34;\u0026#34;) except AppError as e: print(f\u0026#34;错误类型: {type(e).__name__}\u0026#34;) print(f\u0026#34;错误码: {e.error_code}\u0026#34;) print(f\u0026#34;详情: {e.details}\u0026#34;) 异常类的设计原则 继承层次合理：根据异常的语义和用途选择合适的基类 提供有用的信息：异常消息应该清楚描述问题 包含上下文信息：使用属性存储相关上下文 遵循命名约定：异常类名以 Error 结尾 不过度具体化：避免创建过多细粒度的异常类 # 不好的设计：过于具体 class UsernameEmptyError(Exception): pass class UsernameTooShortError(Exception): pass class UsernameTooLongError(Exception): pass # 好的设计：统一的验证错误 class ValidationError(Exception): def __init__(self, field, rule, value=None): self.field = field self.rule = rule self.value = value super().__init__(f\u0026#34;{field} 违反规则 {rule}，值: {value}\u0026#34;) raise ValidationError(\u0026#34;username\u0026#34;, \u0026#34;not_empty\u0026#34;, value=None) raise ValidationError(\u0026#34;username\u0026#34;, \u0026#34;min_length:3\u0026#34;, value=\u0026#34;ab\u0026#34;) raise ValidationError(\u0026#34;username\u0026#34;, \u0026#34;max_length:20\u0026#34;, value=\u0026#34;a\u0026#34; * 25) raise 语句的多种形式 1. raise 单独使用 try: raise ValueError(\u0026#34;错误信息\u0026#34;) except ValueError: print(\u0026#34;捕获了 ValueError\u0026#34;) raise # 重新抛出，不带参数 2. raise Exception raise ValueError(\u0026#34;错误信息\u0026#34;) 3. raise Exception from original try: raise TypeError(\u0026#34;原始错误\u0026#34;) except TypeError as e: raise RuntimeError(\u0026#34;新错误\u0026#34;) from e 4. raise Exception from None raise RuntimeError(\u0026#34;新错误\u0026#34;) from None 异常链详解 异常链允许在一个异常中保留另一个异常的上下文。\n# 显式异常链（from） try: raise ValueError(\u0026#34;原始错误\u0026#34;) except ValueError as e: raise RuntimeError(\u0026#34;中间层错误\u0026#34;) from e # 输出： # Traceback (most recent call last): # File \u0026#34;...\u0026#34;, line 2, in \u0026lt;module\u0026gt; # raise ValueError(\u0026#34;原始错误\u0026#34;) # ValueError: 原始错误 # # The above exception was the direct cause of the following exception: # Traceback (most recent call last): # File \u0026#34;...\u0026#34;, line 4, in \u0026lt;module\u0026gt; # raise RuntimeError(\u0026#34;中间层错误\u0026#34;) from e # RuntimeError: 中间层错误 # 隐式异常链 try: raise ValueError(\u0026#34;原始错误\u0026#34;) except ValueError: raise RuntimeError(\u0026#34;新错误\u0026#34;) # 没有 from，隐式链接 # 输出会显示： # During handling of the above exception, another exception occurred: 断言与异常 断言（assert）用于开发过程中检查不可能发生的情况，断言失败会抛出 AssertionError。\n# 断言语法 assert condition, \u0026#34;错误信息\u0026#34; # 示例 def divide(a, b): assert b != 0, \u0026#34;除数不能为零\u0026#34; return a / b divide(10, 2) # 正常 divide(10, 0) # AssertionError: 除数不能为零 断言 vs 异常：\n断言用于检测程序错误（不应该发生的情况） 异常用于处理运行时可能发生的错误情况 断言可以在 Python 启动时使用 -O 参数禁用 # 不适合用断言的情况 def get_user(user_id): user = db.get(user_id) # 数据库可能不存在 assert user is not None # 不好：应该用异常 return user # 适合用断言的情况 def calculate_triangle_area(base, height): assert base \u0026gt; 0 and height \u0026gt; 0 # 不可能为负数 return base * height / 2 异常处理的反模式 反模式1：空的 except 块 # 不好：隐藏了所有错误 try: risky_operation() except: pass # 好：捕获特定异常 try: risky_operation() except SpecificError as e: logger.error(f\u0026#34;操作失败: {e}\u0026#34;) raise 反模式2：捕获所有异常 # 不好：过于宽泛 try: operation() except Exception: handle_error() # 好：分层处理 try: operation() except ValidationError as e: return bad_request(str(e)) except DatabaseError as e: return server_error(\u0026#34;数据库错误\u0026#34;) except Exception as e: logger.critical(f\u0026#34;未知错误: {e}\u0026#34;) return server_error(\u0026#34;系统错误\u0026#34;) 反模式3：异常用于控制流 # 不好：用异常控制流程 try: result = items[current_index] current_index += 1 except IndexError: current_index = 0 result = items[0] # 好：使用正常的控制流 if current_index \u0026lt; len(items): result = items[current_index] current_index += 1 else: current_index = 0 result = items[0] 异常与调试 使用 traceback 模块 import traceback try: raise ValueError(\u0026#34;测试错误\u0026#34;) except ValueError: # 打印完整的 traceback traceback.print_exc() # 获取 traceback 字符串 tb_str = traceback.format_exc() print(f\u0026#34;捕获的异常: {tb_str}\u0026#34;) 使用 logging 记录异常 import logging logger = logging.getLogger(__name__) try: operation() except Exception as e: logger.exception(\u0026#34;操作失败\u0026#34;) # 自动记录完整 traceback # 或 logger.error(\u0026#34;操作失败: %s\u0026#34;, str(e), exc_info=True) 练习题 练习 1：实现 API 异常 class APIError(Exception): \u0026#34;\u0026#34;\u0026#34;API 错误基类\u0026#34;\u0026#34;\u0026#34; def __init__(self, message, status_code=500, response=None): self.message = message self.status_code = status_code self.response = response super().__init__(self.message) class AuthenticationError(APIError): \u0026#34;\u0026#34;\u0026#34;认证错误\u0026#34;\u0026#34;\u0026#34; def __init__(self, message=\u0026#34;认证失败\u0026#34;): super().__init__(message, status_code=401) class AuthorizationError(APIError): \u0026#34;\u0026#34;\u0026#34;授权错误\u0026#34;\u0026#34;\u0026#34; def __init__(self, message=\u0026#34;权限不足\u0026#34;): super().__init__(message, status_code=403) class NotFoundError(APIError): \u0026#34;\u0026#34;\u0026#34;资源不存在错误\u0026#34;\u0026#34;\u0026#34; def __init__(self, resource, resource_id): message = f\u0026#34;{resource} 不存在: {resource_id}\u0026#34; super().__init__(message, status_code=404) self.resource = resource self.resource_id = resource_id class RateLimitError(APIError): \u0026#34;\u0026#34;\u0026#34;请求频率限制错误\u0026#34;\u0026#34;\u0026#34; def __init__(self, retry_after=60): message = f\u0026#34;请求过于频繁，请在 {retry_after} 秒后重试\u0026#34; super().__init__(message, status_code=429) self.retry_after = retry_after def api_call(endpoint): \u0026#34;\u0026#34;\u0026#34;模拟 API 调用\u0026#34;\u0026#34;\u0026#34; if endpoint == \u0026#34;/auth/login\u0026#34;: raise AuthenticationError(\u0026#34;Token 已过期\u0026#34;) elif endpoint == \u0026#34;/admin/users\u0026#34;: raise AuthorizationError(\u0026#34;需要管理员权限\u0026#34;) elif endpoint == \u0026#34;/users/999\u0026#34;: raise NotFoundError(\u0026#34;用户\u0026#34;, 999) elif endpoint == \u0026#34;/api/data\u0026#34;: raise RateLimitError(30) return {\u0026#34;data\u0026#34;: \u0026#34;success\u0026#34;} # 测试 endpoints = [\u0026#34;/auth/login\u0026#34;, \u0026#34;/admin/users\u0026#34;, \u0026#34;/users/999\u0026#34;, \u0026#34;/api/data\u0026#34;, \u0026#34;/api/valid\u0026#34;] for endpoint in endpoints: try: result = api_call(endpoint) print(f\u0026#34;{endpoint}: {result}\u0026#34;) except APIError as e: print(f\u0026#34;{endpoint}:\u0026#34;) print(f\u0026#34; 状态码: {e.status_code}\u0026#34;) print(f\u0026#34; 消息: {e.message}\u0026#34;) if hasattr(e, \u0026#39;retry_after\u0026#39;): print(f\u0026#34; 重试时间: {e.retry_after}秒\u0026#34;) print() 练习 2：验证器 class ValidationError(Exception): \u0026#34;\u0026#34;\u0026#34;验证错误\u0026#34;\u0026#34;\u0026#34; def __init__(self, field, rule, value=None): self.field = field self.rule = rule self.value = value super().__init__(f\u0026#34;{field}: {rule} (当前值: {value})\u0026#34;) def validate_required(value, field_name): if value is None or (isinstance(value, str) and not value.strip()): raise ValidationError(field_name, \u0026#34;必填字段\u0026#34;) def validate_length(value, field_name, min_len=None, max_len=None): if value is None: return length = len(value) if min_len is not None and length \u0026lt; min_len: raise ValidationError(field_name, f\u0026#34;最小长度: {min_len}\u0026#34;, value) if max_len is not None and length \u0026gt; max_len: raise ValidationError(field_name, f\u0026#34;最大长度: {max_len}\u0026#34;, value) def validate_range(value, field_name, min_val=None, max_val=None): if value is None: return if min_val is not None and value \u0026lt; min_val: raise ValidationError(field_name, f\u0026#34;最小值: {min_val}\u0026#34;, value) if max_val is not None and value \u0026gt; max_val: raise ValidationError(field_name, f\u0026#34;最大值: {max_val}\u0026#34;, value) def validate_email(email, field_name): import re pattern = r\u0026#39;^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$\u0026#39; if not re.match(pattern, email): raise ValidationError(field_name, \u0026#34;无效的邮箱格式\u0026#34;, email) def validate_user_data(data): \u0026#34;\u0026#34;\u0026#34;验证用户数据\u0026#34;\u0026#34;\u0026#34; errors = [] for field, rules in data.items(): value = rules.get(\u0026#39;value\u0026#39;) # 必填检查 if rules.get(\u0026#39;required\u0026#39;, False): try: validate_required(value, field) except ValidationError as e: errors.append(e) # 长度检查 if \u0026#39;min_length\u0026#39; in rules or \u0026#39;max_length\u0026#39; in rules: try: validate_length(value, field, rules.get(\u0026#39;min_length\u0026#39;), rules.get(\u0026#39;max_length\u0026#39;)) except ValidationError as e: errors.append(e) # 范围检查 if \u0026#39;min\u0026#39; in rules or \u0026#39;max\u0026#39; in rules: try: validate_range(value, field, rules.get(\u0026#39;min\u0026#39;), rules.get(\u0026#39;max\u0026#39;)) except ValidationError as e: errors.append(e) # 邮箱检查 if rules.get(\u0026#39;type\u0026#39;) == \u0026#39;email\u0026#39;: try: validate_email(value, field) except ValidationError as e: errors.append(e) if errors: raise ValidationError(\u0026#34;user_data\u0026#34;, \u0026#34;验证失败\u0026#34;) return True # 测试 test_data = { \u0026#34;username\u0026#34;: {\u0026#34;value\u0026#34;: \u0026#34;john\u0026#34;, \u0026#34;required\u0026#34;: True, \u0026#34;min_length\u0026#34;: 3, \u0026#34;max_length\u0026#34;: 20}, \u0026#34;email\u0026#34;: {\u0026#34;value\u0026#34;: \u0026#34;john@example.com\u0026#34;, \u0026#34;required\u0026#34;: True, \u0026#34;type\u0026#34;: \u0026#34;email\u0026#34;}, \u0026#34;age\u0026#34;: {\u0026#34;value\u0026#34;: 25, \u0026#34;min\u0026#34;: 0, \u0026#34;max\u0026#34;: 150}, \u0026#34;bio\u0026#34;: {\u0026#34;value\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;max_length\u0026#34;: 500} } try: validate_user_data(test_data) print(\u0026#34;验证通过！\u0026#34;) except ValidationError as e: print(f\u0026#34;验证失败: {e}\u0026#34;) # 测试无效数据 invalid_data = { \u0026#34;username\u0026#34;: {\u0026#34;value\u0026#34;: \u0026#34;jo\u0026#34;, \u0026#34;required\u0026#34;: True, \u0026#34;min_length\u0026#34;: 3}, \u0026#34;email\u0026#34;: {\u0026#34;value\u0026#34;: \u0026#34;invalid-email\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;email\u0026#34;}, \u0026#34;age\u0026#34;: {\u0026#34;value\u0026#34;: -5, \u0026#34;min\u0026#34;: 0} } try: validate_user_data(invalid_data) except ValidationError as e: print(f\u0026#34;验证失败: {e}\u0026#34;) if hasattr(e, \u0026#39;field\u0026#39;): print(f\u0026#34;字段: {e.field}, 规则: {e.rule}, 值: {e.value}\u0026#34;) 练习 3：上下文管理器与异常 class Transaction: \u0026#34;\u0026#34;\u0026#34;事务上下文管理器\u0026#34;\u0026#34;\u0026#34; def __init__(self, connection): self.conn = connection self.committed = False def __enter__(self): print(\u0026#34;开始事务\u0026#34;) self.conn.begin() return self def __exit__(self, exc_type, exc_val, exc_tb): if exc_type is not None: print(f\u0026#34;事务失败: {exc_val}\u0026#34;) print(\u0026#34;执行回滚\u0026#34;) self.conn.rollback() return False # 不吞没异常 else: print(\u0026#34;提交事务\u0026#34;) self.conn.commit() self.committed = True return True # 吞没异常（如果有） def execute(self, sql): print(f\u0026#34;执行 SQL: {sql}\u0026#34;) self.conn.execute(sql) class MockConnection: def begin(self): print(\u0026#34; [连接] 开始事务\u0026#34;) def commit(self): print(\u0026#34; [连接] 提交事务\u0026#34;) def rollback(self): print(\u0026#34; [连接] 回滚事务\u0026#34;) def execute(self, sql): print(f\u0026#34; [连接] 执行: {sql}\u0026#34;) # 测试成功场景 print(\u0026#34;=== 测试成功场景 ===\u0026#34;) conn = MockConnection() try: with Transaction(conn) as tx: tx.execute(\u0026#34;INSERT INTO users VALUES (1, \u0026#39;张三\u0026#39;)\u0026#34;) tx.execute(\u0026#34;UPDATE accounts SET balance = balance - 100\u0026#34;) print(f\u0026#34;事务提交状态: {tx.committed}\u0026#34;) except Exception as e: print(f\u0026#34;外部捕获异常: {e}\u0026#34;) print(\u0026#34;\\n=== 测试失败场景 ===\u0026#34;) conn2 = MockConnection() try: with Transaction(conn2) as tx: tx.execute(\u0026#34;INSERT INTO orders VALUES (1, \u0026#39;商品\u0026#39;)\u0026#34;) tx.execute(\u0026#34;DELETE FROM inventory WHERE quantity \u0026lt; 0\u0026#34;) # 这会失败 except RuntimeError as e: print(f\u0026#34;外部捕获异常: {e}\u0026#34;) 总结 raise 语句和自定义异常是 Python 异常处理的重要组成部分：\nraise 语句：显式抛出异常，支持异常链 自定义异常：继承 Exception 或其子类 异常链：raise ... from e 和 raise ... from None 断言：用于开发时检查不可能的情况 异常设计原则：提供有用的信息，包含上下文 反模式：避免空 except、过度宽泛的捕获等 在下一节中，我们将学习 Python 的模块系统：import、from、as。\n","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-31-raise-custom-exceptions/","summary":"\u003ch1 id=\"day-31---raise-语句与自定义异常\"\u003eDay 31 - raise 语句与自定义异常\u003c/h1\u003e\n\u003ch2 id=\"raise-语句基础\"\u003eraise 语句基础\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eraise\u003c/code\u003e 语句用于显式地抛出异常。在 Python 中，你可以抛出任何继承自 \u003ccode\u003eBaseException\u003c/code\u003e 的对象，但通常我们应该抛出 \u003ccode\u003eException\u003c/code\u003e 的子类。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 基本语法\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eraise\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eException\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;错误信息\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 重新抛出当前捕获的异常\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eraise\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;原始错误\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;处理异常\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eraise\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 重新抛出\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用 raise from 链接异常\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eraise\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;原始错误\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eraise\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eRuntimeError\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;新错误\u0026#34;\u003c/span\u003e) \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"常见的内置异常\"\u003e常见的内置异常\u003c/h2\u003e\n\u003cp\u003ePython 提供了一系列内置异常，按层次结构组织：\u003c/p\u003e\nBaseException\n├── SystemExit\n├── KeyboardInterrupt\n├── GeneratorExit\n└── Exception\n    ├── StopIteration\n    ├── ArithmeticError\n    │   ├── FloatingPointError\n    │   ├── OverflowError\n    │   └── ZeroDivisionError\n    ├── LookupError\n    │   ├── IndexError\n    │   └── KeyError\n    ├── OSError (IOError)\n    │   ├── FileNotFoundError\n    │   ├── PermissionError\n    │   └── TimeoutError\n    ├── TypeError\n    ├── ValueError\n    ├── RuntimeError\n    └── ...\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 触发各种内置异常\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# ZeroDivisionError\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(int(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;abc\u0026#34;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# ValueError\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint([\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e,\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e][\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e])  \u003cspan style=\"color:#75715e\"\u003e# IndexError\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint({}[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;key\u0026#34;\u003c/span\u003e])  \u003cspan style=\"color:#75715e\"\u003e# KeyError\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eopen(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;nonexistent.txt\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# FileNotFoundError\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"自定义异常类\"\u003e自定义异常类\u003c/h2\u003e\n\u003cp\u003e自定义异常应该继承自 \u003ccode\u003eException\u003c/code\u003e 或其子类。通常，自定义异常类比较简单，只需要定义构造函数和异常消息。\u003c/p\u003e","tags":"Python, 编程","title":"Day 31 - raise 语句与自定义异常"},{"columns":"python-course","content":"Day32 - 模块与导入系统详解 详细讲解 1. 模块基础概念 模块（Module） 是 Python 中组织代码的基本单位。一个 .py 文件就是一个模块，模块中可以包含函数、类、变量以及可执行代码。\n# mymodule.py def greet(name): return f\u0026#34;你好，{name}！\u0026#34; class Calculator: def add(self, a, b): return a + b def subtract(self, a, b): return a - b PI = 3.14159 2. import 语句详解 2.1 基本导入 import mymodule # 调用函数 result = mymodule.greet(\u0026#34;张三\u0026#34;) print(result) # 输出: 你好，张三！ # 使用类 calc = mymodule.Calculator() print(calc.add(10, 5)) # 输出: 15 # 访问变量 print(mymodule.PI) # 输出: 3.14159 2.2 from\u0026hellip;import 语句 # 导入特定成员 from mymodule import greet, PI # 直接使用（无需模块名前缀） print(greet(\u0026#34;李四\u0026#34;)) # 输出: 你好，李四！ print(PI) # 输出: 3.14159 # 导入所有成员（不推荐） from mymodule import * 2.3 as 别名使用 import mymodule as m # 使用简短别名 print(m.greet(\u0026#34;王五\u0026#34;)) # 输出: 你好，王五！ # 部分导入起别名 from mymodule import Calculator as Calc, PI as PI_VALUE calc = Calc() print(calc.add(100, 200)) # 输出: 300 3. sys.path 与模块搜索路径 Python 导入模块时，会按照以下顺序搜索：\n当前目录 - 脚本所在目录 PYTHONPATH - 环境变量中的目录 标准库目录 - Python 安装目录 site-packages - 第三方包目录 import sys # 查看所有搜索路径 print(\u0026#34;模块搜索路径:\u0026#34;) for i, path in enumerate(sys.path): print(f\u0026#34; {i}: {path}\u0026#34;) # 添加自定义搜索路径 sys.path.append(\u0026#39;/path/to/my/modules\u0026#39;) # 插入到最前面（优先搜索） sys.path.insert(0, \u0026#39;/path/to/my/modules\u0026#39;) # 验证路径已添加 print(\u0026#34;\\n添加后的路径:\u0026#34;) print(sys.path) 4. 包（Package）结构 mypackage/ __init__.py # 包初始化文件 module1.py # 模块1 module2.py # 模块2 subpackage/ __init__.py module3.py# 导入包中的模块 import mypackage.module1 from mypackage import module2 from mypackage.subpackage import module3 5. all 变量控制导入行为 # mymodule.py __all__ = [\u0026#39;public_function\u0026#39;, \u0026#39;PublicClass\u0026#39;] def public_function(): return \u0026#34;这是公开函数\u0026#34; def private_function(): return \u0026#34;这是私有函数\u0026#34; class PublicClass: pass class _PrivateClass: pass # from mymodule import * 只会导入 public_function 和 PublicClass 6. 模块的特殊属性 import mymodule # __name__: 模块名（主模块为 \u0026#39;__main__\u0026#39;） print(mymodule.__name__) # 输出: mymodule # __file__: 模块文件路径 print(mymodule.__file__) # __doc__: 模块文档字符串 print(mymodule.__doc__) # __package__: 包名 print(mymodule.__package__) # __spec__: 模块规范信息 print(mymodule.__spec__) 7. 主模块与 __main__ # example.py def main(): print(\u0026#34;主函数执行\u0026#34;) if __name__ == \u0026#39;__main__\u0026#39;: # 只有直接运行此文件时才执行 main() print(\u0026#34;作为主程序运行\u0026#34;) else: print(f\u0026#34;作为模块被导入，模块名: {__name__}\u0026#34;) 8. 动态导入与 importlib import importlib # 动态导入模块 math_module = importlib.import_module(\u0026#39;math\u0026#39;) print(math_module.sqrt(16)) # 输出: 4.0 # 动态导入指定模块的成员 import importlib.util spec = importlib.util.spec_from_file_location(\u0026#34;mymodule\u0026#34;, \u0026#34;/path/to/mymodule.py\u0026#34;) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) # 使用成员的别名 public_function = getattr(module, \u0026#39;public_function\u0026#39;) print(public_function()) 9. 相对导入与绝对导入 # Python 3+ 推荐使用绝对导入 # mypackage/subpackage/module.py from mypackage import module1 # 绝对导入 from . import module2 # 相对导入（同级） from .. import module3 # 相对导入（上级） from ..parent_module import something # 上级的具体模块 10. 重新加载模块 import importlib import mymodule # 重新加载模块（用于开发时） importlib.reload(mymodule) 背诵版 核心概念速记 ┌─────────────────────────────────────────────────────────────┐ │ Python 导入系统 │ ├─────────────────────────────────────────────────────────────┤ │ import mymodule # 导入整个模块 │ │ from mymodule import fn # 导入特定成员 │ │ import mymodule as m # 使用别名 │ │ from m import fn as f # 组合使用 │ ├─────────────────────────────────────────────────────────────┤ │ sys.path 搜索顺序: │ │ 1. 当前目录 → 2. PYTHONPATH → 3. 标准库 → 4. site-packages │ ├─────────────────────────────────────────────────────────────┤ │ __name__ == \u0026#39;__main__\u0026#39; # 判断是否为主程序 │ │ __all__ # 控制 from * 导入行为 │ │ importlib.reload() # 重新加载模块 │ └─────────────────────────────────────────────────────────────┘命令速查表 语法 说明 import os 导入标准库模块 from os import path 导入特定成员 import os as operating_system 使用别名 from . import module 相对导入（同级） from .. import module 相对导入（上级） sys.path.append() 添加搜索路径 importlib.import_module() 动态导入 考前记忆 面试重点 Python 模块搜索顺序（高频）\n当前目录 → PYTHONPATH → 标准库 → site-packages __name__ 的两个值\n__main__：表示文件被直接运行 模块名：表示文件被作为模块导入 导入方式对比\nimport A # 需用 A.xxx 访问 from A import x # 直接使用 x from A import * # 导入所有公开成员（不推荐） sys.path 是列表，可以动态修改\n相对导入只用于包内，且 Python 3 需要 from __future__ import annotations\n记忆口诀 导入模块要记清， 顺序路径在sys中。 __name__判主从， __all__控导入。 别名as来帮忙， importlib动加载。 测试题 选择题 1. 下面哪个选项可以正确导入 math 模块中的 sqrt 函数？\n# A. import math math.sqrt(16) # B. from math import sqrt sqrt(16) # C. import math as m m.sqrt(16) # D. 以上全部正确 答案：D\n2. 当 Python 执行 import sys 时，模块搜索路径的正确顺序是？\n# A. site-packages → 标准库 → PYTHONPATH → 当前目录 # B. 当前目录 → PYTHONPATH → 标准库 → site-packages # C. 标准库 → site-packages → 当前目录 → PYTHONPATH # D. PYTHONPATH → 当前目录 → 标准库 → site-packages 答案：B\n3. 以下代码的输出是什么？\n# module_test.py print(f\u0026#34;模块名: {__name__}\u0026#34;) if __name__ == \u0026#39;__main__\u0026#39;: print(\u0026#34;直接运行\u0026#34;) else: print(\u0026#34;被导入\u0026#34;) A. 直接运行 B. 被导入 C. 模块名: main / 直接运行 D. 模块名: main / 被导入\n答案：C（当直接运行此脚本时，name 为 main）\n4. from mypackage import * 受哪个变量的控制？\n# A. __init__ # B. __all__ # C. __name__ # D. __package__ 答案：B\n5. 如何动态导入一个模块？\n# A. import mymodule # B. import \u0026#39;mymodule\u0026#39; # C. importlib.import_module(\u0026#39;mymodule\u0026#39;) # D. load(\u0026#39;mymodule\u0026#39;) 答案：C\n编程题 1. 编写一个模块 string_utils.py，包含以下功能：\n# string_utils.py \u0026#34;\u0026#34;\u0026#34;字符串处理工具模块\u0026#34;\u0026#34;\u0026#34; __all__ = [\u0026#39;reverse_string\u0026#39;, \u0026#39;count_vowels\u0026#39;, \u0026#39;is_palindrome\u0026#39;] def reverse_string(s): \u0026#34;\u0026#34;\u0026#34;反转字符串\u0026#34;\u0026#34;\u0026#34; return s[::-1] def count_vowels(s): \u0026#34;\u0026#34;\u0026#34;统计元音字母数量\u0026#34;\u0026#34;\u0026#34; vowels = \u0026#39;aeiouAEIOU\u0026#39; return sum(1 for c in s if c in vowels) def is_palindrome(s): \u0026#34;\u0026#34;\u0026#34;判断是否为回文\u0026#34;\u0026#34;\u0026#34; return s == s[::-1] def _private_helper(s): \u0026#34;\u0026#34;\u0026#34;私有辅助函数（不会被 * 导入）\u0026#34;\u0026#34;\u0026#34; return len(s) 2. 创建一个包结构，并使用各种导入方式：\n# 结构： # myapp/ # __init__.py # utils/ # __init__.py # text.py # math_tools.py # myapp/__init__.py \u0026#34;\u0026#34;\u0026#34;我的应用包\u0026#34;\u0026#34;\u0026#34; __version__ = \u0026#34;1.0.0\u0026#34; # myapp/utils/__init__.py from .text import clean_text, count_words from .math_tools import factorial __all__ = [\u0026#39;clean_text\u0026#39;, \u0026#39;count_words\u0026#39;, \u0026#39;factorial\u0026#39;] # myapp/utils/text.py def clean_text(text): \u0026#34;\u0026#34;\u0026#34;清理文本\u0026#34;\u0026#34;\u0026#34; return \u0026#39; \u0026#39;.join(text.split()) def count_words(text): \u0026#34;\u0026#34;\u0026#34;统计词数\u0026#34;\u0026#34;\u0026#34; return len(clean_text(text).split()) # myapp/utils/math_tools.py def factorial(n): \u0026#34;\u0026#34;\u0026#34;计算阶乘\u0026#34;\u0026#34;\u0026#34; if n \u0026lt; 0: raise ValueError(\u0026#34;负数没有阶乘\u0026#34;) if n \u0026lt;= 1: return 1 return n * factorial(n - 1) 3. 使用 importlib 动态加载模块：\nimport importlib.util import sys def load_module_from_path(module_name, file_path): \u0026#34;\u0026#34;\u0026#34;从指定路径动态加载模块\u0026#34;\u0026#34;\u0026#34; spec = importlib.util.spec_from_file_location(module_name, file_path) module = importlib.util.module_from_spec(spec) sys.modules[module_name] = module spec.loader.exec_module(module) return module # 使用示例 # module = load_module_from_path(\u0026#39;mymod\u0026#39;, \u0026#39;/path/to/mymodule.py\u0026#39;) # module.greet(\u0026#34;世界\u0026#34;) 问答题 Q1: 请解释 Python 中 import 语句的执行过程。\n执行 import mymodule 时，Python 依次：\n在 sys.modules 中查找是否已加载该模块 若未加载，按 sys.path 顺序搜索模块文件 找到后编译为字节码（.pyc 文件） 执行模块代码，创建模块对象 将模块对象存入 sys.modules 在当前命名空间创建对模块的引用 Q2: 什么是 __all__ 变量，它有什么作用？\n__all__ 是一个字符串列表，用于控制 from module import * 的行为。\n若定义了 __all__，则只导入列表中的成员 若未定义，则导入所有不以 _ 开头的成员 这是 Python 的显式优于隐式原则的体现 Q3: 何时使用相对导入？何时使用绝对导入？\n类型 语法 适用场景 绝对导入 from package import module Python 3+ 推荐，清晰明确 相对导入 from . import module 仅用于包内部，避免与标准库冲突 Python 3 建议：优先使用绝对导入，相对导入仅在包内部使用。\n参考资料 Python 官方文档 - import 系统 PEP 328 - Imports: Multi-Line and Absolute/Relative PEP 366 - Explicit Relative Imports ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-32-module-import/","summary":"\u003ch1 id=\"day32---模块与导入系统详解\"\u003eDay32 - 模块与导入系统详解\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"1-模块基础概念\"\u003e1. 模块基础概念\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e模块（Module）\u003c/strong\u003e 是 Python 中组织代码的基本单位。一个 \u003ccode\u003e.py\u003c/code\u003e 文件就是一个模块，模块中可以包含函数、类、变量以及可执行代码。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# mymodule.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egreet\u003c/span\u003e(name):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;你好，\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ename\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e！\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eCalculator\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eadd\u003c/span\u003e(self, a, b):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e b\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003esubtract\u003c/span\u003e(self, a, b):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e b\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ePI \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3.14159\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"2-import-语句详解\"\u003e2. import 语句详解\u003c/h3\u003e\n\u003ch4 id=\"21-基本导入\"\u003e2.1 基本导入\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e mymodule\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 调用函数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e mymodule\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egreet(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;张三\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# 输出: 你好，张三！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用类\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecalc \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e mymodule\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eCalculator()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(calc\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eadd(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 输出: 15\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 访问变量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(mymodule\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ePI)  \u003cspan style=\"color:#75715e\"\u003e# 输出: 3.14159\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"22-fromimport-语句\"\u003e2.2 from\u0026hellip;import 语句\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 导入特定成员\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e mymodule \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e greet, PI\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 直接使用（无需模块名前缀）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(greet(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;李四\u0026#34;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 输出: 你好，李四！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(PI)  \u003cspan style=\"color:#75715e\"\u003e# 输出: 3.14159\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 导入所有成员（不推荐）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e mymodule \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"23-as-别名使用\"\u003e2.3 as 别名使用\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e mymodule \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e m\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用简短别名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(m\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egreet(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;王五\u0026#34;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 输出: 你好，王五！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 部分导入起别名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e mymodule \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Calculator \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e Calc, PI \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e PI_VALUE\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecalc \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Calc()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(calc\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eadd(\u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 输出: 300\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"3-syspath-与模块搜索路径\"\u003e3. sys.path 与模块搜索路径\u003c/h3\u003e\n\u003cp\u003ePython 导入模块时，会按照以下顺序搜索：\u003c/p\u003e","tags":"python, module, import, sys","title":"Day32 - 模块与导入系统详解"},{"columns":"python-course","content":"Day33 - 包与命名空间详解 详细讲解 1. 包的基本概念 包（Package） 是包含 __init__.py 文件的目录，用于组织多个模块。包可以嵌套，形成层次结构。\nmypackage/ ├── __init__.py # 包初始化文件（必需） ├── module1.py ├── module2.py └── subpackage/ ├── __init__.py └── module3.py2. __init__.py 文件详解 2.1 作用 __init__.py 是 Python 包的标识文件，有以下作用：\n标识该目录是一个包 在包被导入时执行初始化代码 控制包的导出内容 # mypackage/__init__.py # 1. 初始化代码（包导入时执行） print(\u0026#34;mypackage 已被导入\u0026#34;) # 2. 定义包的版本 __version__ = \u0026#34;1.0.0\u0026#34; # 3. 简化包的导入接口 from .module1 import Class1 from .module2 import function1 # 4. 定义 __all__ 控制 from package import * __all__ = [\u0026#39;Class1\u0026#39;, \u0026#39;function1\u0026#39;, \u0026#39;subpackage\u0026#39;] 2.2 包的多级初始化 # mypackage/subpackage/__init__.py \u0026#34;\u0026#34;\u0026#34;子包初始化\u0026#34;\u0026#34;\u0026#34; print(\u0026#34;mypackage.subpackage 已加载\u0026#34;) # 从模块导入到包级别 from .module3 import ServiceClass __all__ = [\u0026#39;ServiceClass\u0026#39;] 2.3 __init__.py 常见用法 # 方式1：全部导入（不推荐） import mypackage.module1 import mypackage.module2 # 方式2：使用 __init__.py 暴露接口 # 在 __init__.py 中： # from .module1 import useful_function # 使用时： from mypackage import useful_function # 方式3：导入所有公开接口 # 在 __init__.py 中设置 __all__ 3. __name__ 属性详解 __name__ 是 Python 的内置变量，其值取决于代码的执行方式。\n# 测试 __name__ 的值 print(f\u0026#34;当前模块的 __name__: {__name__}\u0026#34;) 3.1 不同场景下的值 执行方式 __name__ 值 说明 直接运行脚本 __main__ 脚本作为主程序 作为模块导入 模块名 如 mypackage.module 作为包导入 包名 如 mypackage 3.2 实际应用 # config.py \u0026#34;\u0026#34;\u0026#34;配置文件模块\u0026#34;\u0026#34;\u0026#34; import os # 开发环境配置 DEV_CONFIG = { \u0026#39;debug\u0026#39;: True, \u0026#39;database\u0026#39;: \u0026#39;dev.db\u0026#39;, \u0026#39;port\u0026#39;: 8000 } # 生产环境配置 PROD_CONFIG = { \u0026#39;debug\u0026#39;: False, \u0026#39;database\u0026#39;: \u0026#39;prod.db\u0026#39;, \u0026#39;port\u0026#39;: 80 } def get_config(): \u0026#34;\u0026#34;\u0026#34;根据环境返回配置\u0026#34;\u0026#34;\u0026#34; env = os.getenv(\u0026#39;ENV\u0026#39;, \u0026#39;dev\u0026#39;) if env == \u0026#39;prod\u0026#39;: return PROD_CONFIG return DEV_CONFIG # 方式1：直接运行用于测试 if __name__ == \u0026#39;__main__\u0026#39;: print(\u0026#34;配置测试模式\u0026#34;) config = get_config() print(f\u0026#34;当前配置: {config}\u0026#34;) # 方式2：作为模块导入使用 # import config # cfg = config.get_config() 4. 命名空间（Namespace） 4.1 概念 命名空间是 Python 中用于隔离标识符的区域，避免名称冲突。\n# 命名空间示例 # 全局命名空间 global_var = \u0026#34;全局变量\u0026#34; def function(): # 局部命名空间 local_var = \u0026#34;局部变量\u0026#34; print(global_var) # 可以访问全局变量 print(local_var) # 可以访问局部变量 function() # print(local_var) # 错误！无法访问局部变量 4.2 命名空间的查找顺序 LEGB 规则： L (Local) → 局部命名空间（函数内部） E (Enclosing) → 闭包命名空间（嵌套函数） G (Global) → 全局命名空间（模块级别） B (Built-in) → 内置命名空间（Python 内置）# LEGB 示例 built_in_var = \u0026#34;Built-in\u0026#34; def outer(): enclosing_var = \u0026#34;Enclosing\u0026#34; def inner(): local_var = \u0026#34;Local\u0026#34; # 查找顺序：L → E → G → B print(local_var) # Local print(enclosing_var) # Enclosing print(built_in_var) # Built-in inner() outer() 5. 包的内置属性 import mypackage # __name__ 包名 print(mypackage.__name__) # mypackage # __file__ __init__.py 的路径 print(mypackage.__file__) # __path__ 包目录路径 print(mypackage.__path__) # 返回一个 _NamespacePath 对象 # __package__ 包的父包（顶级包为 None） print(mypackage.__package__) # None 或父包名 # __spec__ 模块规范 print(mypackage.__spec__) # __loader__ 模块加载器 print(mypackage.__loader__) 6. 包的结构设计最佳实践 6.1 标准包结构 myproject/ ├── __init__.py # 项目初始化，定义版本和公共接口 ├── config.py # 配置模块 ├── main.py # 入口文件 ├── utils/ # 工具包 │ ├── __init__.py │ ├── decorators.py │ └── helpers.py ├── models/ # 数据模型包 │ ├── __init__.py │ ├── user.py │ └── product.py └── services/ # 业务逻辑包 ├── __init__.py ├── auth.py └── database.py6.2 __init__.py 最佳实践 # myproject/__init__.py \u0026#34;\u0026#34;\u0026#34;MyProject - 一个示例项目\u0026#34;\u0026#34;\u0026#34; __version__ = \u0026#34;1.0.0\u0026#34; __author__ = \u0026#34;Your Name\u0026#34; # 导入公共接口 from .config import settings from .models.user import User # 定义公开接口 __all__ = [\u0026#39;settings\u0026#39;, \u0026#39;User\u0026#39;, \u0026#39;__version__\u0026#39;] # myproject/utils/__init__.py \u0026#34;\u0026#34;\u0026#34;工具模块\u0026#34;\u0026#34;\u0026#34; from .decorators import timer, retry from .helpers import format_date, parse_json __all__ = [\u0026#39;timer\u0026#39;, \u0026#39;retry\u0026#39;, \u0026#39;format_date\u0026#39;, \u0026#39;parse_json\u0026#39;] 7. 循环导入问题及解决 7.1 问题示例 # a.py import b def func_a(): return \u0026#34;A\u0026#34; class ClassA: def method(self): return b.func_b() # b.py import a # 循环导入！ def func_b(): return \u0026#34;B\u0026#34; class ClassB: def method(self): return a.func_a() 7.2 解决方案 方案1：延迟导入（在函数内部导入）\n# b.py def func_b(): import a # 延迟导入 return \u0026#34;B\u0026#34; class ClassB: def method(self): import a # 延迟导入 return a.func_a() 方案2：重构代码结构\n# 提取公共部分到单独的模块 # common.py def func_common(): return \u0026#34;Common\u0026#34; 方案3：使用 __init__.py 重新组织\n# package/__init__.py \u0026#34;\u0026#34;\u0026#34;在 __init__ 中只导入需要的，避免循环\u0026#34;\u0026#34;\u0026#34; from .module_a import ClassA # 放在最后避免循环 8. 命名空间包（Namespace Package） Python 3.3+ 支持命名空间包，不一定有 __init__.py 文件。\n# 命名空间包示例（PEP 420） # myproject/ # core/ # __init__.py # 可以没有 # module1.py # utils/ # __init__.py # 可以没有 # module2.py # 导入命名空间包 from myproject.core import module1 from myproject.utils import module2 背诵版 核心概念速记 ┌─────────────────────────────────────────────────────────────┐ │ 包与命名空间 │ ├─────────────────────────────────────────────────────────────┤ │ __init__.py ─ 包的入口，控制导出内容 │ │ __name__ ─ 模块名（__main__ 表示主程序） │ │ __path__ ─ 包目录路径 │ │ __all__ ─ 控制 from package import * │ ├─────────────────────────────────────────────────────────────┤ │ LEGB 查找顺序: Local → Enclosing → Global → Built-in │ ├─────────────────────────────────────────────────────────────┤ │ 命名空间包 ─ Python 3.3\u0026#43; 支持，无需 __init__.py │ └─────────────────────────────────────────────────────────────┘__name__ 取值速查 场景 __name__ 值 python script.py __main__ import module module import package package 命名空间速查 作用域 │ 说明 ─────────────┼───────────────────────── Local (L) │ 函数内部的变量 Enclosing(E) │ 嵌套函数的外层函数变量 Global (G) │ 模块级别的变量 Built-in (B) │ Python 内置函数/异常 考前记忆 面试重点 __init__.py 的作用\n标识目录为包 包导入时执行初始化 控制 from package import * 的行为 __name__ == '__main__' 的应用场景\n区分直接运行和被导入 常用于编写测试代码或入口逻辑 循环导入的解决方法\n延迟导入（在函数内部导入） 重构代码结构 调整导入顺序 LEGB 规则（高频）\nLocal → Enclosing → Global → Built-in 命名空间包特性\nPython 3.3+ 引入 不需要 __init__.py 支持多目录拼接包 记忆口诀 __init__包入口， __name__判主从。 循环导入要避免， 延迟导入记心中。 LEGB找变量， 命名空间各不同。 测试题 选择题 1. 关于 __init__.py 文件，以下说法正确的是？\n# A. 每个 Python 包都必须有 __init__.py 文件 # B. __init__.py 在包第一次被导入时执行 # C. __init__.py 不能为空 # D. __init__.py 中不能使用相对导入 答案：B（Python 3.3+ 的命名空间包不需要）\n2. 以下代码的输出是什么？\n# test_name.py def test(): print(__name__) test() print(__name__) # A. __main__ __main__ # B. test __main__ # C. test test # D. __main__ test 答案：A（函数内的 __name__ 也是 __main__）\n3. 在 Python 中，命名空间查找顺序是？\n# A. Global → Local → Built-in → Enclosing # B. Built-in → Global → Enclosing → Local # C. Local → Built-in → Global → Enclosing # D. Enclosing → Local → Built-in → Global 答案：B（LEGB 规则）\n4. 以下哪种方式可以解决循环导入问题？\n# A. 将导入语句放在模块开头 # B. 在函数内部进行延迟导入 # C. 删除所有导入语句 # D. 使用更深的嵌套 答案：B\n5. 命名空间包的特点是？\n# A. 必须有 __init__.py 文件 # B. 可以没有 __init__.py 文件 # C. 只能包含一个目录 # D. 不支持多级目录 答案：B（Python 3.3+ 支持）\n编程题 1. 设计一个完整的包结构：\n# calculator/ # __init__.py # basic.py # scientific.py # advanced.py # calculator/__init__.py \u0026#34;\u0026#34;\u0026#34;计算器包 - 提供各种数学运算\u0026#34;\u0026#34;\u0026#34; __version__ = \u0026#34;1.0.0\u0026#34; from .basic import add, subtract, multiply, divide from .scientific import power, sqrt, log, sin, cos, tan __all__ = [\u0026#39;add\u0026#39;, \u0026#39;subtract\u0026#39;, \u0026#39;multiply\u0026#39;, \u0026#39;divide\u0026#39;, \u0026#39;power\u0026#39;, \u0026#39;sqrt\u0026#39;, \u0026#39;log\u0026#39;, \u0026#39;sin\u0026#39;, \u0026#39;cos\u0026#39;, \u0026#39;tan\u0026#39;] # calculator/basic.py \u0026#34;\u0026#34;\u0026#34;基础运算模块\u0026#34;\u0026#34;\u0026#34; def add(a, b): \u0026#34;\u0026#34;\u0026#34;加法\u0026#34;\u0026#34;\u0026#34; return a + b def subtract(a, b): \u0026#34;\u0026#34;\u0026#34;减法\u0026#34;\u0026#34;\u0026#34; return a - b def multiply(a, b): \u0026#34;\u0026#34;\u0026#34;乘法\u0026#34;\u0026#34;\u0026#34; return a * b def divide(a, b): \u0026#34;\u0026#34;\u0026#34;除法\u0026#34;\u0026#34;\u0026#34; if b == 0: raise ZeroDivisionError(\u0026#34;除数不能为零\u0026#34;) return a / b # calculator/scientific.py \u0026#34;\u0026#34;\u0026#34;科学计算模块\u0026#34;\u0026#34;\u0026#34; import math def power(base, exponent): \u0026#34;\u0026#34;\u0026#34;幂运算\u0026#34;\u0026#34;\u0026#34; return math.pow(base, exponent) def sqrt(x): \u0026#34;\u0026#34;\u0026#34;平方根\u0026#34;\u0026#34;\u0026#34; if x \u0026lt; 0: raise ValueError(\u0026#34;负数没有实数平方根\u0026#34;) return math.sqrt(x) def log(x, base=math.e): \u0026#34;\u0026#34;\u0026#34;对数\u0026#34;\u0026#34;\u0026#34; if x \u0026lt;= 0: raise ValueError(\u0026#34;对数参数必须为正数\u0026#34;) return math.log(x, base) def sin(x): \u0026#34;\u0026#34;\u0026#34;正弦\u0026#34;\u0026#34;\u0026#34; return math.sin(x) def cos(x): \u0026#34;\u0026#34;\u0026#34;余弦\u0026#34;\u0026#34;\u0026#34; return math.cos(x) def tan(x): \u0026#34;\u0026#34;\u0026#34;正切\u0026#34;\u0026#34;\u0026#34; return math.tan(x) 2. 编写测试代码演示 __name__ 的用法：\n# runner.py \u0026#34;\u0026#34;\u0026#34;测试 __name__ 的使用\u0026#34;\u0026#34;\u0026#34; import sys import calculator def run_tests(): \u0026#34;\u0026#34;\u0026#34;运行测试（仅在直接运行时执行）\u0026#34;\u0026#34;\u0026#34; print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;运行测试套件\u0026#34;) print(\u0026#34;=\u0026#34; * 50) # 测试基础运算 assert calculator.add(2, 3) == 5 assert calculator.subtract(10, 4) == 6 assert calculator.multiply(3, 4) == 12 assert calculator.divide(10, 2) == 5 # 测试科学计算 assert abs(calculator.sqrt(16) - 4) \u0026lt; 0.0001 print(\u0026#34;所有测试通过！\u0026#34;) print(f\u0026#34;当前运行模式: {__name__}\u0026#34;) if __name__ == \u0026#39;__main__\u0026#39;: run_tests() print(f\u0026#34;模块名: {__name__}\u0026#34;) 3. 解决循环导入问题：\n# 问题代码： # user.py 导入 profile.py # profile.py 导入 user.py # user.py class User: def __init__(self, name): self.name = name self.profile = None def set_profile(self, profile): self.profile = profile # profile.py class Profile: def __init__(self, bio, user=None): self.bio = bio self.user = user # 解决方案 - 使用延迟导入 # manager.py class UserManager: def create_user_with_profile(self, name, bio): # 延迟导入避免循环 from user import User from profile import Profile user = User(name) profile = Profile(bio, user) user.set_profile(profile) return user, profile 问答题 Q1: __init__.py 文件有哪些主要作用？\n标识包：告诉 Python 该目录是一个包 初始化：包首次导入时执行初始化代码 控制导出：通过 __all__ 控制 from package import * 的行为 简化导入：将子模块的类/函数导入到包级别 Q2: 什么是命名空间？Python 中有哪些命名空间？\n命名空间是从名称到对象的映射。Python 有三类主要命名空间：\n内置命名空间：Python 预定义的函数、异常等（如 len, print, Exception） 全局命名空间：模块级别的变量和函数 局部命名空间：函数/方法内部的变量 查找顺序遵循 LEGB 规则。\nQ3: 如何避免循环导入问题？\n延迟导入：将 import 语句放在函数内部 重构代码：将公共部分提取到独立模块 调整结构：重新组织模块间的依赖关系 使用相对导入：在包内部使用相对导入 依赖注入：通过参数传递依赖而非在模块级别导入 Q4: __path__ 属性和 __file__ 属性有什么区别？\n属性 说明 示例 __file__ 模块/包的源文件路径 /path/to/package/__init__.py __path__ 包目录路径（只读属性） /path/to/package/ (NamespacePath 对象) __path__ 只存在于包中，是包的目录路径。\n参考资料 Python 官方文档 - 包 PEP 328 - Imports: Multi-Line and Absolute/Relative PEP 420 - Implicit Namespace Packages Python 命名空间与作用域 ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-33-package-name/","summary":"\u003ch1 id=\"day33---包与命名空间详解\"\u003eDay33 - 包与命名空间详解\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"1-包的基本概念\"\u003e1. 包的基本概念\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e包（Package）\u003c/strong\u003e 是包含 \u003ccode\u003e__init__.py\u003c/code\u003e 文件的目录，用于组织多个模块。包可以嵌套，形成层次结构。\u003c/p\u003e\nmypackage/\n├── __init__.py          # 包初始化文件（必需）\n├── module1.py\n├── module2.py\n└── subpackage/\n    ├── __init__.py\n    └── module3.py\u003ch3 id=\"2-__init__py-文件详解\"\u003e2. \u003ccode\u003e__init__.py\u003c/code\u003e 文件详解\u003c/h3\u003e\n\u003ch4 id=\"21-作用\"\u003e2.1 作用\u003c/h4\u003e\n\u003cp\u003e\u003ccode\u003e__init__.py\u003c/code\u003e 是 Python 包的标识文件，有以下作用：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e标识该目录是一个包\u003c/li\u003e\n\u003cli\u003e在包被导入时执行初始化代码\u003c/li\u003e\n\u003cli\u003e控制包的导出内容\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# mypackage/__init__.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 1. 初始化代码（包导入时执行）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;mypackage 已被导入\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 2. 定义包的版本\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e__version__ \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;1.0.0\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 3. 简化包的导入接口\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e .module1 \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Class1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e .module2 \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e function1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 4. 定义 __all__ 控制 from package import *\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e__all__ \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Class1\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;function1\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;subpackage\u0026#39;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"22-包的多级初始化\"\u003e2.2 包的多级初始化\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# mypackage/subpackage/__init__.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;子包初始化\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;mypackage.subpackage 已加载\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 从模块导入到包级别\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e .module3 \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e ServiceClass\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e__all__ \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ServiceClass\u0026#39;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"23-__init__py-常见用法\"\u003e2.3 \u003ccode\u003e__init__.py\u003c/code\u003e 常见用法\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方式1：全部导入（不推荐）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e mypackage.module1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e mypackage.module2\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方式2：使用 __init__.py 暴露接口\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 在 __init__.py 中：\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# from .module1 import useful_function\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用时：\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e mypackage \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e useful_function\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 方式3：导入所有公开接口\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 在 __init__.py 中设置 __all__\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"3-__name__-属性详解\"\u003e3. \u003ccode\u003e__name__\u003c/code\u003e 属性详解\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003e__name__\u003c/code\u003e 是 Python 的内置变量，其值取决于代码的执行方式。\u003c/p\u003e","tags":"python, package, __init__, __name__, namespace","title":"Day33 - 包与命名空间详解"},{"columns":"python-course","content":"Day34 - 文件读写与JSON处理 详细讲解 1. 文件打开与关闭 1.1 基本语法 # 传统方式 - 需要手动关闭 file = open(\u0026#39;example.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) content = file.read() file.close() # 忘记关闭会导致资源泄漏 # 推荐方式 - 使用 with 语句（自动关闭） with open(\u0026#39;example.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as file: content = file.read() # 文件在 with 块结束后自动关闭 1.2 文件打开模式 模式 说明 文件指针位置 如果文件存在 如果文件不存在 'r' 读取（默认） 开头 读取 报错 'w' 写入 开头 覆盖 创建 'x' 创建并写入 开头 报错 创建 'a' 追加 末尾 追加 创建 'r+' 读取+写入 开头 读取 报错 'w+' 读取+写入 开头 覆盖 创建 'a+' 读取+追加 末尾 追加 创建 1.3 编码问题 # 推荐使用 UTF-8 编码 with open(\u0026#39;file.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: content = f.read() # 处理不同编码 with open(\u0026#39;file.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;gbk\u0026#39;) as f: content = f.read() # 遇到编码错误时的处理 with open(\u0026#39;file.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;, errors=\u0026#39;ignore\u0026#39;) as f: content = f.read() with open(\u0026#39;file.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;, errors=\u0026#39;replace\u0026#39;) as f: content = f.read() # 替换为 ? 2. 文件读取操作 2.1 读取全部内容 # 读取整个文件 with open(\u0026#39;example.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: content = f.read() # 返回字符串 # 读取前 N 个字符 with open(\u0026#39;example.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: content = f.read(100) # 读取前100个字符 2.2 按行读取 # 读取单行（包含换行符） with open(\u0026#39;example.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: line1 = f.readline() line2 = f.readline() # 读取所有行（返回列表） with open(\u0026#39;example.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: lines = f.readlines() # 直接迭代文件对象（推荐，内存高效） with open(\u0026#39;example.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: for line in f: print(line.strip()) # strip() 去除换行符 2.3 逐字符读取 with open(\u0026#39;example.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: while True: char = f.read(1) # 读取单个字符 if not char: break print(char, end=\u0026#39;\u0026#39;) 3. 文件写入操作 3.1 写入字符串 # 写入单行（不自动添加换行符） with open(\u0026#39;output.txt\u0026#39;, \u0026#39;w\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: f.write(\u0026#39;第一行\u0026#39;) f.write(\u0026#39;第二行\u0026#39;) # 不会换行 # 写入多行 with open(\u0026#39;output.txt\u0026#39;, \u0026#39;w\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: lines = [\u0026#39;第一行\\n\u0026#39;, \u0026#39;第二行\\n\u0026#39;, \u0026#39;第三行\\n\u0026#39;] f.writelines(lines) # 使用 print 函数写入（自动添加换行符） with open(\u0026#39;output.txt\u0026#39;, \u0026#39;w\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: print(\u0026#39;第一行\u0026#39;, file=f) print(\u0026#39;第二行\u0026#39;, file=f) 3.2 追加模式 # 在文件末尾追加 with open(\u0026#39;log.txt\u0026#39;, \u0026#39;a\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: f.write(\u0026#39;新的日志条目\\n\u0026#39;) 3.3 二进制文件 # 写入二进制数据 with open(\u0026#39;data.bin\u0026#39;, \u0026#39;wb\u0026#39;) as f: f.write(b\u0026#39;\\x00\\x01\\x02\\x03\u0026#39;) # 读取二进制数据 with open(\u0026#39;data.bin\u0026#39;, \u0026#39;rb\u0026#39;) as f: data = f.read() print(data) # b\u0026#39;\\x00\\x01\\x02\\x03\u0026#39; 4. 文件指针操作 with open(\u0026#39;example.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: # 获取文件指针位置 print(f.tell()) # 0 # 读取一些内容 content = f.read(10) print(f.tell()) # 10 # 移动文件指针 f.seek(0) # 移到开头 print(f.tell()) # 0 f.seek(5) # 移到第5个字节 print(f.tell()) # 5 # 从末尾往前移动（需要使用二进制模式） # f.seek(-10, 2) # 从文件末尾往前10字节 5. JSON 数据处理 5.1 JSON 模块概述 JSON（JavaScript Object Notation）是一种轻量级数据交换格式。\nimport json # Python 对象与 JSON 的对应关系： # dict ↔ object # list/tuple ↔ array # str ↔ string # int/float ↔ number # True/None ↔ true/null # False ↔ false 5.2 序列化（Python → JSON） # 字典转 JSON 字符串 data = {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;} # 转为字符串 json_str = json.dumps(data) print(json_str) # 输出: {\u0026#34;name\u0026#34;: \u0026#34;\\u5f20\\u4e09\u0026#34;, \u0026#34;age\u0026#34;: 25, \u0026#34;city\u0026#34;: \u0026#34;\\u5317\\u4eac\u0026#34;} # 美化输出 json_str_pretty = json.dumps(data, indent=4, ensure_ascii=False) print(json_str_pretty) # 按键排序 json_str_sorted = json.dumps(data, sort_keys=True, ensure_ascii=False) print(json_str_sorted) # 处理特殊类型 class Person: def __init__(self, name, age): self.name = name self.age = age # 自定义编码器 def person_encoder(obj): if isinstance(obj, Person): return {\u0026#39;name\u0026#39;: obj.name, \u0026#39;age\u0026#39;: obj.age, \u0026#39;type\u0026#39;: \u0026#39;Person\u0026#39;} raise TypeError(f\u0026#34;Object of type {type(obj)} is not JSON serializable\u0026#34;) person = Person(\u0026#39;李四\u0026#39;, 30) json_str = json.dumps(person, default=person_encoder, ensure_ascii=False) print(json_str) 5.3 反序列化（JSON → Python） # JSON 字符串转字典 json_str = \u0026#39;{\u0026#34;name\u0026#34;: \u0026#34;张三\u0026#34;, \u0026#34;age\u0026#34;: 25}\u0026#39; data = json.loads(json_str) print(data) # {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25} # 从文件读取 JSON with open(\u0026#39;data.json\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: data = json.load(f) # 处理特殊解码 def person_decoder(dct): if \u0026#39;type\u0026#39; in dct and dct[\u0026#39;type\u0026#39;] == \u0026#39;Person\u0026#39;: return Person(dct[\u0026#39;name\u0026#39;], dct[\u0026#39;age\u0026#39;]) return dct json_str = \u0026#39;{\u0026#34;name\u0026#34;: \u0026#34;王五\u0026#34;, \u0026#34;age\u0026#34;: 28, \u0026#34;type\u0026#34;: \u0026#34;Person\u0026#34;}\u0026#39; person = json.loads(json_str, object_hook=person_decoder) 5.4 JSON 文件操作 # 写入 JSON 文件 data = { \u0026#39;users\u0026#39;: [ {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25}, {\u0026#39;name\u0026#39;: \u0026#39;李四\u0026#39;, \u0026#39;age\u0026#39;: 30} ], \u0026#39;count\u0026#39;: 2 } with open(\u0026#39;users.json\u0026#39;, \u0026#39;w\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: json.dump(data, f, indent=4, ensure_ascii=False) # 读取 JSON 文件 with open(\u0026#39;users.json\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: data = json.load(f) print(data) # 追加写入 JSON Lines 格式 with open(\u0026#39;logs.jsonl\u0026#39;, \u0026#39;a\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: log_entry = {\u0026#39;timestamp\u0026#39;: \u0026#39;2024-01-01\u0026#39;, \u0026#39;level\u0026#39;: \u0026#39;INFO\u0026#39;, \u0026#39;message\u0026#39;: \u0026#39;系统启动\u0026#39;} f.write(json.dumps(log_entry, ensure_ascii=False) + \u0026#39;\\n\u0026#39;) 6. 文件操作上下文管理器 # 基本上下文管理器 with open(\u0026#39;file.txt\u0026#39;, \u0026#39;r\u0026#39;) as f: content = f.read() # 多个文件 with open(\u0026#39;input.txt\u0026#39;, \u0026#39;r\u0026#39;) as infile, open(\u0026#39;output.txt\u0026#39;, \u0026#39;w\u0026#39;) as outfile: content = infile.read() outfile.write(content.upper()) # 自定义上下文管理器 class FileManager: def __init__(self, filename, mode): self.filename = filename self.mode = mode self.file = None def __enter__(self): self.file = open(self.filename, self.mode) return self.file def __exit__(self, exc_type, exc_val, exc_tb): if self.file: self.file.close() return False # 不抑制异常 # 使用 with FileManager(\u0026#39;test.txt\u0026#39;, \u0026#39;w\u0026#39;) as f: f.write(\u0026#39;Hello, World!\u0026#39;) 7. 实战案例：配置文件读写 # config.json # { # \u0026#34;database\u0026#34;: { # \u0026#34;host\u0026#34;: \u0026#34;localhost\u0026#34;, # \u0026#34;port\u0026#34;: 3306, # \u0026#34;name\u0026#34;: \u0026#34;myapp\u0026#34; # }, # \u0026#34;app\u0026#34;: { # \u0026#34;debug\u0026#34;: true, # \u0026#34;secret_key\u0026#34;: \u0026#34;abc123\u0026#34; # } # } import json from pathlib import Path class Config: def __init__(self, config_path=\u0026#39;config.json\u0026#39;): self.config_path = Path(config_path) self.data = {} def load(self): \u0026#34;\u0026#34;\u0026#34;加载配置文件\u0026#34;\u0026#34;\u0026#34; if self.config_path.exists(): with open(self.config_path, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: self.data = json.load(f) else: print(f\u0026#34;配置文件 {self.config_path} 不存在，使用默认配置\u0026#34;) self.data = self.get_default_config() return self def save(self): \u0026#34;\u0026#34;\u0026#34;保存配置到文件\u0026#34;\u0026#34;\u0026#34; with open(self.config_path, \u0026#39;w\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: json.dump(self.data, f, indent=4, ensure_ascii=False) @staticmethod def get_default_config(): \u0026#34;\u0026#34;\u0026#34;获取默认配置\u0026#34;\u0026#34;\u0026#34; return { \u0026#39;database\u0026#39;: { \u0026#39;host\u0026#39;: \u0026#39;localhost\u0026#39;, \u0026#39;port\u0026#39;: 5432, \u0026#39;name\u0026#39;: \u0026#39;default_db\u0026#39;, \u0026#39;user\u0026#39;: \u0026#39;admin\u0026#39;, \u0026#39;password\u0026#39;: \u0026#39;admin\u0026#39; }, \u0026#39;app\u0026#39;: { \u0026#39;debug\u0026#39;: False, \u0026#39;secret_key\u0026#39;: \u0026#39;change-me-in-production\u0026#39;, \u0026#39;log_level\u0026#39;: \u0026#39;INFO\u0026#39; } } def get(self, key, default=None): \u0026#34;\u0026#34;\u0026#34;获取配置项（支持点号分隔的路径）\u0026#34;\u0026#34;\u0026#34; keys = key.split(\u0026#39;.\u0026#39;) value = self.data for k in keys: if isinstance(value, dict): value = value.get(k) if value is None: return default else: return default return value def set(self, key, value): \u0026#34;\u0026#34;\u0026#34;设置配置项\u0026#34;\u0026#34;\u0026#34; keys = key.split(\u0026#39;.\u0026#39;) target = self.data for k in keys[:-1]: if k not in target: target[k] = {} target = target[k] target[keys[-1]] = value # 使用示例 if __name__ == \u0026#39;__main__\u0026#39;: config = Config(\u0026#39;app_config.json\u0026#39;) config.load() # 获取配置 db_host = config.get(\u0026#39;database.host\u0026#39;) print(f\u0026#34;数据库主机: {db_host}\u0026#34;) # 修改配置 config.set(\u0026#39;app.debug\u0026#39;, True) config.save() 背诵版 核心速查表 ┌─────────────────────────────────────────────────────────────┐ │ 文件操作模式 │ ├─────────────────────────────────────────────────────────────┤ │ r │ 读取 │ 开头 │ 文件不存在报错 │ │ w │ 写入 │ 开头 │ 文件不存在创建，存在的覆盖 │ │ a │ 追加 │ 末尾 │ 文件不存在创建 │ │ x │ 新建 │ 开头 │ 文件存在报错 │ │ \u0026#43; │ 读写 │ │ 组合使用如 r\u0026#43;, w\u0026#43;, a\u0026#43; │ ├─────────────────────────────────────────────────────────────┤ │ b │ 二进制 │ 组合使用如 rb, wb, ab │ └─────────────────────────────────────────────────────────────┘JSON 操作速查 操作 函数 说明 Python → JSON 字符串 json.dumps(obj) 序列化 JSON 字符串 → Python json.loads(str) 反序列化 Python → JSON 文件 json.dump(obj, f) 写入文件 JSON 文件 → Python json.load(f) 读取文件 读取方法对比 方法 返回值 特点 read() str 读取全部 readline() str 读取一行 readlines() list 读取所有行到列表 for line in f - 迭代（推荐内存高效） 考前记忆 面试重点 with 语句的优势\n自动关闭文件 异常安全 避免资源泄漏 read() vs readlines() vs 迭代\nread() 一次性读取，内存占用大 readlines() 返回列表，占用内存 迭代方式最节省内存（推荐） json.dump() vs json.dumps()\ndump() 写入文件 dumps() 转为字符串 ensure_ascii=False 的重要性\n允许非 ASCII 字符（如中文）正常显示 不设置会转义为 \\uXXXX 文件指针操作\ntell() 获取位置 seek(offset, whence) 移动位置 记忆口诀 文件操作用 with， 自动关闭不失手。 json dumps 序列化， loads 反序列化。 read readline readlines， 迭代读取最推荐。 测试题 选择题 1. 下面哪个选项可以正确读取文件所有行？\n# A. with open(\u0026#39;file.txt\u0026#39;, \u0026#39;r\u0026#39;) as f: content = f.read() # B. with open(\u0026#39;file.txt\u0026#39;, \u0026#39;r\u0026#39;) as f: lines = f.readlines() # C. with open(\u0026#39;file.txt\u0026#39;, \u0026#39;r\u0026#39;) as f: for line in f: print(line) # D. 以上全部正确 答案：D\n2. 如果要追加内容到文件，应该使用哪个模式？\n# A. \u0026#39;r+\u0026#39; # B. \u0026#39;w\u0026#39; # C. \u0026#39;a\u0026#39; # D. \u0026#39;x\u0026#39; 答案：C\n3. json.dumps(data, ensure_ascii=False) 的作用是？\n# A. 忽略所有 ASCII 字符 # B. 保留非 ASCII 字符（如中文） # C. 将所有字符转为 ASCII # D. 报错 答案：B\n4. 读取大文件时，推荐使用哪种方式？\n# A. read() 一次性读取 # B. readlines() 读取到列表 # C. for line in file 迭代 # D. readline() 循环 答案：C\n5. seek(0) 的作用是？\n# A. 移到文件开头 # B. 移到文件末尾 # C. 当前位置 # D. 下一行 答案：A\n编程题 1. 文件复制程序：\ndef copy_file(src, dst): \u0026#34;\u0026#34;\u0026#34;复制文件\u0026#34;\u0026#34;\u0026#34; with open(src, \u0026#39;rb\u0026#39;) as src_file: with open(dst, \u0026#39;wb\u0026#39;) as dst_file: # 分块复制（适合大文件） while chunk := src_file.read(8192): dst_file.write(chunk) print(f\u0026#34;已复制: {src} -\u0026gt; {dst}\u0026#34;) # 使用 copy_file(\u0026#39;source.txt\u0026#39;, \u0026#39;destination.txt\u0026#39;) 2. 日志文件处理：\nimport json from datetime import datetime def append_log(log_file, level, message): \u0026#34;\u0026#34;\u0026#34;追加日志到 JSON Lines 文件\u0026#34;\u0026#34;\u0026#34; log_entry = { \u0026#39;timestamp\u0026#39;: datetime.now().isoformat(), \u0026#39;level\u0026#39;: level, \u0026#39;message\u0026#39;: message } with open(log_file, \u0026#39;a\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: f.write(json.dumps(log_entry, ensure_ascii=False) + \u0026#39;\\n\u0026#39;) def read_logs(log_file): \u0026#34;\u0026#34;\u0026#34;读取所有日志\u0026#34;\u0026#34;\u0026#34; logs = [] with open(log_file, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: for line in f: if line.strip(): logs.append(json.loads(line)) return logs def filter_logs(log_file, level): \u0026#34;\u0026#34;\u0026#34;按级别过滤日志\u0026#34;\u0026#34;\u0026#34; with open(log_file, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: for line in f: if line.strip(): entry = json.loads(line) if entry[\u0026#39;level\u0026#39;] == level: yield entry # 使用 append_log(\u0026#39;app.log\u0026#39;, \u0026#39;INFO\u0026#39;, \u0026#39;应用启动\u0026#39;) append_log(\u0026#39;app.log\u0026#39;, \u0026#39;ERROR\u0026#39;, \u0026#39;发生错误\u0026#39;) append_log(\u0026#39;app.log\u0026#39;, \u0026#39;INFO\u0026#39;, \u0026#39;处理完成\u0026#39;) # 读取所有日志 all_logs = read_logs(\u0026#39;app.log\u0026#39;) print(f\u0026#34;共 {len(all_logs)} 条日志\u0026#34;) # 过滤错误日志 for log in filter_logs(\u0026#39;app.log\u0026#39;, \u0026#39;ERROR\u0026#39;): print(f\u0026#34;[{log[\u0026#39;timestamp\u0026#39;]}] {log[\u0026#39;message\u0026#39;]}\u0026#34;) 3. 配置文件管理器：\nimport json class ConfigManager: \u0026#34;\u0026#34;\u0026#34;配置文件管理器\u0026#34;\u0026#34;\u0026#34; def __init__(self, config_file=\u0026#39;config.json\u0026#39;): self.config_file = config_file self.config = {} self.load() def load(self): \u0026#34;\u0026#34;\u0026#34;从文件加载配置\u0026#34;\u0026#34;\u0026#34; try: with open(self.config_file, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: self.config = json.load(f) except FileNotFoundError: print(f\u0026#34;配置文件 {self.config_file} 不存在\u0026#34;) self.config = self._default_config() def save(self): \u0026#34;\u0026#34;\u0026#34;保存配置到文件\u0026#34;\u0026#34;\u0026#34; with open(self.config_file, \u0026#39;w\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: json.dump(self.config, f, indent=4, ensure_ascii=False) @staticmethod def _default_config(): \u0026#34;\u0026#34;\u0026#34;默认配置\u0026#34;\u0026#34;\u0026#34; return { \u0026#39;version\u0026#39;: \u0026#39;1.0.0\u0026#39;, \u0026#39;database\u0026#39;: { \u0026#39;host\u0026#39;: \u0026#39;localhost\u0026#39;, \u0026#39;port\u0026#39;: 3306, \u0026#39;name\u0026#39;: \u0026#39;testdb\u0026#39;, \u0026#39;charset\u0026#39;: \u0026#39;utf8mb4\u0026#39; }, \u0026#39;server\u0026#39;: { \u0026#39;host\u0026#39;: \u0026#39;0.0.0.0\u0026#39;, \u0026#39;port\u0026#39;: 8080, \u0026#39;debug\u0026#39;: True }, \u0026#39;logging\u0026#39;: { \u0026#39;level\u0026#39;: \u0026#39;INFO\u0026#39;, \u0026#39;file\u0026#39;: \u0026#39;app.log\u0026#39; } } def get(self, key_path): \u0026#34;\u0026#34;\u0026#34;获取配置项（支持路径如 \u0026#39;database.host\u0026#39;）\u0026#34;\u0026#34;\u0026#34; keys = key_path.split(\u0026#39;.\u0026#39;) value = self.config for key in keys: if isinstance(value, dict): value = value.get(key) else: return None return value def set(self, key_path, value): \u0026#34;\u0026#34;\u0026#34;设置配置项\u0026#34;\u0026#34;\u0026#34; keys = key_path.split(\u0026#39;.\u0026#39;) target = self.config for key in keys[:-1]: target = target.setdefault(key, {}) target[keys[-1]] = value # 使用示例 if __name__ == \u0026#39;__main__\u0026#39;: config = ConfigManager(\u0026#39;app_config.json\u0026#39;) # 读取配置 print(f\u0026#34;数据库主机: {config.get(\u0026#39;database.host\u0026#39;)}\u0026#34;) print(f\u0026#34;服务器端口: {config.get(\u0026#39;server.port\u0026#39;)}\u0026#34;) # 修改配置 config.set(\u0026#39;server.debug\u0026#39;, False) config.set(\u0026#39;database.host\u0026#39;, \u0026#39;192.168.1.100\u0026#39;) # 保存 config.save() print(\u0026#34;配置已保存\u0026#34;) 问答题 Q1: 为什么推荐使用 with 语句操作文件？\n自动关闭：代码块结束后自动调用 close() 异常安全：即使发生异常也会关闭文件 代码简洁：无需手动 try-finally 避免资源泄漏：确保文件描述符被释放 Q2: 如何处理不同编码的文件？\n# 常见编码处理 with open(\u0026#39;file.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: # UTF-8 pass with open(\u0026#39;file.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;gbk\u0026#39;) as f: # GBK pass # 错误处理 with open(\u0026#39;file.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;, errors=\u0026#39;ignore\u0026#39;) as f: # 忽略错误 pass with open(\u0026#39;file.txt\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;, errors=\u0026#39;replace\u0026#39;) as f: # 替换为 ? pass Q3: JSON 和 Python 字典的区别是什么？\n方面 JSON Python dict 类型 字符串格式 Python 对象 键 必须是字符串 可哈希对象 值 有限类型 任意类型 布尔值 true/false True/False 空值 null None 注释 不支持 支持 参考资料 Python 官方文档 - io Python 官方文档 - json Python 文件操作详解 ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-34-file-read-write/","summary":"\u003ch1 id=\"day34---文件读写与json处理\"\u003eDay34 - 文件读写与JSON处理\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"1-文件打开与关闭\"\u003e1. 文件打开与关闭\u003c/h3\u003e\n\u003ch4 id=\"11-基本语法\"\u003e1.1 基本语法\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 传统方式 - 需要手动关闭\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003efile \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;example.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003econtent \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e file\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eread()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003efile\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eclose()  \u003cspan style=\"color:#75715e\"\u003e# 忘记关闭会导致资源泄漏\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 推荐方式 - 使用 with 语句（自动关闭）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;example.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e file:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    content \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e file\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eread()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 文件在 with 块结束后自动关闭\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"12-文件打开模式\"\u003e1.2 文件打开模式\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e模式\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n          \u003cth\u003e文件指针位置\u003c/th\u003e\n          \u003cth\u003e如果文件存在\u003c/th\u003e\n          \u003cth\u003e如果文件不存在\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e'r'\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e读取（默认）\u003c/td\u003e\n          \u003ctd\u003e开头\u003c/td\u003e\n          \u003ctd\u003e读取\u003c/td\u003e\n          \u003ctd\u003e报错\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e'w'\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e写入\u003c/td\u003e\n          \u003ctd\u003e开头\u003c/td\u003e\n          \u003ctd\u003e覆盖\u003c/td\u003e\n          \u003ctd\u003e创建\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e'x'\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e创建并写入\u003c/td\u003e\n          \u003ctd\u003e开头\u003c/td\u003e\n          \u003ctd\u003e报错\u003c/td\u003e\n          \u003ctd\u003e创建\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e'a'\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e追加\u003c/td\u003e\n          \u003ctd\u003e末尾\u003c/td\u003e\n          \u003ctd\u003e追加\u003c/td\u003e\n          \u003ctd\u003e创建\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e'r+'\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e读取+写入\u003c/td\u003e\n          \u003ctd\u003e开头\u003c/td\u003e\n          \u003ctd\u003e读取\u003c/td\u003e\n          \u003ctd\u003e报错\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e'w+'\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e读取+写入\u003c/td\u003e\n          \u003ctd\u003e开头\u003c/td\u003e\n          \u003ctd\u003e覆盖\u003c/td\u003e\n          \u003ctd\u003e创建\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e'a+'\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e读取+追加\u003c/td\u003e\n          \u003ctd\u003e末尾\u003c/td\u003e\n          \u003ctd\u003e追加\u003c/td\u003e\n          \u003ctd\u003e创建\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"13-编码问题\"\u003e1.3 编码问题\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 推荐使用 UTF-8 编码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    content \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eread()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 处理不同编码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;gbk\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    content \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eread()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 遇到编码错误时的处理\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e, errors\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ignore\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    content \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eread()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e, errors\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;replace\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    content \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eread()  \u003cspan style=\"color:#75715e\"\u003e# 替换为 ?\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"2-文件读取操作\"\u003e2. 文件读取操作\u003c/h3\u003e\n\u003ch4 id=\"21-读取全部内容\"\u003e2.1 读取全部内容\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 读取整个文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;example.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    content \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eread()  \u003cspan style=\"color:#75715e\"\u003e# 返回字符串\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 读取前 N 个字符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;example.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    content \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eread(\u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 读取前100个字符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"22-按行读取\"\u003e2.2 按行读取\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 读取单行（包含换行符）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;example.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    line1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ereadline()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    line2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ereadline()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 读取所有行（返回列表）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;example.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    lines \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ereadlines()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 直接迭代文件对象（推荐，内存高效）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;example.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e line \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(line\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estrip())  \u003cspan style=\"color:#75715e\"\u003e# strip() 去除换行符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"23-逐字符读取\"\u003e2.3 逐字符读取\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;example.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ewhile\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        char \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eread(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 读取单个字符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e char:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ebreak\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(char, end\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"3-文件写入操作\"\u003e3. 文件写入操作\u003c/h3\u003e\n\u003ch4 id=\"31-写入字符串\"\u003e3.1 写入字符串\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 写入单行（不自动添加换行符）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;output.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;w\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewrite(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;第一行\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewrite(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;第二行\u0026#39;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 不会换行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 写入多行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;output.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;w\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    lines \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;第一行\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;第二行\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;第三行\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewritelines(lines)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用 print 函数写入（自动添加换行符）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;output.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;w\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;第一行\u0026#39;\u003c/span\u003e, file\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003ef)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;第二行\u0026#39;\u003c/span\u003e, file\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003ef)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"32-追加模式\"\u003e3.2 追加模式\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 在文件末尾追加\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;log.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;a\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewrite(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;新的日志条目\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"33-二进制文件\"\u003e3.3 二进制文件\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 写入二进制数据\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;data.bin\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;wb\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewrite(\u003cspan style=\"color:#e6db74\"\u003eb\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\x00\\x01\\x02\\x03\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 读取二进制数据\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;data.bin\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;rb\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    data \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eread()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(data)  \u003cspan style=\"color:#75715e\"\u003e# b\u0026#39;\\x00\\x01\\x02\\x03\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"4-文件指针操作\"\u003e4. 文件指针操作\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;example.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 获取文件指针位置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003etell())  \u003cspan style=\"color:#75715e\"\u003e# 0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 读取一些内容\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    content \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eread(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003etell())  \u003cspan style=\"color:#75715e\"\u003e# 10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 移动文件指针\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eseek(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e)        \u003cspan style=\"color:#75715e\"\u003e# 移到开头\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003etell())  \u003cspan style=\"color:#75715e\"\u003e# 0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eseek(\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e)        \u003cspan style=\"color:#75715e\"\u003e# 移到第5个字节\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003etell())  \u003cspan style=\"color:#75715e\"\u003e# 5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 从末尾往前移动（需要使用二进制模式）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# f.seek(-10, 2)  # 从文件末尾往前10字节\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"5-json-数据处理\"\u003e5. JSON 数据处理\u003c/h3\u003e\n\u003ch4 id=\"51-json-模块概述\"\u003e5.1 JSON 模块概述\u003c/h4\u003e\n\u003cp\u003eJSON（JavaScript Object Notation）是一种轻量级数据交换格式。\u003c/p\u003e","tags":"python, file, read, write, json","title":"Day34 - 文件读写与JSON处理"},{"columns":"python-course","content":"Day35 - 文件处理综合 (CSV/shutil/os/pathlib) 详细讲解 1. CSV 文件处理 1.1 CSV 模块基础 import csv # 准备数据 data = [ [\u0026#39;姓名\u0026#39;, \u0026#39;年龄\u0026#39;, \u0026#39;城市\u0026#39;], [\u0026#39;张三\u0026#39;, \u0026#39;25\u0026#39;, \u0026#39;北京\u0026#39;], [\u0026#39;李四\u0026#39;, \u0026#39;30\u0026#39;, \u0026#39;上海\u0026#39;], [\u0026#39;王五\u0026#39;, \u0026#39;28\u0026#39;, \u0026#39;广州\u0026#39;] ] # 写入 CSV 文件 with open(\u0026#39;output.csv\u0026#39;, \u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: writer = csv.writer(f) writer.writerows(data) # 写入多行 # 读取 CSV 文件 with open(\u0026#39;output.csv\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: reader = csv.reader(f) for row in reader: print(row) 注意：newline='' 在写入 CSV 时必须使用，否则在 Windows 上可能导致行距加倍。\n1.2 字典方式操作 CSV import csv # 写入字典格式 fieldnames = [\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;, \u0026#39;city\u0026#39;] data = [ {\u0026#39;name\u0026#39;: \u0026#39;张三\u0026#39;, \u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;北京\u0026#39;}, {\u0026#39;name\u0026#39;: \u0026#39;李四\u0026#39;, \u0026#39;age\u0026#39;: 30, \u0026#39;city\u0026#39;: \u0026#39;上海\u0026#39;} ] with open(\u0026#39;dict_data.csv\u0026#39;, \u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() # 写入表头 writer.writerows(data) # 读取字典格式 with open(\u0026#39;dict_data.csv\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: reader = csv.DictReader(f) for row in reader: print(f\u0026#34;{row[\u0026#39;name\u0026#39;]} - {row[\u0026#39;age\u0026#39;]} - {row[\u0026#39;city\u0026#39;]}\u0026#34;) 1.3 CSV 高级选项 import csv # 自定义分隔符 with open(\u0026#39;tab_data.tsv\u0026#39;, \u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: writer = csv.writer(f, delimiter=\u0026#39;\\t\u0026#39;) writer.writerows(data) # 引用处理 with open(\u0026#39;quoted.csv\u0026#39;, \u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: writer = csv.writer(f, quoting=csv.QUOTE_ALL) # 所有字段加引号 writer.writerows(data) # quoting 选项： # QUOTE_ALL - 所有字段加引号 # QUOTE_MINIMAL - 特殊字符字段加引号（默认） # QUOTE_NONNUMERIC - 非数字字段加引号 # QUOTE_NONE - 不加引号 1.4 处理大 CSV 文件 import csv # 使用生成器处理大文件 def read_csv_chunked(filepath, chunk_size=1000): \u0026#34;\u0026#34;\u0026#34;分块读取大 CSV 文件\u0026#34;\u0026#34;\u0026#34; with open(filepath, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: reader = csv.reader(f) header = next(reader) # 读取表头 chunk = [] for row in reader: chunk.append(row) if len(chunk) \u0026gt;= chunk_size: yield header, chunk chunk = [] if chunk: # 处理最后一块 yield header, chunk # 使用 for header, chunk in read_csv_chunked(\u0026#39;large_file.csv\u0026#39;): print(f\u0026#34;处理 {len(chunk)} 条记录\u0026#34;) # 处理每块数据 2. shutil 模块 - 高级文件操作 2.1 复制操作 import shutil # 复制文件 shutil.copy(\u0026#39;source.txt\u0026#39;, \u0026#39;dest.txt\u0026#39;) # 复制文件内容 shutil.copy2(\u0026#39;source.txt\u0026#39;, \u0026#39;dest.txt\u0026#39;) # 复制文件并保留元数据 # 复制目录 shutil.copytree(\u0026#39;source_dir\u0026#39;, \u0026#39;dest_dir\u0026#39;) # 递归复制整个目录 # 复制到文件夹 shutil.copy(\u0026#39;file.txt\u0026#39;, \u0026#39;target_dir/\u0026#39;) # 目标可以是目录 2.2 移动和重命名 import shutil # 移动文件 shutil.move(\u0026#39;source.txt\u0026#39;, \u0026#39;dest.txt\u0026#39;) # 移动目录 shutil.move(\u0026#39;source_dir\u0026#39;, \u0026#39;dest_dir\u0026#39;) # 重命名（同一目录下移动即重命名） shutil.move(\u0026#39;old_name.txt\u0026#39;, \u0026#39;new_name.txt\u0026#39;) 2.3 删除操作 import shutil # 删除目录（必须是空目录） import os os.rmdir(\u0026#39;empty_dir\u0026#39;) # 删除目录树（递归删除） shutil.rmtree(\u0026#39;dir_to_remove\u0026#39;) # 安全删除（移动到回收站，可安装 send2trash 库） # pip install send2trash try: import send2trash send2trash.send2trash(\u0026#39;file_to_delete.txt\u0026#39;) except ImportError: print(\u0026#34;请安装: pip install send2trash\u0026#34;) 2.4 归档和压缩 import shutil # 创建归档（zip, tar, gztar, bztar, xztar） shutil.make_archive(\u0026#39;backup\u0026#39;, \u0026#39;zip\u0026#39;, \u0026#39;directory_to_backup\u0026#39;) # 解压归档 shutil.unpack_archive(\u0026#39;backup.zip\u0026#39;, \u0026#39;extract_here\u0026#39;) # 列出支持的格式 print(shutil.get_archive_formats()) print(shutil.get_unpack_formats()) 2.5 其他有用功能 import shutil # 获取磁盘使用情况 total, used, free = shutil.disk_usage(\u0026#39;/\u0026#39;) print(f\u0026#34;总容量: {total // (2**30)} GB\u0026#34;) print(f\u0026#34;已使用: {used // (2**30)} GB\u0026#34;) print(f\u0026#34;剩余: {free // (2**30)} GB\u0026#34;) # 复制权限（仅 Unix） # shutil.copystat(src, dst) # 获取临时目录 print(shutil.gettempdir()) # 命令行工具包装 # shutil.which(\u0026#39;python\u0026#39;) # 查找命令路径 3. os 模块 - 系统交互 3.1 路径操作 import os # 获取当前工作目录 print(os.getcwd()) # 改变当前目录 os.chdir(\u0026#39;/path/to/directory\u0026#39;) # 返回绝对路径 os.path.abspath(\u0026#39;relative/path\u0026#39;) # 判断路径类型 os.path.isfile(\u0026#39;file.txt\u0026#39;) # 是否为文件 os.path.isdir(\u0026#39;directory\u0026#39;) # 是否为目录 os.path.islink(\u0026#39;link\u0026#39;) # 是否为符号链接 os.path.exists(\u0026#39;path\u0026#39;) # 路径是否存在 # 路径连接 path = os.path.join(\u0026#39;dir\u0026#39;, \u0026#39;subdir\u0026#39;, \u0026#39;file.txt\u0026#39;) # 输出: dir/subdir/file.txt (Unix) 或 dir\\subdir\\file.txt (Windows) # 分割路径 dirname, basename = os.path.split(\u0026#39;/path/to/file.txt\u0026#39;) # dirname: /path/to, basename: file.txt # 分割扩展名 name, ext = os.path.splitext(\u0026#39;file.txt\u0026#39;) # name: file, ext: .txt 3.2 目录操作 import os # 创建目录 os.mkdir(\u0026#39;new_dir\u0026#39;) # 创建单级目录（父目录必须存在） os.makedirs(\u0026#39;path/to/new/dir\u0026#39;) # 递归创建目录 # 列出目录内容 os.listdir(\u0026#39;.\u0026#39;) # 返回列表 # 遍历目录树 for dirpath, dirnames, filenames in os.walk(\u0026#39;.\u0026#39;): print(f\u0026#34;目录: {dirpath}\u0026#34;) print(f\u0026#34;子目录: {dirnames}\u0026#34;) print(f\u0026#34;文件: {filenames}\u0026#34;) # 删除 os.remove(\u0026#39;file.txt\u0026#39;) # 删除文件 os.rmdir(\u0026#39;empty_dir\u0026#39;) # 删除空目录 3.3 文件信息 import os import datetime # 获取文件大小（字节） size = os.path.getsize(\u0026#39;file.txt\u0026#39;) # 获取文件修改时间 mtime = os.path.getmtime(\u0026#39;file.txt\u0026#39;) print(datetime.datetime.fromtimestamp(mtime)) # 获取创建时间 ctime = os.path.getctime(\u0026#39;file.txt\u0026#39;) # 获取文件详细信息 stat_info = os.stat(\u0026#39;file.txt\u0026#39;) print(f\u0026#34;大小: {stat_info.st_size} 字节\u0026#34;) print(f\u0026#34;修改: {datetime.datetime.fromtimestamp(stat_info.st_mtime)}\u0026#34;) 3.4 环境变量 import os # 获取环境变量 home = os.environ.get(\u0026#39;HOME\u0026#39;) # Unix # home = os.environ.get(\u0026#39;USERPROFILE\u0026#39;) # Windows path = os.environ.get(\u0026#39;PATH\u0026#39;, \u0026#39;\u0026#39;) # 设置环境变量 os.environ[\u0026#39;MY_VAR\u0026#39;] = \u0026#39;value\u0026#39; # 获取所有环境变量 for key, value in os.environ.items(): print(f\u0026#34;{key}={value}\u0026#34;) 4. pathlib 模块 - 面向对象路径操作 Python 3.4+ 推荐使用 pathlib，比 os.path 更直观。\n4.1 基本使用 from pathlib import Path # 当前目录 p = Path(\u0026#39;.\u0026#39;) print(p.absolute()) # 路径拼接 p = Path(\u0026#39;dir\u0026#39;) / \u0026#39;subdir\u0026#39; / \u0026#39;file.txt\u0026#39; print(p) # 获取路径各部分 p = Path(\u0026#39;/home/user/documents/file.txt\u0026#39;) print(p.name) # file.txt print(p.stem) # file print(p.suffix) # .txt print(p.parent) # /home/user/documents print(p.parents) # 父路径迭代器 # 路径判断 p = Path(\u0026#39;file.txt\u0026#39;) print(p.is_file()) # True print(p.is_dir()) # False print(p.exists()) # True 4.2 目录操作 from pathlib import Path # 创建目录 Path(\u0026#39;new_dir\u0026#39;).mkdir() # 创建单级目录 Path(\u0026#39;a/b/c\u0026#39;).mkdir(parents=True) # 递归创建 # 创建目录（如果不存在） Path(\u0026#39;dir\u0026#39;).mkdir(exist_ok=True) # 删除空目录 Path(\u0026#39;empty_dir\u0026#39;).rmdir() # 列出目录内容 p = Path(\u0026#39;.\u0026#39;) for item in p.iterdir(): # 只列出直接子项 print(item.name) # glob 模式匹配 for py_file in p.glob(\u0026#39;*.py\u0026#39;): # 所有 .py 文件 print(py_file) for py_file in p.rglob(\u0026#39;*.py\u0026#39;): # 递归所有 .py 文件（包括子目录） print(py_file) 4.3 文件读写 from pathlib import Path # 读取文本 content = Path(\u0026#39;file.txt\u0026#39;).read_text(encoding=\u0026#39;utf-8\u0026#39;) # 写入文本 Path(\u0026#39;output.txt\u0026#39;).write_text(\u0026#39;Hello, World!\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) # 读取字节 content_bytes = Path(\u0026#39;file.txt\u0026#39;).read_bytes() # 写入字节 Path(\u0026#39;output.bin\u0026#39;).write_bytes(b\u0026#39;\\x00\\x01\\x02\u0026#39;) # 追加写入（需要用 open） p = Path(\u0026#39;log.txt\u0026#39;) p.write_text(\u0026#39;新内容\\n\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) # 这会覆盖 # 正确追加方式 with p.open(\u0026#39;a\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: f.write(\u0026#39;追加内容\\n\u0026#39;) 4.4 Path 与 os.path 互转 from pathlib import Path # Path 转字符串 str_path = str(Path(\u0026#39;dir/file.txt\u0026#39;)) print(str_path) # dir/file.txt # os.path 函数中使用 Path import os p = Path(\u0026#39;file.txt\u0026#39;) print(os.path.exists(p)) # Path 对象可直接用于 os.path 函数 # 获取路径字符串用于 subprocess 等 import subprocess subprocess.run([\u0026#39;ls\u0026#39;, \u0026#39;-la\u0026#39;, str(Path(\u0026#39;.\u0026#39;))]) 5. 实战案例：文件处理工具 from pathlib import Path import csv import shutil from datetime import datetime class FileManager: \u0026#34;\u0026#34;\u0026#34;文件管理工具类\u0026#34;\u0026#34;\u0026#34; def __init__(self, base_dir=\u0026#39;.\u0026#39;): self.base_dir = Path(base_dir) def create_directory(self, dir_name): \u0026#34;\u0026#34;\u0026#34;创建目录\u0026#34;\u0026#34;\u0026#34; target = self.base_dir / dir_name target.mkdir(parents=True, exist_ok=True) print(f\u0026#34;已创建目录: {target}\u0026#34;) return target def list_files(self, pattern=\u0026#39;*\u0026#39;): \u0026#34;\u0026#34;\u0026#34;列出文件\u0026#34;\u0026#34;\u0026#34; return list(self.base_dir.glob(pattern)) def find_large_files(self, min_size_mb=10): \u0026#34;\u0026#34;\u0026#34;查找大于指定大小的文件\u0026#34;\u0026#34;\u0026#34; large_files = [] for file in self.base_dir.rglob(\u0026#39;*\u0026#39;): if file.is_file(): size_mb = file.stat().st_size / (1024 * 1024) if size_mb \u0026gt;= min_size_mb: large_files.append((file, size_mb)) return sorted(large_files, key=lambda x: x[1], reverse=True) def backup_file(self, filename, backup_dir=\u0026#39;backups\u0026#39;): \u0026#34;\u0026#34;\u0026#34;备份文件\u0026#34;\u0026#34;\u0026#34; src = self.base_dir / filename if not src.exists(): raise FileNotFoundError(f\u0026#34;文件不存在: {src}\u0026#34;) # 创建备份目录 backup_path = self.base_dir / backup_dir backup_path.mkdir(exist_ok=True) # 生成带时间戳的备份文件名 timestamp = datetime.now().strftime(\u0026#39;%Y%m%d_%H%M%S\u0026#39;) backup_name = f\u0026#34;{src.stem}_{timestamp}{src.suffix}\u0026#34; dst = backup_path / backup_name shutil.copy2(src, dst) print(f\u0026#34;已备份到: {dst}\u0026#34;) return dst def read_csv_as_dict(self, csv_file): \u0026#34;\u0026#34;\u0026#34;读取 CSV 为字典列表\u0026#34;\u0026#34;\u0026#34; with open(csv_file, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: reader = csv.DictReader(f) return list(reader) def write_dict_to_csv(self, data, csv_file, fieldnames=None): \u0026#34;\u0026#34;\u0026#34;写入字典列表到 CSV\u0026#34;\u0026#34;\u0026#34; if not data: return if fieldnames is None: fieldnames = list(data[0].keys()) with open(csv_file, \u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() writer.writerows(data) print(f\u0026#34;已写入 CSV: {csv_file}\u0026#34;) def clean_old_files(self, days=30): \u0026#34;\u0026#34;\u0026#34;清理指定天数前的文件\u0026#34;\u0026#34;\u0026#34; from datetime import timedelta cutoff = datetime.now() - timedelta(days=days) removed = [] for file in self.base_dir.rglob(\u0026#39;*\u0026#39;): if file.is_file(): mtime = datetime.fromtimestamp(file.stat().st_mtime) if mtime \u0026lt; cutoff: file.unlink() removed.append(file) print(f\u0026#34;已清理 {len(removed)} 个文件\u0026#34;) return removed def get_disk_usage(self): \u0026#34;\u0026#34;\u0026#34;获取磁盘使用情况\u0026#34;\u0026#34;\u0026#34; import shutil as sh usage = sh.disk_usage(self.base_dir) return { \u0026#39;total_gb\u0026#39;: usage.total / (1024**3), \u0026#39;used_gb\u0026#39;: usage.used / (1024**3), \u0026#39;free_gb\u0026#39;: usage.free / (1024**3), \u0026#39;percent\u0026#39;: (usage.used / usage.total) * 100 } # 使用示例 if __name__ == \u0026#39;__main__\u0026#39;: fm = FileManager(\u0026#39;/tmp/test\u0026#39;) # 创建测试目录 fm.create_directory(\u0026#39;data\u0026#39;) # 创建测试文件 (fm.base_dir / \u0026#39;data\u0026#39; / \u0026#39;test.txt\u0026#39;).write_text(\u0026#39;测试内容\u0026#39;) # 列出所有文件 print(\u0026#34;\\n所有文件:\u0026#34;) for f in fm.list_files(\u0026#39;**/*\u0026#39;): print(f\u0026#34; {f}\u0026#34;) # 读取磁盘使用情况 usage = fm.get_disk_usage() print(f\u0026#34;\\n磁盘使用: {usage[\u0026#39;percent\u0026#39;]:.1f}%\u0026#34;) 背诵版 模块速查 ┌─────────────────────────────────────────────────────────────┐ │ 文件处理模块对比 │ ├─────────────────────────────────────────────────────────────┤ │ os │ 底层系统调用，传统 API │ │ shutil │ 高级文件操作（复制/移动/压缩） │ │ pathlib │ 面向对象路径操作（Python 3.4\u0026#43;，推荐） │ │ csv │ CSV 文件读写 │ └─────────────────────────────────────────────────────────────┘pathlib Path 常用方法 方法 说明 Path.mkdir() 创建目录 Path.unlink() 删除文件 Path.rename() 重命名 Path.glob() 模式匹配 Path.iterdir() 遍历子项 Path.read_text() 读取文本 Path.write_text() 写入文本 Path.is_file() 是否为文件 Path.is_dir() 是否为目录 Path.exists() 是否存在 Path.stat() 获取信息 Path.resolve() 转绝对路径 shutil 常用函数 函数 说明 shutil.copy() 复制文件 shutil.copy2() 复制保留元数据 shutil.copytree() 复制目录树 shutil.move() 移动/重命名 shutil.rmtree() 删除目录树 shutil.make_archive() 创建归档 shutil.unpack_archive() 解压归档 shutil.disk_usage() 磁盘使用情况 考前记忆 面试重点 pathlib vs os.path\npathlib 面向对象，API 更直观 Python 3.4+ 推荐使用 pathlib Path 对象可与 os.path 函数混用 shutil.rmtree() vs os.remove()\nrmtree() 删除目录树 remove() 删除单个文件 CSV 读取注意\nnewline='' 避免 Windows 换行问题 DictReader/DictWriter 更方便 路径拼接\n使用 / 运算符：Path('dir') / 'file.txt' 避免使用字符串拼接 glob vs rglob\nglob() 只匹配当前目录 rglob() 递归匹配 记忆口诀 pathlib面向对象， 路径操作最轻松。 shutil管复制移动， csv处理表格中。 os底层系统调， 三者配合显神通。 测试题 选择题 1. 哪个模块是 Python 3.4+ 推荐使用的路径操作方式？\n# A. os.path # B. pathlib # C. shutil # D. glob 答案：B\n2. 如何递归列出目录下所有 .txt 文件？\n# A. for f in Path(\u0026#39;.\u0026#39;).glob(\u0026#39;*.txt\u0026#39;): print(f) # B. for f in Path(\u0026#39;.\u0026#39;).rglob(\u0026#39;*.txt\u0026#39;): print(f) # C. for f in os.listdir(\u0026#39;.\u0026#39;): if f.endswith(\u0026#39;.txt\u0026#39;): print(f) # D. 以上都不对 答案：B\n3. 写入 CSV 文件时，为什么要使用 newline=''？\n# A. 加快写入速度 # B. 避免 Windows 上行距加倍 # C. 兼容 Linux # D. 必须这样做 答案：B\n4. 如何复制文件并保留文件的元数据（修改时间等）？\n# A. shutil.copy() # B. shutil.copytree() # C. shutil.copy2() # D. shutil.move() 答案：C\n5. 删除非空目录应该使用哪个函数？\n# A. os.rmdir() # B. shutil.rmtree() # C. os.remove() # D. Path.rmdir() 答案：B\n编程题 1. 实现文件搜索工具：\nfrom pathlib import Path from datetime import datetime def search_files(directory, pattern=\u0026#39;*\u0026#39;, min_size=0, max_size=float(\u0026#39;inf\u0026#39;)): \u0026#34;\u0026#34;\u0026#34;搜索文件\u0026#34;\u0026#34;\u0026#34; results = [] dir_path = Path(directory) for file in dir_path.rglob(pattern): if file.is_file(): try: size = file.stat().st_size if min_size \u0026lt;= size \u0026lt;= max_size: results.append({ \u0026#39;name\u0026#39;: file.name, \u0026#39;path\u0026#39;: str(file), \u0026#39;size\u0026#39;: size, \u0026#39;modified\u0026#39;: datetime.fromtimestamp( file.stat().st_mtime ).strftime(\u0026#39;%Y-%m-%d %H:%M\u0026#39;) }) except (PermissionError, FileNotFoundError): continue return results # 使用 results = search_files(\u0026#39;.\u0026#39;, pattern=\u0026#39;*.py\u0026#39;, min_size=1000) for r in results: print(f\u0026#34;{r[\u0026#39;name\u0026#39;]}: {r[\u0026#39;size\u0026#39;]} 字节, 修改于 {r[\u0026#39;modified\u0026#39;]}\u0026#34;) 2. 实现目录备份脚本：\nfrom pathlib import Path import shutil from datetime import datetime def backup_directory(source, destination): \u0026#34;\u0026#34;\u0026#34;备份目录\u0026#34;\u0026#34;\u0026#34; src = Path(source) dst = Path(destination) if not src.exists(): raise FileNotFoundError(f\u0026#34;源目录不存在: {src}\u0026#34;) # 创建带时间戳的备份目录 timestamp = datetime.now().strftime(\u0026#39;%Y%m%d_%H%M%S\u0026#39;) backup_name = f\u0026#34;{src.name}_backup_{timestamp}\u0026#34; backup_path = dst / backup_name # 复制目录 shutil.copytree(src, backup_path) print(f\u0026#34;备份完成: {backup_path}\u0026#34;) return backup_path # 使用 backup_directory(\u0026#39;/path/to/source\u0026#39;, \u0026#39;/path/to/backups\u0026#39;) 3. CSV 数据处理工具：\nimport csv from pathlib import Path def process_csv(input_file, output_file, transform_fn): \u0026#34;\u0026#34;\u0026#34;处理 CSV 数据\u0026#34;\u0026#34;\u0026#34; with open(input_file, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as inf, \\ open(output_file, \u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as outf: reader = csv.DictReader(inf) fieldnames = reader.fieldnames writer = csv.DictWriter(outf, fieldnames=fieldnames) writer.writeheader() for row in reader: transformed = transform_fn(row) if transformed: # 如果返回 None 则跳过 writer.writerow(transformed) # 使用示例：过滤年龄大于 25 的记录，并添加一列 def transform(row): if int(row[\u0026#39;age\u0026#39;]) \u0026gt; 25: row[\u0026#39;status\u0026#39;] = \u0026#39;adult\u0026#39; return row return None process_csv(\u0026#39;input.csv\u0026#39;, \u0026#39;output.csv\u0026#39;, transform) 问答题 Q1: pathlib 相比 os.path 有哪些优势？\n面向对象：Path 是类，有丰富的方法 链式调用：Path('a') / 'b' / 'c' 更直观 统一接口：Windows 和 Unix 路径行为一致 功能丰富：glob, iterdir, read_text 等方法 可与其他模块混用：可直接传给 os.path 函数 Q2: shutil 模块的主要功能有哪些？\n复制：copy, copy2, copytree 移动：move 删除：rmtree 归档：make_archive, unpack_archive 磁盘信息：disk_usage 权限：copystat, chmod 参考资料 Python 官方文档 - pathlib Python 官方文档 - shutil Python 官方文档 - csv Python 官方文档 - os ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-35-file-comprehensive/","summary":"\u003ch1 id=\"day35---文件处理综合-csvshutilospathlib\"\u003eDay35 - 文件处理综合 (CSV/shutil/os/pathlib)\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"1-csv-文件处理\"\u003e1. CSV 文件处理\u003c/h3\u003e\n\u003ch4 id=\"11-csv-模块基础\"\u003e1.1 CSV 模块基础\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e csv\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 准备数据\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edata \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    [\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;姓名\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;年龄\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;城市\u0026#39;\u003c/span\u003e],\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    [\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;张三\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;25\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;北京\u0026#39;\u003c/span\u003e],\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    [\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;李四\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;30\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;上海\u0026#39;\u003c/span\u003e],\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    [\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;王五\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;28\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;广州\u0026#39;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 写入 CSV 文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;output.csv\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;w\u0026#39;\u003c/span\u003e, newline\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    writer \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e csv\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewriter(f)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    writer\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewriterows(data)  \u003cspan style=\"color:#75715e\"\u003e# 写入多行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 读取 CSV 文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;output.csv\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    reader \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e csv\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ereader(f)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e row \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e reader:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(row)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e注意\u003c/strong\u003e：\u003ccode\u003enewline=''\u003c/code\u003e 在写入 CSV 时必须使用，否则在 Windows 上可能导致行距加倍。\u003c/p\u003e\n\u003ch4 id=\"12-字典方式操作-csv\"\u003e1.2 字典方式操作 CSV\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e csv\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 写入字典格式\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003efieldnames \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;name\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;age\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;city\u0026#39;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edata \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;name\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;张三\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;age\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e25\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;city\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;北京\u0026#39;\u003c/span\u003e},\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;name\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;李四\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;age\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;city\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;上海\u0026#39;\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;dict_data.csv\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;w\u0026#39;\u003c/span\u003e, newline\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    writer \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e csv\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eDictWriter(f, fieldnames\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003efieldnames)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    writer\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewriteheader()  \u003cspan style=\"color:#75715e\"\u003e# 写入表头\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    writer\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewriterows(data)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 读取字典格式\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;dict_data.csv\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    reader \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e csv\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eDictReader(f)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e row \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e reader:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003erow[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;name\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e - \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003erow[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;age\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e - \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003erow[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;city\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"13-csv-高级选项\"\u003e1.3 CSV 高级选项\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e csv\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 自定义分隔符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;tab_data.tsv\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;w\u0026#39;\u003c/span\u003e, newline\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    writer \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e csv\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewriter(f, delimiter\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    writer\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewriterows(data)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 引用处理\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;quoted.csv\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;w\u0026#39;\u003c/span\u003e, newline\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    writer \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e csv\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewriter(f, quoting\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003ecsv\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eQUOTE_ALL)  \u003cspan style=\"color:#75715e\"\u003e# 所有字段加引号\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    writer\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewriterows(data)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# quoting 选项：\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# QUOTE_ALL      - 所有字段加引号\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# QUOTE_MINIMAL  - 特殊字符字段加引号（默认）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# QUOTE_NONNUMERIC - 非数字字段加引号\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# QUOTE_NONE     - 不加引号\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"14-处理大-csv-文件\"\u003e1.4 处理大 CSV 文件\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e csv\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用生成器处理大文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eread_csv_chunked\u003c/span\u003e(filepath, chunk_size\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e1000\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;分块读取大 CSV 文件\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(filepath, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        reader \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e csv\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ereader(f)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        header \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e next(reader)  \u003cspan style=\"color:#75715e\"\u003e# 读取表头\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        chunk \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e row \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e reader:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            chunk\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(row)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e len(chunk) \u003cspan style=\"color:#f92672\"\u003e\u0026gt;=\u003c/span\u003e chunk_size:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#66d9ef\"\u003eyield\u003c/span\u003e header, chunk\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                chunk \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e chunk:  \u003cspan style=\"color:#75715e\"\u003e# 处理最后一块\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eyield\u003c/span\u003e header, chunk\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e header, chunk \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e read_csv_chunked(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;large_file.csv\u0026#39;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;处理 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003elen(chunk)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 条记录\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 处理每块数据\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"2-shutil-模块---高级文件操作\"\u003e2. shutil 模块 - 高级文件操作\u003c/h3\u003e\n\u003ch4 id=\"21-复制操作\"\u003e2.1 复制操作\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e shutil\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 复制文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eshutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecopy(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;source.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;dest.txt\u0026#39;\u003c/span\u003e)      \u003cspan style=\"color:#75715e\"\u003e# 复制文件内容\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eshutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecopy2(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;source.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;dest.txt\u0026#39;\u003c/span\u003e)    \u003cspan style=\"color:#75715e\"\u003e# 复制文件并保留元数据\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 复制目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eshutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecopytree(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;source_dir\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;dest_dir\u0026#39;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 递归复制整个目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 复制到文件夹\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eshutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecopy(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;target_dir/\u0026#39;\u003c/span\u003e)     \u003cspan style=\"color:#75715e\"\u003e# 目标可以是目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"22-移动和重命名\"\u003e2.2 移动和重命名\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e shutil\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 移动文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eshutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emove(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;source.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;dest.txt\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 移动目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eshutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emove(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;source_dir\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;dest_dir\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 重命名（同一目录下移动即重命名）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eshutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emove(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;old_name.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;new_name.txt\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"23-删除操作\"\u003e2.3 删除操作\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e shutil\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 删除目录（必须是空目录）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e os\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ermdir(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;empty_dir\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 删除目录树（递归删除）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eshutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ermtree(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;dir_to_remove\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 安全删除（移动到回收站，可安装 send2trash 库）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pip install send2trash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e send2trash\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    send2trash\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esend2trash(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file_to_delete.txt\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eImportError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;请安装: pip install send2trash\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"24-归档和压缩\"\u003e2.4 归档和压缩\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e shutil\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 创建归档（zip, tar, gztar, bztar, xztar）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eshutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emake_archive(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;backup\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;zip\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;directory_to_backup\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 解压归档\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eshutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eunpack_archive(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;backup.zip\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;extract_here\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 列出支持的格式\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(shutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget_archive_formats())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(shutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget_unpack_formats())\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"25-其他有用功能\"\u003e2.5 其他有用功能\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e shutil\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 获取磁盘使用情况\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etotal, used, free \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e shutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edisk_usage(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;总容量: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etotal \u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e GB\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;已使用: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eused \u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e GB\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;剩余: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003efree \u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e GB\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 复制权限（仅 Unix）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# shutil.copystat(src, dst)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 获取临时目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(shutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egettempdir())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 命令行工具包装\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# shutil.which(\u0026#39;python\u0026#39;)  # 查找命令路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"3-os-模块---系统交互\"\u003e3. os 模块 - 系统交互\u003c/h3\u003e\n\u003ch4 id=\"31-路径操作\"\u003e3.1 路径操作\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e os\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 获取当前工作目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egetcwd())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 改变当前目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003echdir(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/path/to/directory\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 返回绝对路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eabspath(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;relative/path\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 判断路径类型\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eisfile(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e)     \u003cspan style=\"color:#75715e\"\u003e# 是否为文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eisdir(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;directory\u0026#39;\u003c/span\u003e)     \u003cspan style=\"color:#75715e\"\u003e# 是否为目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eislink(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;link\u0026#39;\u003c/span\u003e)         \u003cspan style=\"color:#75715e\"\u003e# 是否为符号链接\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexists(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;path\u0026#39;\u003c/span\u003e)         \u003cspan style=\"color:#75715e\"\u003e# 路径是否存在\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 路径连接\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epath \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ejoin(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;dir\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;subdir\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 输出: dir/subdir/file.txt (Unix) 或 dir\\subdir\\file.txt (Windows)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 分割路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edirname, basename \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/path/to/file.txt\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# dirname: /path/to, basename: file.txt\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 分割扩展名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ename, ext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplitext(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# name: file, ext: .txt\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"32-目录操作\"\u003e3.2 目录操作\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e os\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 创建目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emkdir(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;new_dir\u0026#39;\u003c/span\u003e)           \u003cspan style=\"color:#75715e\"\u003e# 创建单级目录（父目录必须存在）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emakedirs(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;path/to/new/dir\u0026#39;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 递归创建目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 列出目录内容\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003elistdir(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;.\u0026#39;\u003c/span\u003e)               \u003cspan style=\"color:#75715e\"\u003e# 返回列表\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 遍历目录树\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e dirpath, dirnames, filenames \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewalk(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;.\u0026#39;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;目录: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edirpath\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;子目录: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edirnames\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;文件: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003efilenames\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 删除\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eremove(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e)         \u003cspan style=\"color:#75715e\"\u003e# 删除文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ermdir(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;empty_dir\u0026#39;\u003c/span\u003e)         \u003cspan style=\"color:#75715e\"\u003e# 删除空目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"33-文件信息\"\u003e3.3 文件信息\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e os\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e datetime\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 获取文件大小（字节）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esize \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egetsize(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 获取文件修改时间\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emtime \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egetmtime(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(datetime\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edatetime\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efromtimestamp(mtime))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 获取创建时间\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ectime \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egetctime(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 获取文件详细信息\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003estat_info \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estat(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;大小: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003estat_info\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003est_size\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 字节\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;修改: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edatetime\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edatetime\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efromtimestamp(stat_info\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003est_mtime)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"34-环境变量\"\u003e3.4 环境变量\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e os\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 获取环境变量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehome \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eenviron\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;HOME\u0026#39;\u003c/span\u003e)           \u003cspan style=\"color:#75715e\"\u003e# Unix\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# home = os.environ.get(\u0026#39;USERPROFILE\u0026#39;) # Windows\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epath \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eenviron\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;PATH\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 设置环境变量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eos\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eenviron[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;MY_VAR\u0026#39;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;value\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 获取所有环境变量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e key, value \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eenviron\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eitems():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ekey\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003evalue\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"4-pathlib-模块---面向对象路径操作\"\u003e4. pathlib 模块 - 面向对象路径操作\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003ePython 3.4+ 推荐使用 pathlib\u003c/strong\u003e，比 os.path 更直观。\u003c/p\u003e","tags":"python, csv, shutil, os, pathlib","title":"Day35 - 文件处理综合 (CSV/shutil/os/pathlib)"},{"columns":"python-course","content":"Day36 - 浅拷贝与深拷贝详解 详细讲解 1. 对象赋值与引用 在 Python 中，一切皆对象。赋值语句（如 a = b）并不复制对象，而是创建了对同一对象的引用。\n# 赋值 - 同一个对象的不同引用 a = [1, 2, 3] b = a print(f\u0026#34;a: {a}\u0026#34;) # [1, 2, 3] print(f\u0026#34;b: {b}\u0026#34;) # [1, 2, 3] print(f\u0026#34;a is b: {a is b}\u0026#34;) # True - 同一对象 # 修改 a，b 也会变化 a.append(4) print(f\u0026#34;修改后 a: {a}\u0026#34;) # [1, 2, 3, 4] print(f\u0026#34;修改后 b: {b}\u0026#34;) # [1, 2, 3, 4] - b 也变了！ # id() 显示对象身份 print(f\u0026#34;id(a): {id(a)}\u0026#34;) print(f\u0026#34;id(b): {id(b)}\u0026#34;) # 相同 2. 浅拷贝（Shallow Copy） 浅拷贝创建一个新对象，但只复制原对象中的第一层引用。对于嵌套对象，只复制其引用，不复制嵌套对象本身。\nimport copy # 浅拷贝的几种方式 original = [1, 2, [3, 4]] # 方式1: copy.copy() shallow1 = copy.copy(original) # 方式2: list() / dict() / 切片等 shallow2 = list(original) # 方式3: 切片 shallow3 = original[:] # 方式4: dict(original) original_dict = {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: [1, 2]} shallow_dict = dict(original_dict) print(f\u0026#34;original: {original}\u0026#34;) print(f\u0026#34;shallow: {shallow1}\u0026#34;) print(f\u0026#34;original is shallow: {original is shallow1}\u0026#34;) # False - 新对象 print(f\u0026#34;original[2] is shallow[2]: {original[2] is shallow1[2]}\u0026#34;) # True - 内部对象相同 # 修改第一层，不影响原对象 shallow1[0] = 999 print(f\u0026#34;修改后 original: {original}\u0026#34;) # [1, 2, [3, 4]] - 不变 print(f\u0026#34;修改后 shallow: {shallow1}\u0026#34;) # [999, 2, [3, 4]] # 修改深层对象，影响原对象 shallow1[2].append(5) print(f\u0026#34;修改深层后 original: {original}\u0026#34;) # [1, 2, [3, 4, 5]] - 变了！ print(f\u0026#34;修改深层后 shallow: {shallow1}\u0026#34;) # [999, 2, [3, 4, 5]] 3. 深拷贝（Deep Copy） 深拷贝递归地复制所有嵌套对象，创建完全独立的对象副本。\nimport copy original = [1, 2, [3, 4]] # 深拷贝 deep = copy.deepcopy(original) print(f\u0026#34;original: {original}\u0026#34;) print(f\u0026#34;deep: {deep}\u0026#34;) print(f\u0026#34;original is deep: {original is deep}\u0026#34;) # False print(f\u0026#34;original[2] is deep[2]: {original[2] is deep[2]}\u0026#34;) # False - 完全独立！ # 修改第一层，不影响原对象 deep[0] = 999 print(f\u0026#34;修改后 original: {original}\u0026#34;) # [1, 2, [3, 4]] - 不变 print(f\u0026#34;修改后 deep: {deep}\u0026#34;) # [999, 2, [3, 4]] # 修改深层对象，也不影响原对象 deep[2].append(5) print(f\u0026#34;修改深层后 original: {original}\u0026#34;) # [1, 2, [3, 4]] - 不变！ print(f\u0026#34;修改深层后 deep: {deep}\u0026#34;) # [999, 2, [3, 4, 5]] 4. 拷贝操作对比表 ┌─────────────────────────────────────────────────────────────┐ │ 拷贝方式对比 │ ├─────────────┬───────────────────────────────────────────────┤ │ 赋值 (=) │ 共享引用，修改互相影响 │ ├─────────────┼───────────────────────────────────────────────┤ │ 浅拷贝 │ 第一层独立，深层共享引用 │ ├─────────────┼───────────────────────────────────────────────┤ │ 深拷贝 │ 完全独立，所有层级都复制 │ └─────────────┴───────────────────────────────────────────────┘5. 不可变对象与拷贝 重要：对于不可变对象（如 tuple, str, int, frozenset），由于其不可修改，拷贝的意义不大，Python 可能会复用对象。\nimport copy # 不可变对象 a = \u0026#34;hello\u0026#34; b = copy.copy(a) c = copy.deepcopy(a) print(f\u0026#34;a: {a}, b: {b}, c: {c}\u0026#34;) print(f\u0026#34;a is b: {a is b}\u0026#34;) # True - 不可变对象可能复用 print(f\u0026#34;a is c: {a is c}\u0026#34;) # True - 不可变对象可能复用 # tuple 整体不可变，但内部可变对象呢？ t = (1, 2, [3, 4]) t_copy = copy.copy(t) t_deep = copy.deepcopy(t) print(f\u0026#34;t is t_copy: {t is t_copy}\u0026#34;) # True - tuple 不可变，copy 可能复用 print(f\u0026#34;t is t_deep: {t is t_deep}\u0026#34;) # False - deepcopy 总是创建新对象 # 但内部的 list 是独立的 t_copy[2].append(5) print(f\u0026#34;t: {t}\u0026#34;) # (1, 2, [3, 4]) - tuple 不变 print(f\u0026#34;t_copy: {t_copy}\u0026#34;) # (1, 2, [3, 4, 5]) 6. 浅拷贝的常见方式 # 1. 切片拷贝 list1 = [1, 2, 3] list2 = list1[:] # 2. list() / dict() / set() list3 = list(list1) dict1 = {\u0026#39;a\u0026#39;: 1} dict2 = dict(dict1) set1 = {1, 2} set2 = set(set1) # 3. list.copy() / dict.copy() list4 = list1.copy() dict3 = dict1.copy() # 4. copy.copy() import copy list5 = copy.copy(list1) # 5. copy.copy() for dict with nested original = {\u0026#39;a\u0026#39;: [1, 2, 3], \u0026#39;b\u0026#39;: {\u0026#39;x\u0026#39;: 1}} shallow = original.copy() 7. 深拷贝的常见方式 import copy # 1. copy.deepcopy() original = [1, 2, [3, 4]] deep = copy.deepcopy(original) # 2. 递归自定义深拷贝 def deep_copy(obj): if isinstance(obj, (list, tuple)): return type(obj)(deep_copy(item) for item in obj) elif isinstance(obj, dict): return {key: deep_copy(val) for key, val in obj.items()} elif isinstance(obj, (int, str, float, bool, type(None))): return obj else: # 其他对象尝试使用 __dict__ 复制 try: result = object.__new__(type(obj)) result.__dict__.update(obj.__dict__) return result except: return obj 8. 拷贝的注意事项 8.1 循环引用 import copy # 循环引用的对象 list1 = [1, 2] list2 = [3, 4] list1.append(list2) list2.append(list1) # list1 -\u0026gt; list2 -\u0026gt; list1 # deepcopy 能处理循环引用，不会无限递归 deep = copy.deepcopy(list1) print(f\u0026#34;深拷贝完成，无无限递归\u0026#34;) 8.2 对象自定义拷贝行为 import copy class MyClass: def __init__(self, value): self.value = value self.data = [1, 2, 3] # 定义浅拷贝行为 def __copy__(self): new_obj = MyClass(self.value) new_obj.data = list(self.data) # 重新创建列表 return new_obj # 定义深拷贝行为 def __deepcopy__(self, memo): new_obj = MyClass(self.value) memo[id(self)] = new_obj # 防止循环引用 new_obj.data = copy.deepcopy(self.data, memo) return new_obj obj = MyClass(42) obj_copy = copy.copy(obj) # 调用 __copy__ obj_deep = copy.deepcopy(obj) # 调用 __deepcopy__ 8.3 单例对象 import copy # 单例对象（如 None, True, False） singleton = None copy_of_singleton = copy.copy(singleton) deep_copy_of_singleton = copy.deepcopy(singleton) print(f\u0026#34;singleton is copy: {singleton is copy_of_singleton}\u0026#34;) # True # 深拷贝也保持单例特性 print(f\u0026#34;singleton is deep: {singleton is deep_copy_of_singleton}\u0026#34;) # True 9. 实战案例：配置对象拷贝 import copy from dataclasses import dataclass, field @dataclass class DatabaseConfig: \u0026#34;\u0026#34;\u0026#34;数据库配置\u0026#34;\u0026#34;\u0026#34; host: str = \u0026#39;localhost\u0026#39; port: int = 3306 name: str = \u0026#39;testdb\u0026#39; credentials: dict = field(default_factory=dict) @dataclass class AppConfig: \u0026#34;\u0026#34;\u0026#34;应用配置\u0026#34;\u0026#34;\u0026#34; name: str = \u0026#39;MyApp\u0026#39; debug: bool = False db: DatabaseConfig = field(default_factory=DatabaseConfig) def create_copy(self): \u0026#34;\u0026#34;\u0026#34;创建深拷贝\u0026#34;\u0026#34;\u0026#34; return copy.deepcopy(self) def create_shallow(self): \u0026#34;\u0026#34;\u0026#34;创建浅拷贝\u0026#34;\u0026#34;\u0026#34; return copy.copy(self) # 创建原始配置 config1 = AppConfig( name=\u0026#39;Production\u0026#39;, debug=False, db=DatabaseConfig( host=\u0026#39;db.example.com\u0026#39;, credentials={\u0026#39;user\u0026#39;: \u0026#39;admin\u0026#39;} ) ) # 深拷贝 - 完全独立 config2 = config1.create_copy() config2.name = \u0026#39;Development\u0026#39; config2.db.host = \u0026#39;localhost\u0026#39; # 不影响 config1 print(f\u0026#34;原始配置: {config1.name}, {config1.db.host}\u0026#34;) print(f\u0026#34;拷贝配置: {config2.name}, {config2.db.host}\u0026#34;) # 输出: # 原始配置: Production, db.example.com # 拷贝配置: Development, localhost # 浅拷贝 - 嵌套对象共享引用 config3 = config1.create_shallow() config3.name = \u0026#39;Testing\u0026#39; config3.db.host = \u0026#39;127.0.0.1\u0026#39; # 这会影响到 config1！ print(f\u0026#34;原始配置: {config1.name}, {config1.db.host}\u0026#34;) print(f\u0026#34;浅拷贝配置: {config3.name}, {config3.db.host}\u0026#34;) # 输出: # 原始配置: Production, 127.0.0.1 \u0026lt;- 被影响了！ # 浅拷贝配置: Testing, 127.0.0.1 10. 拷贝判断方法 import copy a = [1, 2, 3] b = a c = copy.copy(a) d = copy.deepcopy(a) print(f\u0026#34;a is b: {a is b}\u0026#34;) # True - 同一引用 print(f\u0026#34;a is c: {a is c}\u0026#34;) # False - 浅拷贝 print(f\u0026#34;a is d: {a is d}\u0026#34;) # False - 深拷贝 # 检查值是否相等 print(f\u0026#34;a == b: {a == b}\u0026#34;) # True print(f\u0026#34;a == c: {a == c}\u0026#34;) # True print(f\u0026#34;a == d: {a == d}\u0026#34;) # True 背诵版 三种拷贝方式速查 ┌─────────────────────────────────────────────────────────────┐ │ 方式 │ 第一层 │ 深层（嵌套） │ 说明 │ ├───────────┼──────────┼────────────────┼────────────────────┤ │ 赋值 = │ 共享 │ 共享 │ 同一引用 │ ├───────────┼──────────┼────────────────┼────────────────────┤ │ 浅拷贝 │ 独立 │ 共享 │ copy.copy() │ ├───────────┼──────────┼────────────────┼────────────────────┤ │ 深拷贝 │ 独立 │ 独立 │ copy.deepcopy() │ └───────────┴──────────┴────────────────┴────────────────────┘拷贝方法总结 方法 类型 说明 a = b 赋值 共享引用 a[:] 浅拷贝 切片，适用于 list list(a) 浅拷贝 构造函数 a.copy() 浅拷贝 方法形式 copy.copy(a) 浅拷贝 模块函数 copy.deepcopy(a) 深拷贝 完全独立副本 考前记忆 面试重点 赋值 vs 拷贝的区别\n赋值：创建新引用，指向同一对象 拷贝：创建新对象 浅拷贝只复制第一层\n第一层是独立的 深层嵌套对象仍是引用 深拷贝完全独立\n所有层级都递归复制 循环引用也能正确处理 不可变对象的特点\nint, str, tuple 等不需要拷贝 拷贝可能复用对象 __copy__ 和 __deepcopy__ 方法\n自定义类可定义这两个方法控制拷贝行为 记忆口诀 赋值共享同一对象， 浅拷贝第一层独立。 深拷贝完全递归复制， immutable无需拷贝。 测试题 选择题 1. 下面代码的输出是什么？\nimport copy a = [1, [2, 3]] b = copy.copy(a) b[0] = 99 b[1].append(4) print(a) # A. [1, [2, 3]] # B. [99, [2, 3]] # C. [1, [2, 3, 4]] # D. [99, [2, 3, 4]] 答案：C（第一层独立，深层共享）\n2. 深拷贝的特点是什么？\n# A. 只复制第一层 # B. 创建新引用 # C. 递归复制所有嵌套对象 # D. 不复制不可变对象 答案：C\n3. list1 = list2[:] 是什么类型的拷贝？\n# A. 赋值 # B. 浅拷贝 # C. 深拷贝 # D. 都不是 答案：B\n4. 下面哪个是深拷贝的正确方式？\n# A. a = b # B. a = copy.copy(b) # C. a = copy.deepcopy(b) # D. a = b[:] 答案：C\n5. 不可变对象（int, str, tuple）拷贝时会怎样？\n# A. 总是创建新对象 # B. 可能复用已有对象 # C. 报错 # D. 返回 None 答案：B（不可变对象拷贝可能复用，Python 优化）\n编程题 1. 实现一个安全的配置合并函数：\nimport copy def merge_configs(base, override): \u0026#34;\u0026#34;\u0026#34; 合并配置，override 的值会覆盖 base 使用深拷贝确保不修改原始配置 \u0026#34;\u0026#34;\u0026#34; result = copy.deepcopy(base) for key, value in override.items(): if key in result and isinstance(result[key], dict) and isinstance(value, dict): result[key] = merge_configs(result[key], value) else: result[key] = copy.deepcopy(value) return result # 测试 base_config = { \u0026#39;database\u0026#39;: { \u0026#39;host\u0026#39;: \u0026#39;localhost\u0026#39;, \u0026#39;port\u0026#39;: 3306, \u0026#39;options\u0026#39;: {\u0026#39;timeout\u0026#39;: 30} }, \u0026#39;app\u0026#39;: {\u0026#39;debug\u0026#39;: False} } override_config = { \u0026#39;database\u0026#39;: { \u0026#39;host\u0026#39;: \u0026#39;production.db.com\u0026#39;, \u0026#39;options\u0026#39;: {\u0026#39;timeout\u0026#39;: 60} }, \u0026#39;app\u0026#39;: {\u0026#39;debug\u0026#39;: True} } merged = merge_configs(base_config, override_config) print(merged) # {\u0026#39;database\u0026#39;: {\u0026#39;host\u0026#39;: \u0026#39;production.db.com\u0026#39;, \u0026#39;port\u0026#39;: 3306, \u0026#39;options\u0026#39;: {\u0026#39;timeout\u0026#39;: 60}}, # \u0026#39;app\u0026#39;: {\u0026#39;debug\u0026#39;: True}} # 验证原始配置未被修改 print(base_config[\u0026#39;database\u0026#39;][\u0026#39;host\u0026#39;]) # \u0026#39;localhost\u0026#39; 2. 实现一个不可变配置类：\nimport copy from typing import Any class ImmutableConfig: \u0026#34;\u0026#34;\u0026#34;不可变配置类\u0026#34;\u0026#34;\u0026#34; def __init__(self, data): self._data = self._deep_freeze(data) @staticmethod def _deep_freeze(obj): \u0026#34;\u0026#34;\u0026#34;深度冻结 - 将所有嵌套 dict 转为 ImmutableConfig\u0026#34;\u0026#34;\u0026#34; if isinstance(obj, dict): return ImmutableConfig(obj._data if isinstance(obj, ImmutableConfig) else obj) elif isinstance(obj, list): return tuple(ImmutableConfig._deep_freeze(item) for item in obj) else: return obj def get(self, key, default=None): \u0026#34;\u0026#34;\u0026#34;获取值\u0026#34;\u0026#34;\u0026#34; keys = key.split(\u0026#39;.\u0026#39;) value = self._data for k in keys: if isinstance(value, dict): value = value.get(k) elif isinstance(value, ImmutableConfig): value = value._data.get(k) else: return default if value is None: return default return value def with_overrides(self, **kwargs): \u0026#34;\u0026#34;\u0026#34;返回带覆盖的新实例（原实例不变）\u0026#34;\u0026#34;\u0026#34; new_data = copy.deepcopy(self._data) for key, value in kwargs.items(): new_data[key] = value return ImmutableConfig(new_data) def __repr__(self): return f\u0026#34;ImmutableConfig({self._data})\u0026#34; # 使用 config = ImmutableConfig({ \u0026#39;host\u0026#39;: \u0026#39;localhost\u0026#39;, \u0026#39;port\u0026#39;: 8080, \u0026#39;database\u0026#39;: { \u0026#39;name\u0026#39;: \u0026#39;testdb\u0026#39;, \u0026#39;user\u0026#39;: \u0026#39;admin\u0026#39; } }) # 获取值 print(config.get(\u0026#39;host\u0026#39;)) # localhost print(config.get(\u0026#39;database.name\u0026#39;)) # testdb # 创建新配置（不修改原配置） new_config = config.with_overrides(host=\u0026#39;production\u0026#39;, port=443) print(config.get(\u0026#39;host\u0026#39;)) # localhost - 原配置不变 print(new_config.get(\u0026#39;host\u0026#39;)) # production 3. 检测拷贝类型的装饰器：\nimport copy def verify_copy(original, copied, expected_type): \u0026#34;\u0026#34;\u0026#34;验证拷贝结果的正确性\u0026#34;\u0026#34;\u0026#34; checks = { \u0026#39;assignment\u0026#39;: lambda o, c: o is c, \u0026#39;shallow\u0026#39;: lambda o, c: o is not c and o[2] is c[2], # 假设有嵌套 \u0026#39;deep\u0026#39;: lambda o, c: o is not c and (len(o) != len(c) or o[2] is not c[2]) } return checks.get(expected_type, lambda *a: False)(original, copied) # 测试 nested = [1, [2, 3]] assignment = nested shallow = copy.copy(nested) deep = copy.deepcopy(nested) print(f\u0026#34;Assignment: {nested is assignment}\u0026#34;) # True print(f\u0026#34;Shallow: {nested is not shallow and nested[1] is shallow[1]}\u0026#34;) # True print(f\u0026#34;Deep: {nested is not deep and nested[1] is not deep[1]}\u0026#34;) # True 问答题 Q1: 什么是浅拷贝？什么是深拷贝？请举例说明它们的区别。\n浅拷贝：创建一个新对象，但只复制原对象的第一层。对于嵌套的可变对象（如 list 中的 list），只复制引用，不复制嵌套对象本身。 深拷贝：递归地复制所有嵌套对象，创建完全独立的对象副本。 import copy original = [1, [2, 3]] shallow = copy.copy(original) shallow[1].append(4) # original 也会变化 deep = copy.deepcopy(original) deep[1].append(5) # original 不受影响 Q2: 什么情况下需要使用深拷贝而不是浅拷贝？\n需要深拷贝的场景：\n修改副本时不想影响原对象 原对象包含多层嵌套的可变对象 需要对配置、状态等进行隔离修改 多线程或并发场景下需要独立状态 典型场景：\n配置文件修改 游戏对象克隆 数据处理中的数据隔离 状态机中的状态副本 Q3: Python 中哪些对象是可变的？哪些是不可变的？\n可变对象：\nlist, dict, set bytearray 用户自定义类（默认） 不可变对象：\nint, float, bool str, bytes tuple, frozenset None complex, decimal 重要：包含可变对象的不可变对象（如包含 list 的 tuple）修改内部可变对象时，原对象也会变化。\n参考资料 Python 官方文档 - copy 模块 Python 数据模型 - copy 和 deepcopy Python 拷贝与赋值的区别 ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-36-deep-shallow-copy/","summary":"\u003ch1 id=\"day36---浅拷贝与深拷贝详解\"\u003eDay36 - 浅拷贝与深拷贝详解\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"1-对象赋值与引用\"\u003e1. 对象赋值与引用\u003c/h3\u003e\n\u003cp\u003e在 Python 中，一切皆对象。赋值语句（如 \u003ccode\u003ea = b\u003c/code\u003e）并不复制对象，而是创建了对同一对象的引用。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 赋值 - 同一个对象的不同引用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ea \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eb \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e a\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)   \u003cspan style=\"color:#75715e\"\u003e# [1, 2, 3]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;b: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eb\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)   \u003cspan style=\"color:#75715e\"\u003e# [1, 2, 3]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a is b: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea \u003cspan style=\"color:#f92672\"\u003eis\u003c/span\u003e b\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# True - 同一对象\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 修改 a，b 也会变化\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ea\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(\u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;修改后 a: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ea\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)   \u003cspan style=\"color:#75715e\"\u003e# [1, 2, 3, 4]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;修改后 b: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eb\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)   \u003cspan style=\"color:#75715e\"\u003e# [1, 2, 3, 4] - b 也变了！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# id() 显示对象身份\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;id(a): \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eid(a)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;id(b): \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eid(b)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 相同\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"2-浅拷贝shallow-copy\"\u003e2. 浅拷贝（Shallow Copy）\u003c/h3\u003e\n\u003cp\u003e浅拷贝创建一个新对象，但只复制原对象中的\u003cstrong\u003e第一层\u003c/strong\u003e引用。对于嵌套对象，只复制其引用，不复制嵌套对象本身。\u003c/p\u003e","tags":"python, copy, deepcopy, shallow, reference","title":"Day36 - 浅拷贝与深拷贝详解"},{"columns":"python-course","content":"Day37 - 迭代器与生成器详解 详细讲解 1. 迭代器基础 1.1 可迭代对象与迭代器 可迭代对象（Iterable）：可以使用 for 循环遍历的对象，如 list, dict, str, file 等。\n迭代器（Iterator）：实现了 __iter__() 和 __next__() 方法的对象。\n# 可迭代对象 numbers = [1, 2, 3] # list 是可迭代对象 # 获取迭代器 iterator = iter(numbers) print(f\u0026#34;迭代器: {iterator}\u0026#34;) # 手动迭代 print(next(iterator)) # 1 print(next(iterator)) # 2 print(next(iterator)) # 3 print(next(iterator)) # StopIteration 异常 1.2 迭代器协议 # 迭代器必须实现的两个方法 class MyIterator: def __init__(self, data): self.data = data self.index = 0 def __iter__(self): \u0026#34;\u0026#34;\u0026#34;返回迭代器本身\u0026#34;\u0026#34;\u0026#34; return self def __next__(self): \u0026#34;\u0026#34;\u0026#34;返回下一个元素\u0026#34;\u0026#34;\u0026#34; if self.index \u0026gt;= len(self.data): raise StopIteration value = self.data[self.index] self.index += 1 return value # 使用 it = MyIterator([10, 20, 30]) for item in it: print(item) 1.3 iter() 和 next() 内置函数 # iter() 可以接受两个参数：可迭代对象 + 哨兵值 # 这样会在每次 next() 时调用可迭代对象，直到返回值等于哨兵值 # 示例：读取行直到空行 with open(\u0026#39;lines.txt\u0026#39;, \u0026#39;r\u0026#39;) as f: for line in iter(f.readline, \u0026#39;\u0026#39;): print(line.strip()) # next() 可以指定默认值 numbers = [1, 2, 3] it = iter(numbers) print(next(it, \u0026#39;默认值\u0026#39;)) # 1 print(next(it, \u0026#39;默认值\u0026#39;)) # 2 print(next(it, \u0026#39;默认值\u0026#39;)) # 3 print(next(it, \u0026#39;默认值\u0026#39;)) # 默认值（不会抛出 StopIteration） 2. 生成器基础 生成器是一种特殊的迭代器，使用 yield 关键字来产生值，而不是 return。\n2.1 生成器函数 def countdown(n): \u0026#34;\u0026#34;\u0026#34;倒计时生成器\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;开始倒计时从 {n}\u0026#34;) while n \u0026gt; 0: yield n # 暂停，返回值 n -= 1 print(\u0026#34;倒计时结束\u0026#34;) # 创建生成器对象（函数不会立即执行） gen = countdown(5) print(f\u0026#34;生成器对象: {gen}\u0026#34;) # 迭代获取值 print(next(gen)) # 5 print(next(gen)) # 4 print(next(gen)) # 3 # 也可以用 for 循环 for num in countdown(3): print(f\u0026#34;倒计时: {num}\u0026#34;) 2.2 生成器表达式 # 类似列表推导式，但使用圆括号（惰性求值） gen = (x ** 2 for x in range(10)) print(gen) # \u0026lt;generator object\u0026gt; # 惰性求值 - 每次只计算一个值 for value in gen: print(value) # 转换为列表 squares = list(x ** 2 for x in range(5)) print(squares) # [0, 1, 4, 9, 16] # 在函数参数中使用 print(sum(x ** 2 for x in range(5))) # 30 print(max(x for x in range(10) if x % 2 == 0)) # 8 2.3 生成器 vs 列表 import sys # 列表 - 一次性生成所有元素 list_comp = [x ** 2 for x in range(10000)] print(f\u0026#34;列表大小: {sys.getsizeof(list_comp)} 字节\u0026#34;) # ~80KB # 生成器 - 惰性求值，节省内存 gen_exp = (x ** 2 for x in range(10000)) print(f\u0026#34;生成器大小: {sys.getsizeof(gen_exp)} 字节\u0026#34;) # ~200 bytes # 对比：生成 1000 万个数字的内存使用 def using_list(): return [x for x in range(10000000)] def using_generator(): return (x for x in range(10000000)) import sys print(f\u0026#34;列表: {sys.getsizeof(using_list())} bytes\u0026#34;) print(f\u0026#34;生成器: {sys.getsizeof(using_generator())} bytes\u0026#34;) # 列表: 约 80MB # 生成器: 约 200 bytes 3. 生成器的实际应用 3.1 处理大数据文件 def read_large_file(filepath, chunk_size=1024): \u0026#34;\u0026#34;\u0026#34;分块读取大文件（节省内存）\u0026#34;\u0026#34;\u0026#34; with open(filepath, \u0026#39;rb\u0026#39;) as f: while True: chunk = f.read(chunk_size) if not chunk: break yield chunk # 使用示例 - 处理大日志文件 def find_errors(log_file): \u0026#34;\u0026#34;\u0026#34;从大日志文件中查找错误\u0026#34;\u0026#34;\u0026#34; error_count = 0 for chunk in read_large_file(log_file): error_count += chunk.count(b\u0026#39;ERROR\u0026#39;) return error_count # 使用 for chunk in read_large_file(\u0026#39;huge_file.dat\u0026#39;): process(chunk) # 每块 1KB 3.2 无限序列 def fibonacci(): \u0026#34;\u0026#34;\u0026#34;无限斐波那契数列生成器\u0026#34;\u0026#34;\u0026#34; a, b = 0, 1 while True: yield a a, b = b, a + b # 获取前 10 个斐波那契数 fib = fibonacci() for _ in range(10): print(next(fib), end=\u0026#39; \u0026#39;) # 0 1 1 2 3 5 8 13 21 34 # 生成无限自然数 def natural_numbers(): n = 1 while True: yield n n += 1 # 累加前 100 个自然数的平方 result = sum(x**2 for x in range(1, 101)) 3.3 管道处理 def numbers(): \u0026#34;\u0026#34;\u0026#34;生成数字\u0026#34;\u0026#34;\u0026#34; for i in range(1, 6): yield i def square(nums): \u0026#34;\u0026#34;\u0026#34;平方\u0026#34;\u0026#34;\u0026#34; for n in nums: yield n ** 2 def filter_odd(nums): \u0026#34;\u0026#34;\u0026#34;过滤奇数\u0026#34;\u0026#34;\u0026#34; for n in nums: if n % 2 == 0: yield n def pipeline(): \u0026#34;\u0026#34;\u0026#34;数据处理管道\u0026#34;\u0026#34;\u0026#34; return filter_odd(square(numbers())) # 使用管道 for num in pipeline(): print(num) # 4, 16 4. yield from 语句 yield from 用于委托给子生成器，简化嵌套生成器的写法。\ndef inner(): yield 1 yield 2 yield 3 # 不用 yield from def without_yield_from(): for item in inner(): yield item # 使用 yield from（更简洁） def with_yield_from(): yield from inner() # 验证 print(list(without_yield_from())) # [1, 2, 3] print(list(with_yield_from())) # [1, 2, 3] # yield from 的实际应用 - 扁平化 def flatten(nested_list): \u0026#34;\u0026#34;\u0026#34;扁平化嵌套列表\u0026#34;\u0026#34;\u0026#34; for item in nested_list: if isinstance(item, list): yield from flatten(item) else: yield item # 使用 nested = [1, [2, [3, 4], 5], 6] print(list(flatten(nested))) # [1, 2, 3, 4, 5, 6] 5. 生成器的方法（协程通信） 生成器有以下方法，可以向正在运行的生成器发送值：\ndef coro(): \u0026#34;\u0026#34;\u0026#34;协程生成器\u0026#34;\u0026#34;\u0026#34; while True: received = yield print(f\u0026#34;收到: {received}\u0026#34;) c = coro() next(c) # 启动生成器到第一个 yield c.send(\u0026#39;Hello\u0026#39;) # 发送值 c.send(\u0026#39;World\u0026#39;) # 发送另一个值 c.close() # 关闭生成器 def counter(initial=0): \u0026#34;\u0026#34;\u0026#34;计数器协程\u0026#34;\u0026#34;\u0026#34; count = initial while True: increment = yield count if increment is None: increment = 1 count += increment # 使用 c = counter(10) print(next(c)) # 10 print(c.send(5)) # 15 print(c.send(5)) # 20 print(next(c)) # 21（send(None) 等价于 next()） 6. itertools 模块 import itertools # count() - 无限计数 for i in itertools.count(10, 2): # 从 10 开始，步长 2 if i \u0026gt; 20: break print(i, end=\u0026#39; \u0026#39;) # 10 12 14 16 18 20 # cycle() - 无限循环 counter = 0 for item in itertools.cycle([\u0026#39;A\u0026#39;, \u0026#39;B\u0026#39;, \u0026#39;C\u0026#39;]): print(item, end=\u0026#39; \u0026#39;) counter += 1 if counter \u0026gt; 8: break # A B C A B C A B C # repeat() - 重复 for i in itertools.repeat(5, 3): # 重复 5，3 次 print(i, end=\u0026#39; \u0026#39;) # 5 5 5 # chain() - 连接多个迭代器 print(list(itertools.chain([1, 2], [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;], [3, 4]))) # [1, 2, \u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, 3, 4] # islice() - 切片迭代器 print(list(itertools.islice(range(10), 2, 8, 2))) # [2, 4, 6] # compress() - 按条件筛选 data = [\u0026#39;A\u0026#39;, \u0026#39;B\u0026#39;, \u0026#39;C\u0026#39;, \u0026#39;D\u0026#39;, \u0026#39;E\u0026#39;] selector = [1, 0, 1, 0, 1] print(list(itertools.compress(data, selector))) # [\u0026#39;A\u0026#39;, \u0026#39;C\u0026#39;, \u0026#39;E\u0026#39;] # takewhile / dropwhile print(list(itertools.takewhile(lambda x: x \u0026lt; 5, [1, 4, 6, 4, 1]))) # [1, 4] print(list(itertools.dropwhile(lambda x: x \u0026lt; 5, [1, 4, 6, 4, 1]))) # [6, 4, 1] # groupby() - 分组 data = [(\u0026#39;A\u0026#39;, 1), (\u0026#39;A\u0026#39;, 2), (\u0026#39;B\u0026#39;, 3), (\u0026#39;B\u0026#39;, 4)] for key, group in itertools.groupby(data, key=lambda x: x[0]): print(f\u0026#34;{key}: {list(group)}\u0026#34;) 7. 生成器在 Python 3.11+ 的改进 # Python 3.11+ 中生成器的类型注解改进 from typing import Generator def my_generator(n: int) -\u0026gt; Generator[int, None, None]: for i in range(n): yield i # 或者使用更简洁的类型别名 from collections.abc import Iterator def my_generator2(n: int) -\u0026gt; Iterator[int]: for i in range(n): yield i 背诵版 核心速查 ┌─────────────────────────────────────────────────────────────┐ │ 迭代器 vs 生成器 │ ├─────────────────────────────────────────────────────────────┤ │ 迭代器：实现了 __iter__() 和 __next__() │ │ 生成器：使用 yield 的特殊迭代器 │ ├─────────────────────────────────────────────────────────────┤ │ iter(obj) → 获取迭代器 │ │ next(it) → 获取下一个元素 │ │ next(it, def) → 提供默认值避免 StopIteration │ │ yield from → 委托给子生成器 │ └─────────────────────────────────────────────────────────────┘生成器特点 生成器 ───── 惰性求值 ───── 节省内存 │ ├── yield ─ 暂停函数，返回值 ├── yield from ─ 委托给子生成器 └── send() ─ 向生成器发送值itertools 常用函数 函数 说明 示例 count() 无限计数 count(10, 2) cycle() 无限循环 cycle('AB') repeat() 重复 repeat(5, 3) chain() 连接 chain([1], [2]) islice() 切片 islice(range(10), 5) takewhile() 条件取 takewhile(cond, iter) dropwhile() 条件丢 dropwhile(cond, iter) groupby() 分组 groupby(data, key) 考前记忆 面试重点 迭代器协议\n__iter__() 返回迭代器本身 __next__() 返回下一个元素，结束时抛出 StopIteration 生成器的特点\n惰性求值，节省内存 使用 yield 暂停函数 函数调用返回生成器对象 yield vs return\nreturn 结束函数并返回值 yield 暂停函数，保存状态，下次调用继续执行 生成器表达式 vs 列表推导式\n列表推导式：[x**2 for x in range(10)] 生成器表达式：(x**2 for x in range(10)) 生成器惰性求值，列表立即求值 yield from 的作用\n委托给子生成器 简化嵌套循环 记忆口诀 迭代器有 iter 和 next， StopIteration 结束收。 生成器用 yield 惰性求， 省内存管道解耦不用愁。 测试题 选择题 1. 以下哪个是生成器函数？\n# A. def func1(): return [1, 2, 3] # B. def func2(): return (x ** 2 for x in range(10)) # C. def func3(): yield 1 yield 2 yield 3 # D. func4 = [x ** 2 for x in range(10)] 答案：C（包含 yield 的函数）\n2. 生成器相比列表的优势是？\n# A. 速度更快 # B. 可以使用更多操作 # C. 惰性求值，节省内存 # D. 可以无限大 答案：C\n3. next(it, 'default') 的作用是？\n# A. 返回第 next 个元素 # B. 迭代两次 # C. 提供默认值，迭代器耗尽时返回默认值而非抛异常 # D. 跳过元素 答案：C\n4. yield from 的作用是？\n# A. 产生值并继续 # B. 委托给子生成器 # C. 结束生成器 # D. 接收值 答案：B\n5. 生成器表达式 (x ** 2 for x in range(5)) 的类型是？\n# A. list # B. tuple # C. generator # D. set 答案：C\n编程题 1. 实现一个生成器函数：\ndef prime_generator(limit): \u0026#34;\u0026#34;\u0026#34;生成素数生成器\u0026#34;\u0026#34;\u0026#34; def is_prime(n): if n \u0026lt; 2: return False for i in range(2, int(n**0.5) + 1): if n % i == 0: return False return True num = 2 while num \u0026lt;= limit: if is_prime(num): yield num num += 1 # 使用 for p in prime_generator(50): print(p, end=\u0026#39; \u0026#39;) # 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 2. 实现文件行生成器：\ndef file_lines(filepath): \u0026#34;\u0026#34;\u0026#34;逐行读取文件（内存高效）\u0026#34;\u0026#34;\u0026#34; with open(filepath, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: for line in f: yield line.strip() # 使用 for line in file_lines(\u0026#39;large_file.txt\u0026#39;): if \u0026#39;error\u0026#39; in line.lower(): print(line) 3. 实现数据处理管道：\ndef generate_numbers(start, end): \u0026#34;\u0026#34;\u0026#34;生成范围内的数字\u0026#34;\u0026#34;\u0026#34; for i in range(start, end + 1): yield i def filter_positive(numbers): \u0026#34;\u0026#34;\u0026#34;过滤正数\u0026#34;\u0026#34;\u0026#34; for n in numbers: if n \u0026gt; 0: yield n def square(numbers): \u0026#34;\u0026#34;\u0026#34;平方\u0026#34;\u0026#34;\u0026#34; for n in numbers: yield n ** 2 def take(numbers, count): \u0026#34;\u0026#34;\u0026#34;取前 n 个\u0026#34;\u0026#34;\u0026#34; for i, n in enumerate(numbers): if i \u0026gt;= count: break yield n def pipeline(start, end, count): \u0026#34;\u0026#34;\u0026#34;数据处理管道\u0026#34;\u0026#34;\u0026#34; return take(square(filter_positive(generate_numbers(start, end))), count) # 使用 print(list(pipeline(-5, 10, 5))) # [1, 4, 9, 16, 25] 4. 使用 itertools 实现复杂操作：\nimport itertools def solve(): # 问题：找出前 10 个同时是 2, 3, 5 的倍数的数 numbers = itertools.cycle([2, 3, 5]) return [x for x in itertools.takewhile(lambda x: len([n for n in [2, 3, 5] if x % n == 0]) == 3, itertools.count())][:10] # 简单版本 def simple_solution(): result = [] n = 1 while len(result) \u0026lt; 10: if n % 30 == 0: # 同时是 2, 3, 5 的倍数 result.append(n) n += 1 return result print(simple_solution()) # [30, 60, 90, 120, 150, 180, 210, 240, 270, 300] 问答题 Q1: 什么是迭代器协议？请描述其核心方法。\n迭代器协议要求对象实现两个方法：\n__iter__()：返回迭代器本身 __next__()：返回下一个元素，当没有更多元素时抛出 StopIteration 异常 这是 Python 中所有迭代器必须遵循的协议。\nQ2: 生成器相比普通函数有什么特点？\n惰性求值：不会立即执行，只有调用 next() 时才产生值 节省内存：不需要一次性生成所有值 状态保持：函数执行到 yield 时暂停，保存局部状态 可迭代：生成器是迭代器，可使用 for 循环遍历 Q3: 什么时候应该使用生成器而不是列表？\n处理大数据：不需要一次性加载所有数据 无限序列：如斐波那契数列、自然数等 内存敏感：内存有限时 流处理：数据来自持续输入（如网络、传感器） 管道处理：多步骤处理，避免创建中间列表 参考资料 Python 官方文档 - 迭代器类型 Python 官方文档 - 生成器 Python 官方文档 - itertools PEP 255 - Simple Generators PEP 380 - Syntax for Delegating to a Subgenerator ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-37-iterator-generator/","summary":"\u003ch1 id=\"day37---迭代器与生成器详解\"\u003eDay37 - 迭代器与生成器详解\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"1-迭代器基础\"\u003e1. 迭代器基础\u003c/h3\u003e\n\u003ch4 id=\"11-可迭代对象与迭代器\"\u003e1.1 可迭代对象与迭代器\u003c/h4\u003e\n\u003cp\u003e\u003cstrong\u003e可迭代对象（Iterable）\u003c/strong\u003e：可以使用 \u003ccode\u003efor\u003c/code\u003e 循环遍历的对象，如 list, dict, str, file 等。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e迭代器（Iterator）\u003c/strong\u003e：实现了 \u003ccode\u003e__iter__()\u003c/code\u003e 和 \u003ccode\u003e__next__()\u003c/code\u003e 方法的对象。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 可迭代对象\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enumbers \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e]  \u003cspan style=\"color:#75715e\"\u003e# list 是可迭代对象\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 获取迭代器\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eiterator \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e iter(numbers)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;迭代器: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eiterator\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 手动迭代\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(next(iterator))  \u003cspan style=\"color:#75715e\"\u003e# 1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(next(iterator))  \u003cspan style=\"color:#75715e\"\u003e# 2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(next(iterator))  \u003cspan style=\"color:#75715e\"\u003e# 3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(next(iterator))  \u003cspan style=\"color:#75715e\"\u003e# StopIteration 异常\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"12-迭代器协议\"\u003e1.2 迭代器协议\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 迭代器必须实现的两个方法\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eMyIterator\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e __init__(self, data):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edata \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e data\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eindex \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e __iter__(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;返回迭代器本身\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e self\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e __next__(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;返回下一个元素\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eindex \u003cspan style=\"color:#f92672\"\u003e\u0026gt;=\u003c/span\u003e len(self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edata):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eraise\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eStopIteration\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        value \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edata[self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eindex]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eindex \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e value\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eit \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e MyIterator([\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e item \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e it:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(item)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"13-iter-和-next-内置函数\"\u003e1.3 iter() 和 next() 内置函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# iter() 可以接受两个参数：可迭代对象 + 哨兵值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 这样会在每次 next() 时调用可迭代对象，直到返回值等于哨兵值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 示例：读取行直到空行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;lines.txt\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e line \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e iter(f\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ereadline, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(line\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estrip())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# next() 可以指定默认值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enumbers \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eit \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e iter(numbers)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(next(it, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;默认值\u0026#39;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(next(it, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;默认值\u0026#39;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(next(it, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;默认值\u0026#39;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(next(it, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;默认值\u0026#39;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 默认值（不会抛出 StopIteration）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"2-生成器基础\"\u003e2. 生成器基础\u003c/h3\u003e\n\u003cp\u003e生成器是一种特殊的迭代器，使用 \u003ccode\u003eyield\u003c/code\u003e 关键字来产生值，而不是 \u003ccode\u003ereturn\u003c/code\u003e。\u003c/p\u003e","tags":"python, iterator, generator, yield, iter, next","title":"Day37 - 迭代器与生成器详解"},{"columns":"python-course","content":"Day38 - 装饰器详解 (@decorator/wraps/闭包) 详细讲解 1. 闭包基础 1.1 什么是闭包 闭包是指一个函数记住其创建时所处的环境（外部作用域的变量）的机制。\ndef outer(): x = 10 # 外部变量 def inner(): print(x) # 引用外部变量 return inner # 创建闭包 closure = outer() closure() # 输出 10 # 验证闭包 print(f\u0026#34;closure.__closure__: {closure.__closure__}\u0026#34;) # 闭包变量 print(f\u0026#34;closure.__code__.co_freevars: {closure.__code__.co_freevars}\u0026#34;) # 自由变量名 1.2 闭包的经典应用 def make_multiplier(factor): \u0026#34;\u0026#34;\u0026#34;创建乘数函数（闭包）\u0026#34;\u0026#34;\u0026#34; def multiply(x): return x * factor return multiply # 创建两个不同的乘数 times_2 = make_multiplier(2) times_3 = make_multiplier(3) times_5 = make_multiplier(5) print(times_2(10)) # 20 print(times_3(10)) # 30 print(times_5(10)) # 50 # 闭包会记住创建时的 factor 值 print(f\u0026#34;times_2 的闭包: {times_2.__closure__[0].cell_contents}\u0026#34;) # 2 1.3 闭包的常见陷阱 # 陷阱：循环中的闭包 def create_funcs(): funcs = [] for i in range(3): # 错误！所有函数都会引用同一个 i def func(): return i funcs.append(func) return funcs funcs = create_funcs() print([f() for f in funcs]) # [2, 2, 2] - 不是 [0, 1, 2]！ # 正确做法：使用默认参数捕获当前值 def create_funcs_fixed(): funcs = [] for i in range(3): def func(i=i): # 默认参数在定义时绑定 return i funcs.append(func) return funcs funcs = create_funcs_fixed() print([f() for f in funcs]) # [0, 1, 2] 2. 装饰器基础 装饰器是一个返回函数的高阶函数，用于在不修改原函数的情况下扩展功能。\n2.1 简单装饰器 def my_decorator(func): \u0026#34;\u0026#34;\u0026#34;装饰器函数\u0026#34;\u0026#34;\u0026#34; def wrapper(*args, **kwargs): print(\u0026#34;函数开始执行\u0026#34;) result = func(*args, **kwargs) print(\u0026#34;函数执行结束\u0026#34;) return result return wrapper @my_decorator def say_hello(name): print(f\u0026#34;你好，{name}！\u0026#34;) # 等价于 say_hello = my_decorator(say_hello) say_hello(\u0026#34;张三\u0026#34;) 2.2 装饰器的执行时机 print(\u0026#34;装饰器定义位置\u0026#34;) @my_decorator # 装饰器在被装饰函数定义时立即执行 def test(): print(\u0026#34;test 函数执行\u0026#34;) print(\u0026#34;装饰器定义后\u0026#34;) # 输出顺序： # 装饰器定义位置 # 装饰器定义后 # （装饰器函数执行时输出 \u0026#34;函数开始执行\u0026#34;） # test 函数执行 # 函数执行结束 2.3 带参数的装饰器 def repeat(times): \u0026#34;\u0026#34;\u0026#34;带参数的装饰器工厂函数\u0026#34;\u0026#34;\u0026#34; def decorator(func): def wrapper(*args, **kwargs): for _ in range(times): result = func(*args, **kwargs) return result return wrapper return decorator @repeat(3) # 会打印 3 次 def greet(name): print(f\u0026#34;你好，{name}！\u0026#34;) greet(\u0026#34;李四\u0026#34;) # 输出： # 你好，李四！ # 你好，李四！ # 你好，李四！ 3. functools.wraps 详解 wraps 用于保留原函数的元信息（名称、文档等）。\nimport functools def my_decorator(func): @functools.wraps(func) # 保留原函数元信息 def wrapper(*args, **kwargs): print(\u0026#34;扩展功能\u0026#34;) return func(*args, **kwargs) return wrapper @my_decorator def original_func(): \u0026#34;\u0026#34;\u0026#34;这是 original_func 的文档\u0026#34;\u0026#34;\u0026#34; pass # 不使用 wraps 的问题 def bad_decorator(func): def wrapper(*args, **kwargs): return func(*args, **kwargs) wrapper.__name__ = func.__name__ # 手动复制（不推荐） return wrapper # 使用 wraps print(original_func.__name__) # \u0026#39;original_func\u0026#39; print(original_func.__doc__) # \u0026#39;这是 original_func 的文档\u0026#39; 4. 类装饰器 import functools class CountCalls: \u0026#34;\u0026#34;\u0026#34;计数装饰器类\u0026#34;\u0026#34;\u0026#34; def __init__(self, func): self.func = func self.count = 0 functools.update_wrapper(self, func) def __call__(self, *args, **kwargs): self.count += 1 print(f\u0026#34;函数被调用了 {self.count} 次\u0026#34;) return self.func(*args, **kwargs) @CountCalls def some_function(): return 42 some_function() # 函数被调用了 1 次 some_function() # 函数被调用了 2 次 print(some_function.count) # 2 5. 多重装饰器 装饰器可以叠加，按从下到上的顺序执行。\ndef decorator1(func): def wrapper(*args, **kwargs): print(\u0026#34;装饰器 1 开始\u0026#34;) result = func(*args, **kwargs) print(\u0026#34;装饰器 1 结束\u0026#34;) return result return wrapper def decorator2(func): def wrapper(*args, **kwargs): print(\u0026#34;装饰器 2 开始\u0026#34;) result = func(*args, **kwargs) print(\u0026#34;装饰器 2 结束\u0026#34;) return result return wrapper @decorator1 @decorator2 def hello(): print(\u0026#34;Hello!\u0026#34;) # 执行顺序： # 装饰器 1 开始 # 装饰器 2 开始 # Hello! # 装饰器 2 结束 # 装饰器 1 结束 6. 装饰器实际应用 6.1 计时器装饰器 import functools import time def timer(func): \u0026#34;\u0026#34;\u0026#34;函数执行计时装饰器\u0026#34;\u0026#34;\u0026#34; @functools.wraps(func) def wrapper(*args, **kwargs): start = time.perf_counter() result = func(*args, **kwargs) end = time.perf_counter() print(f\u0026#34;{func.__name__} 执行耗时: {end - start:.4f} 秒\u0026#34;) return result return wrapper @timer def slow_function(): time.sleep(1) return \u0026#34;完成\u0026#34; @timer def calculate_sum(n): return sum(range(n)) 6.2 日志装饰器 import functools import logging # 配置日志 logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def log_calls(func): \u0026#34;\u0026#34;\u0026#34;日志记录装饰器\u0026#34;\u0026#34;\u0026#34; @functools.wraps(func) def wrapper(*args, **kwargs): logger.info(f\u0026#34;调用 {func.__name__}, 参数: args={args}, kwargs={kwargs}\u0026#34;) try: result = func(*args, **kwargs) logger.info(f\u0026#34;{func.__name__} 返回: {result}\u0026#34;) return result except Exception as e: logger.error(f\u0026#34;{func.__name__} 抛出异常: {e}\u0026#34;) raise return wrapper @log_calls def divide(a, b): return a / b 6.3 缓存装饰器 import functools def memoize(func): \u0026#34;\u0026#34;\u0026#34;简单的缓存装饰器（适用于纯函数）\u0026#34;\u0026#34;\u0026#34; cache = {} @functools.wraps(func) def wrapper(*args): if args not in cache: cache[args] = func(*args) return cache[args] # 暴露缓存接口 wrapper.cache = cache wrapper.clear_cache = lambda: cache.clear() return wrapper @memoize def fibonacci(n): \u0026#34;\u0026#34;\u0026#34;斐波那契数列（带缓存）\u0026#34;\u0026#34;\u0026#34; if n \u0026lt; 2: return n return fibonacci(n - 1) + fibonacci(n - 2) # 使用缓存 print(fibonacci(100)) # 很快，因为使用了缓存 print(fibonacci.cache) # 查看缓存内容 6.4 重试装饰器 import functools import time def retry(max_attempts=3, delay=1, exceptions=(Exception,)): \u0026#34;\u0026#34;\u0026#34;重试装饰器\u0026#34;\u0026#34;\u0026#34; def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): attempts = 0 while attempts \u0026lt; max_attempts: try: return func(*args, **kwargs) except exceptions as e: attempts += 1 if attempts \u0026gt;= max_attempts: raise print(f\u0026#34;第 {attempts} 次尝试失败，重试中... ({e})\u0026#34;) time.sleep(delay) return wrapper return decorator @retry(max_attempts=3, delay=0.5) def unreliable_api_call(): import random if random.random() \u0026lt; 0.7: raise ConnectionError(\u0026#34;连接失败\u0026#34;) return \u0026#34;成功\u0026#34; 6.5 类型检查装饰器 import functools def type_check(func): \u0026#34;\u0026#34;\u0026#34;运行时类型检查装饰器\u0026#34;\u0026#34;\u0026#34; @functools.wraps(func) def wrapper(*args, **kwargs): # 获取函数签名 hints = func.__annotations__ # 检查参数类型 for arg, (name, expected_type) in zip(args, list(hints.items())[:-1]): if name in hints and not isinstance(arg, hints[name]): raise TypeError(f\u0026#34;参数 {name} 期望 {expected_type.__name__}, 得到 {type(arg).__name__}\u0026#34;) return func(*args, **kwargs) return wrapper @type_check def add(a: int, b: int) -\u0026gt; int: return a + b # add(1, 2) # 3 # add(\u0026#34;1\u0026#34;, \u0026#34;2\u0026#34;) # TypeError 7. 装饰器类与装饰器工厂 import functools # 装饰器工厂：返回装饰器的函数 def requires_permission(permission): \u0026#34;\u0026#34;\u0026#34;权限检查装饰器工厂\u0026#34;\u0026#34;\u0026#34; def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): # 假设有一个权限检查逻辑 if check_permission(permission): return func(*args, **kwargs) else: raise PermissionError(f\u0026#34;需要 {permission} 权限\u0026#34;) return wrapper return decorator def check_permission(permission): \u0026#34;\u0026#34;\u0026#34;模拟权限检查\u0026#34;\u0026#34;\u0026#34; return True @requires_permission(\u0026#39;admin\u0026#39;) def delete_user(user_id): print(f\u0026#34;删除用户 {user_id}\u0026#34;) # 使用类作为装饰器 class RateLimit: \u0026#34;\u0026#34;\u0026#34;速率限制装饰器类\u0026#34;\u0026#34;\u0026#34; def __init__(self, max_calls=10, period=60): self.max_calls = max_calls self.period = period self.calls = [] def __call__(self, func): @functools.wraps(func) def wrapper(*args, **kwargs): now = time.time() self.calls = [t for t in self.calls if now - t \u0026lt; self.period] if len(self.calls) \u0026gt;= self.max_calls: raise RuntimeError(\u0026#34;速率限制触发\u0026#34;) self.calls.append(now) return func(*args, **kwargs) return wrapper @RateLimit(max_calls=5, period=10) def api_endpoint(): return \u0026#34;API 响应\u0026#34; 8. 装饰器与类方法 import functools def log_method(func): \u0026#34;\u0026#34;\u0026#34;类方法装饰器\u0026#34;\u0026#34;\u0026#34; @functools.wraps(func) def wrapper(self, *args, **kwargs): print(f\u0026#34;调用方法 {func.__name__}\u0026#34;) return func(self, *args, **kwargs) return wrapper def log_classmethods(cls): \u0026#34;\u0026#34;\u0026#34;类装饰器：自动装饰所有方法\u0026#34;\u0026#34;\u0026#34; for name, method in vars(cls).items(): if callable(method) and not name.startswith(\u0026#39;_\u0026#39;): setattr(cls, name, log_method(method)) return cls @log_classmethods class MyClass: def method1(self): return \u0026#34;方法1\u0026#34; def method2(self): return \u0026#34;方法2\u0026#34; obj = MyClass() obj.method1() # 调用方法 method1 obj.method2() # 调用方法 method2 背诵版 核心速查 ┌─────────────────────────────────────────────────────────────┐ │ 装饰器速查 │ ├─────────────────────────────────────────────────────────────┤ │ @decorator ─ 应用装饰器 │ │ @decorator(args) ─ 带参数装饰器 │ │ functools.wraps ─ 保留原函数元信息 │ │ 多重装饰器 ─ 从下到上的顺序执行 │ └─────────────────────────────────────────────────────────────┘装饰器模板 import functools def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): # 前置处理 result = func(*args, **kwargs) # 后置处理 return result return wrapper # 带参数的装饰器 def decorator_factory(arg): def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): # 使用 arg return func(*args, **kwargs) return wrapper return decorator 考前记忆 面试重点 装饰器的本质\n本质是一个返回函数的高阶函数 用于不修改原函数的情况下扩展功能 @functools.wraps 的作用\n保留原函数的 __name__、__doc__ 等元信息 必须在 wrapper 函数上使用 装饰器的执行顺序\n多重装饰器从下到上执行 装饰发生在函数定义时，不是在调用时 闭包与装饰器的关系\n装饰器利用闭包来\u0026quot;记住\u0026quot;被装饰的函数 wrapper 闭包引用了原函数 *args, **kwargs 的重要性\n让装饰器通用化，传递任意参数 使用 functools.wraps 保留签名信息 记忆口诀 装饰器是返回函数的高阶函数， wraps 保留元信息。 闭包记住外部变量， 装饰顺序从下到上。 测试题 选择题 1. 装饰器的本质是什么？\n# A. 一个类 # B. 一个返回函数的高阶函数 # C. 一个特殊语法 # D. 一个闭包 答案：B\n2. 以下代码的输出是什么？\ndef decorator(func): def wrapper(): print(\u0026#34;A\u0026#34;) func() return wrapper @decorator def say(): print(\u0026#34;B\u0026#34;) say() # A. A # B. B # C. A B # D. B A 答案：C\n3. functools.wraps 的作用是？\n# A. 创建装饰器 # B. 保留原函数的元信息 # C. 执行函数 # D. 创建闭包 答案：B\n4. 多重装饰器的执行顺序是？\n@decorator1 @decorator2 def func(): pass # A. 先执行 decorator1，再执行 decorator2 # B. 先执行 decorator2，再执行 decorator1 # C. 同时执行 # D. 不执行任何装饰器 答案：B（从下到上）\n5. 闭包的作用是？\n# A. 加快函数执行 # B. 让函数记住外部作用域的变量 # C. 限制函数作用域 # D. 创建类 答案：B\n编程题 1. 实现一个日志装饰器：\nimport functools import time def log(func): \u0026#34;\u0026#34;\u0026#34;日志记录装饰器\u0026#34;\u0026#34;\u0026#34; @functools.wraps(func) def wrapper(*args, **kwargs): print(f\u0026#34;[{time.strftime(\u0026#39;%Y-%m-%d %H:%M:%S\u0026#39;)}] 调用 {func.__name__}\u0026#34;) start = time.time() result = func(*args, **kwargs) end = time.time() print(f\u0026#34;[{time.strftime(\u0026#39;%Y-%m-%d %H:%M:%S\u0026#39;)}] {func.__name__} 返回 {result}, 耗时 {end-start:.4f}s\u0026#34;) return result return wrapper @log def add(a, b): return a + b @log def slow_func(): time.sleep(1) return \u0026#34;完成\u0026#34; 2. 实现一个缓存装饰器：\nimport functools import hashlib import json def cache(func): \u0026#34;\u0026#34;\u0026#34;缓存装饰器\u0026#34;\u0026#34;\u0026#34; @functools.wraps(func) def wrapper(*args, **kwargs): # 生成缓存键 key = f\u0026#34;{func.__name__}_{args}_{kwargs}\u0026#34; cache_key = hashlib.md5(str(key).encode()).hexdigest() # 检查缓存 if hasattr(wrapper, \u0026#39;_cache\u0026#39;) and cache_key in wrapper._cache: print(f\u0026#34;缓存命中: {cache_key}\u0026#34;) return wrapper._cache[cache_key] # 执行函数 result = func(*args, **kwargs) # 保存到缓存 if not hasattr(wrapper, \u0026#39;_cache\u0026#39;): wrapper._cache = {} wrapper._cache[cache_key] = result return result return wrapper @cache def fibonacci(n): if n \u0026lt; 2: return n return fibonacci(n - 1) + fibonacci(n - 2) print(fibonacci(100)) # 第一次计算 print(fibonacci(100)) # 缓存命中 3. 实现一个类装饰器：\nimport functools class Validator: \u0026#34;\u0026#34;\u0026#34;验证器装饰器类\u0026#34;\u0026#34;\u0026#34; def __init__(self, func): self.func = func functools.update_wrapper(self, func) def __call__(self, *args, **kwargs): # 验证逻辑 if hasattr(self.func, \u0026#39;__annotations__\u0026#39;): hints = self.func.__annotations__ for arg, (name, expected) in zip(args, list(hints.items())): if name in hints and not isinstance(arg, expected): raise TypeError(f\u0026#34;{name} 应该是 {expected.__name__}\u0026#34;) return self.func(*args, **kwargs) @Validator def add(a: int, b: int) -\u0026gt; int: return a + b 问答题 Q1: 什么是装饰器？请解释装饰器的工作原理。\n装饰器是一个接受函数作为参数并返回新函数的函数。其工作原理：\n当 Python 遇到 @decorator 时，会将被装饰的函数作为参数传给装饰器函数 装饰器函数返回一个新的包装函数（wrapper） 原来的函数名被替换为包装函数 调用原函数时，实际执行的是包装函数 @decorator def func(): pass # 等价于 func = decorator(func) Q2: 为什么需要 functools.wraps？如果不使用会有什么后果？\nfunctools.wraps 用于将原函数的元信息复制到包装函数中。如果不使用：\nfunc.__name__ 会变成 'wrapper' func.__doc__ 会变成包装函数的文档或为空 可能影响调试和反射工具 使用 wraps 可以保留原函数的名称、文档、模块等信息。\nQ3: 装饰器和闭包有什么区别和联系？\n区别：\n闭包是一种语言特性，指函数记住外部作用域变量 装饰器是一种应用闭包的设计模式 联系：\n装饰器的 wrapper 函数就是一个闭包 它引用了被装饰的原函数（外部变量） def decorator(func): # func 是外部变量 def wrapper(*args): # wrapper 是闭包 return func(*args) # 引用外部变量 func return wrapper 参考资料 Python 官方文档 - functools PEP 318 - Decorators for Functions and Methods Python 装饰器完全指南 ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-38-decorator/","summary":"\u003ch1 id=\"day38---装饰器详解-decoratorwraps闭包\"\u003eDay38 - 装饰器详解 (@decorator/wraps/闭包)\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"1-闭包基础\"\u003e1. 闭包基础\u003c/h3\u003e\n\u003ch4 id=\"11-什么是闭包\"\u003e1.1 什么是闭包\u003c/h4\u003e\n\u003cp\u003e闭包是指一个函数记住其创建时所处的环境（外部作用域的变量）的机制。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eouter\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    x \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 外部变量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003einner\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(x)  \u003cspan style=\"color:#75715e\"\u003e# 引用外部变量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e inner\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 创建闭包\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eclosure \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e outer()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eclosure()  \u003cspan style=\"color:#75715e\"\u003e# 输出 10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 验证闭包\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;closure.__closure__: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eclosure\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e__closure__\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 闭包变量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;closure.__code__.co_freevars: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eclosure\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e__code__\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eco_freevars\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 自由变量名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"12-闭包的经典应用\"\u003e1.2 闭包的经典应用\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emake_multiplier\u003c/span\u003e(factor):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;创建乘数函数（闭包）\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emultiply\u003c/span\u003e(x):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e x \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e factor\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e multiply\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 创建两个不同的乘数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etimes_2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e make_multiplier(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etimes_3 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e make_multiplier(\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etimes_5 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e make_multiplier(\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(times_2(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 20\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(times_3(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 30\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(times_5(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# 50\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 闭包会记住创建时的 factor 值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;times_2 的闭包: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etimes_2\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e__closure__[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e]\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecell_contents\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"13-闭包的常见陷阱\"\u003e1.3 闭包的常见陷阱\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 陷阱：循环中的闭包\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecreate_funcs\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    funcs \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 错误！所有函数都会引用同一个 i\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efunc\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e i\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        funcs\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(func)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e funcs\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003efuncs \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e create_funcs()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint([f() \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e f \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e funcs])  \u003cspan style=\"color:#75715e\"\u003e# [2, 2, 2] - 不是 [0, 1, 2]！\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 正确做法：使用默认参数捕获当前值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecreate_funcs_fixed\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    funcs \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efunc\u003c/span\u003e(i\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003ei):  \u003cspan style=\"color:#75715e\"\u003e# 默认参数在定义时绑定\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e i\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        funcs\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(func)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e funcs\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003efuncs \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e create_funcs_fixed()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint([f() \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e f \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e funcs])  \u003cspan style=\"color:#75715e\"\u003e# [0, 1, 2]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"2-装饰器基础\"\u003e2. 装饰器基础\u003c/h3\u003e\n\u003cp\u003e装饰器是一个返回函数的高阶函数，用于在不修改原函数的情况下扩展功能。\u003c/p\u003e","tags":"python, decorator, wraps, closure, @","title":"Day38 装饰器详解"},{"columns":"python-course","content":"Day39 - 正则表达式基础 详细讲解 1. 正则表达式简介 正则表达式是一种用于匹配字符串的模式表达式，在文本处理、数据提取、验证等场景中广泛应用。\nimport re # 最简单的匹配 pattern = r\u0026#39;hello\u0026#39; text = \u0026#39;hello world\u0026#39; if re.search(pattern, text): print(\u0026#34;找到匹配！\u0026#34;) # 常用场景 # 1. 验证邮箱格式 # 2. 提取网页中的链接 # 3. 处理日志文件 # 4. 数据清洗和转换 2. re 模块主要函数 2.1 re.match() - 从开头匹配 import re # match() 从字符串开头匹配 result = re.match(r\u0026#39;hello\u0026#39;, \u0026#39;hello world\u0026#39;) print(result) # \u0026lt;re.Match object\u0026gt; print(result.group()) # \u0026#39;hello\u0026#39; print(result.span()) # (0, 5) # 如果开头不匹配，返回 None result = re.match(r\u0026#39;world\u0026#39;, \u0026#39;hello world\u0026#39;) print(result) # None # 使用分组 result = re.match(r\u0026#39;(\\w+), (\\w+)\u0026#39;, \u0026#39;hello, world\u0026#39;) if result: print(result.group(1)) # \u0026#39;hello\u0026#39; print(result.group(2)) # \u0026#39;world\u0026#39; print(result.groups()) # (\u0026#39;hello\u0026#39;, \u0026#39;world\u0026#39;) 2.2 re.search() - 搜索匹配 # search() 在字符串任意位置查找第一个匹配 result = re.search(r\u0026#39;world\u0026#39;, \u0026#39;hello world\u0026#39;) print(result.group()) # \u0026#39;world\u0026#39; print(result.span()) # (6, 11) # 搜索邮箱 text = \u0026#34;联系邮箱: test@example.com 或 admin@test.org\u0026#34; result = re.search(r\u0026#39;\\w+@\\w+\\.\\w+\u0026#39;, text) print(result.group()) # \u0026#39;test@example.com\u0026#39; # 找不到返回 None result = re.search(r\u0026#39;notfound\u0026#39;, \u0026#39;hello\u0026#39;) print(result) # None 2.3 re.findall() - 查找所有匹配 # findall() 返回所有匹配的列表 text = \u0026#34;我的邮箱是 test@example.com，副邮箱是 backup@example.org\u0026#34; # 查找所有邮箱 emails = re.findall(r\u0026#39;\\w+@\\w+\\.\\w+\u0026#39;, text) print(emails) # [\u0026#39;test@example.com\u0026#39;, \u0026#39;backup@example.org\u0026#39;] # 查找所有数字 numbers = re.findall(r\u0026#39;\\d+\u0026#39;, \u0026#39;我有 3 个苹果，5 个橙子，共 8 个水果\u0026#39;) print(numbers) # [\u0026#39;3\u0026#39;, \u0026#39;5\u0026#39;, \u0026#39;8\u0026#39;] # 使用分组 - 返回分组内容的列表 text = \u0026#34;红色: #FF0000, 绿色: #00FF00, 蓝色: #0000FF\u0026#34; colors = re.findall(r\u0026#39;#([0-9A-Fa-f]{6})\u0026#39;, text) print(colors) # [\u0026#39;FF0000\u0026#39;, \u0026#39;00FF00\u0026#39;, \u0026#39;0000FF\u0026#39;] 2.4 re.finditer() - 迭代器版本 # finditer() 返回迭代器，比 findall() 内存效率高 text = \u0026#34;邮箱: a@test.com, b@test.com, c@test.com\u0026#34; for match in re.finditer(r\u0026#39;\\w+@\\w+\\.\\w+\u0026#39;, text): print(f\u0026#34;位置 {match.span()}: {match.group()}\u0026#34;) 3. 字符类（Character Classes） # [] - 匹配方括号内的任意一个字符 # 匹配元音字母 vowels = re.findall(r\u0026#39;[aeiouAEIOU]\u0026#39;, \u0026#39;Hello World\u0026#39;) print(vowels) # [\u0026#39;e\u0026#39;, \u0026#39;o\u0026#39;, \u0026#39;o\u0026#39;] # 匹配数字或字母 alphanum = re.findall(r\u0026#39;[a-zA-Z0-9]\u0026#39;, \u0026#39;Hello123!\u0026#39;) print(alphanum) # [\u0026#39;H\u0026#39;, \u0026#39;e\u0026#39;, \u0026#39;l\u0026#39;, \u0026#39;l\u0026#39;, \u0026#39;o\u0026#39;, \u0026#39;1\u0026#39;, \u0026#39;2\u0026#39;, \u0026#39;3\u0026#39;] # [^] - 否定，匹配不在方括号内的字符 non_vowels = re.findall(r\u0026#39;[^aeiouAEIOU]\u0026#39;, \u0026#39;Hello\u0026#39;) print(non_vowels) # [\u0026#39;H\u0026#39;, \u0026#39;l\u0026#39;, \u0026#39;l\u0026#39;] # 常用简写 # \\d = [0-9] 数字 # \\D = [^0-9] 非数字 # \\w = [a-zA-Z0-9_] 单词字符 # \\W = [^a-zA-Z0-9_] 非单词字符 # \\s = [ \\t\\n\\r\\f\\v] 空白字符 # \\S = [^ \\t\\n\\r\\f\\v] 非空白字符 # . = 任意字符（除换行符） # 示例 text = \u0026#34;用户: ZhangSan, 年龄: 25, 电话: 138-0000-8888\u0026#34; ages = re.findall(r\u0026#39;\\d+\u0026#39;, text) print(ages) # [\u0026#39;25\u0026#39;, \u0026#39;138\u0026#39;, \u0026#39;0000\u0026#39;, \u0026#39;8888\u0026#39;] words = re.findall(r\u0026#39;\\w+\u0026#39;, text) print(words) # [\u0026#39;用户\u0026#39;, \u0026#39;ZhangSan\u0026#39;, \u0026#39;年龄\u0026#39;, \u0026#39;25\u0026#39;, \u0026#39;电话\u0026#39;, \u0026#39;138\u0026#39;, \u0026#39;0000\u0026#39;, \u0026#39;8888\u0026#39;] 4. 量词（Quantifiers） # * - 0 次或多次 # + - 1 次或多次 # ? - 0 次或 1 次 # {n} - 恰好 n 次 # {n,} - 至少 n 次 # {n,m} - n 到 m 次 # * 示例：匹配任意数量字符 pattern = r\u0026#39;ab*c\u0026#39; # ac, abc, abbc, abbbc, ... print(re.findall(r\u0026#39;ab*c\u0026#39;, \u0026#39;ac abc abbc abbbc\u0026#39;)) # [\u0026#39;ac\u0026#39;, \u0026#39;abc\u0026#39;, \u0026#39;abbc\u0026#39;, \u0026#39;abbbc\u0026#39;] # + 示例：至少一个 pattern = r\u0026#39;ab+c\u0026#39; # abc, abbc, abbbc, ... (不包括 ac) print(re.findall(r\u0026#39;ab+c\u0026#39;, \u0026#39;ac abc abbc\u0026#39;)) # [\u0026#39;abc\u0026#39;, \u0026#39;abbc\u0026#39;] # ? 示例：可选 pattern = r\u0026#39;colou?r\u0026#39; # color, colour print(re.findall(r\u0026#39;colou?r\u0026#39;, \u0026#39;color colour\u0026#39;)) # [\u0026#39;color\u0026#39;, \u0026#39;colour\u0026#39;] # {n} 示例：精确次数 pattern = r\u0026#39;\\d{4}\u0026#39; # 4 位数字 print(re.findall(r\u0026#39;\\d{4}\u0026#39;, \u0026#39;2024年 12345月\u0026#39;)) # [\u0026#39;2024\u0026#39;, \u0026#39;1234\u0026#39;] # {n,m} 示例：范围次数 pattern = r\u0026#39;\\d{2,4}\u0026#39; # 2-4 位数字 print(re.findall(r\u0026#39;\\d{2,4}\u0026#39;, \u0026#39;1 12 123 1234 12345\u0026#39;)) # [\u0026#39;12\u0026#39;, \u0026#39;123\u0026#39;, \u0026#39;1234\u0026#39;, \u0026#39;1234\u0026#39;, \u0026#39;5\u0026#39;] - 注意贪婪匹配 # 贪婪 vs 非贪婪（最小匹配） text = \u0026#39;\u0026lt;div\u0026gt;content\u0026lt;/div\u0026gt;\u0026#39; # 贪婪：尽可能多匹配 print(re.findall(r\u0026#39;\u0026lt;div\u0026gt;.*\u0026lt;/div\u0026gt;\u0026#39;, text)) # [\u0026#39;\u0026lt;div\u0026gt;content\u0026lt;/div\u0026gt;\u0026#39;] # 非贪婪：尽可能少匹配 print(re.findall(r\u0026#39;\u0026lt;div\u0026gt;.*?\u0026lt;/div\u0026gt;\u0026#39;, text)) # [\u0026#39;\u0026lt;div\u0026gt;content\u0026lt;/div\u0026gt;\u0026#39;] # 非贪婪添加 ? text = \u0026#39;\u0026lt;div\u0026gt;div1\u0026lt;/div\u0026gt;\u0026lt;div\u0026gt;div2\u0026lt;/div\u0026gt;\u0026#39; print(re.findall(r\u0026#39;\u0026lt;div\u0026gt;.*?\u0026lt;/div\u0026gt;\u0026#39;, text)) # [\u0026#39;\u0026lt;div\u0026gt;div1\u0026lt;/div\u0026gt;\u0026#39;, \u0026#39;\u0026lt;div\u0026gt;div2\u0026lt;/div\u0026gt;\u0026#39;] 5. 边界匹配 # ^ - 字符串开头 # $ - 字符串结尾 # \\b - 单词边界 # \\B - 非单词边界 # 匹配以数字开头的行 text = \u0026#34;123abc\\nhello\\n456xyz\u0026#34; lines = re.findall(r\u0026#39;^\\d+\u0026#39;, text, re.MULTILINE) print(lines) # [\u0026#39;123\u0026#39;, \u0026#39;456\u0026#39;] # 匹配以.com结尾的域名 domains = re.findall(r\u0026#39;\\w+\\.com$\u0026#39;, \u0026#39;test.com\\nexample.org\\nmail.com\u0026#39;) print(domains) # [\u0026#39;test.com\u0026#39;, \u0026#39;mail.com\u0026#39;] # \\b 边界示例 text = \u0026#34;a cat a the in cat\u0026#34; # 匹配完整的单词 \u0026#39;cat\u0026#39; cats = re.findall(r\u0026#39;\\bcat\\b\u0026#39;, text) print(cats) # [\u0026#39;cat\u0026#39;, \u0026#39;cat\u0026#39;] - 两个独立的 cat # 不使用边界 cats_all = re.findall(r\u0026#39;cat\u0026#39;, text) print(cats_all) # [\u0026#39;cat\u0026#39;, \u0026#39;cat\u0026#39;, \u0026#39;cat\u0026#39;] - 包括 a[cat] 中的 cat # \\B 非边界示例 text = \u0026#34;abc abc\u0026#34; print(re.findall(r\u0026#39;ab\\B\u0026#39;, text)) # [\u0026#39;ab\u0026#39;] - abc 中的 ab print(re.findall(r\u0026#39;\\Bab\\B\u0026#39;, text)) # [] - 开头和结尾的 ab 都不匹配 6. 分组（Groups） # () - 创建分组 # 提取邮箱用户名和域名 text = \u0026#34;邮箱: john@example.com 和 jane@test.org\u0026#34; matches = re.findall(r\u0026#39;(\\w+)@(\\w+)\\.(\\w+)\u0026#39;, text) print(matches) # [(\u0026#39;john\u0026#39;, \u0026#39;example\u0026#39;, \u0026#39;com\u0026#39;), (\u0026#39;jane\u0026#39;, \u0026#39;test\u0026#39;, \u0026#39;org\u0026#39;)] # 嵌套分组 text = \u0026#34;2024-05-01\u0026#34; match = re.search(r\u0026#39;(\\d{4})-(\\d{2})-(\\d{2})\u0026#39;, text) if match: print(match.groups()) # (\u0026#39;2024\u0026#39;, \u0026#39;05\u0026#39;, \u0026#39;01\u0026#39;) print(match.group(1)) # \u0026#39;2024\u0026#39; 年 print(match.group(2)) # \u0026#39;05\u0026#39; 月 print(match.group(3)) # \u0026#39;01\u0026#39; 日 # 命名分组 pattern = r\u0026#39;(?P\u0026lt;year\u0026gt;\\d{4})-(?P\u0026lt;month\u0026gt;\\d{2})-(?P\u0026lt;day\u0026gt;\\d{2})\u0026#39; match = re.search(pattern, \u0026#39;2024-05-01\u0026#39;) if match: print(match.group(\u0026#39;year\u0026#39;)) # \u0026#39;2024\u0026#39; print(match.group(\u0026#39;month\u0026#39;)) # \u0026#39;05\u0026#39; print(match.group(\u0026#39;day\u0026#39;)) # \u0026#39;01\u0026#39; print(match.groupdict()) # {\u0026#39;year\u0026#39;: \u0026#39;2024\u0026#39;, \u0026#39;month\u0026#39;: \u0026#39;05\u0026#39;, \u0026#39;day\u0026#39;: \u0026#39;01\u0026#39;} # 非捕获分组 (?:) text = \u0026#34;abc123def\u0026#34; # 捕获分组会作为 groups 返回 match = re.search(r\u0026#39;(?:abc)(\\d+)\u0026#39;, text) print(match.groups()) # (\u0026#39;123\u0026#39;,) # 分组在替换中的应用 text = \u0026#34;2024-05-01\u0026#34; result = re.sub(r\u0026#39;(\\d{4})-(\\d{2})-(\\d{2})\u0026#39;, r\u0026#39;\\2/\\3/\\1\u0026#39;, text) print(result) # 05/01/2024 7. re.compile() 编译正则 # 编译正则表达式，提高匹配效率 pattern = re.compile(r\u0026#39;\\d{4}-\\d{2}-\\d{2}\u0026#39;) # 使用编译后的 pattern text = \u0026#34;今天是 2024-05-01，明天是 2024-05-02\u0026#34; print(pattern.findall(text)) # [\u0026#39;2024-05-01\u0026#39;, \u0026#39;2024-05-02\u0026#39;] print(pattern.search(text).group()) # \u0026#39;2024-05-01\u0026#39; # 编译时指定 flags pattern = re.compile(r\u0026#39;hello\u0026#39;, re.IGNORECASE) print(pattern.findall(\u0026#39;Hello HELLO hello\u0026#39;)) # [\u0026#39;Hello\u0026#39;, \u0026#39;HELLO\u0026#39;, \u0026#39;hello\u0026#39;] 8. re 模块的 flags # re.IGNORECASE / re.I - 忽略大小写 print(re.findall(r\u0026#39;hello\u0026#39;, \u0026#39;Hello HELLO\u0026#39;, re.I)) # re.MULTILINE / re.M - 多行模式 text = \u0026#34;line1\\nline2\\nline3\u0026#34; print(re.findall(r\u0026#39;^line\\d\u0026#39;, text, re.M)) # [\u0026#39;line1\u0026#39;, \u0026#39;line2\u0026#39;, \u0026#39;line3\u0026#39;] # re.DOTALL / re.S - 点号匹配所有字符（包括换行） text = \u0026#34;hello\\nworld\u0026#34; print(re.findall(r\u0026#39;hello.*world\u0026#39;, text)) # [] - 默认不匹配换行 print(re.findall(r\u0026#39;hello.*world\u0026#39;, text, re.S)) # [\u0026#39;hello\\nworld\u0026#39;] # re.VERBOSE / re.X - 详细模式（忽略空白和注释） pattern = re.compile(r\u0026#39;\u0026#39;\u0026#39; \\d{3} # 区号 - # 分隔符 \\d{4} # 号码 \u0026#39;\u0026#39;\u0026#39;, re.VERBOSE) # 可以组合使用 pattern = re.compile(r\u0026#39;hello\u0026#39;, re.I | re.M) 背诵版 核心速查 ┌─────────────────────────────────────────────────────────────┐ │ re 模块主要函数 │ ├─────────────────────────────────────────────────────────────┤ │ re.match() │ 从字符串开头匹配 │ │ re.search() │ 搜索第一个匹配 │ │ re.findall() │ 返回所有匹配的列表 │ │ re.finditer() │ 返回匹配的迭代器 │ │ re.sub() │ 替换匹配项 │ │ re.split() │ 按匹配分割 │ │ re.compile() │ 编译正则表达式 │ └─────────────────────────────────────────────────────────────┘字符类速查 模式 说明 等价 \\d 数字 [0-9] \\D 非数字 [^0-9] \\w 单词字符 [a-zA-Z0-9_] \\W 非单词字符 [^a-zA-Z0-9_] \\s 空白字符 [ \\t\\n\\r\\f\\v] \\S 非空白字符 [^ \\t\\n\\r\\f\\v] . 任意字符 - 量词速查 量词 说明 * 0 次或多次 + 1 次或多次 ? 0 次或 1 次 {n} 恰好 n 次 {n,} 至少 n 次 {n,m} n 到 m 次 考前记忆 面试重点 match vs search\nmatch 从字符串开头匹配 search 在字符串任意位置匹配 findall vs finditer\nfindall 返回列表，内存占用高 finditer 返回迭代器，内存高效 贪婪 vs 非贪婪\n贪婪：.* 尽可能多匹配 非贪婪：.*? 尽可能少匹配 字符类简写\n\\d 数字, \\w 单词, \\s 空白 分组编号\ngroup(0) 或 group() 是整个匹配 group(1) 是第一个分组，以此类推 记忆口诀 match 从头搜，search 任意找。 findall 找全部，finditer 迭代器。 量词控制次数，字符类定范围。 贪婪非贪婪，区别在 * 和 \u0026#43;。 测试题 选择题 1. re.match() 和 re.search() 的区别是什么？\n# A. 没有区别 # B. match 从开头匹配，search 搜索任意位置 # C. search 从开头匹配，match 搜索任意位置 # D. match 返回列表，search 返回单个 答案：B\n2. 以下哪个量词表示\u0026quot;0次或1次\u0026quot;？\n# A. * # B. + # C. ? # D. {1} 答案：C\n3. 哪个字符类匹配数字？\n# A. \\w # B. \\s # C. \\d # D. \\D 答案：C\n4. 以下代码的输出是什么？\nprint(re.findall(r\u0026#39;\\d+\u0026#39;, \u0026#39;a1b2c3\u0026#39;)) # A. [\u0026#39;1\u0026#39;, \u0026#39;2\u0026#39;, \u0026#39;3\u0026#39;] # B. \u0026#39;123\u0026#39; # C. [1, 2, 3] # D. [\u0026#39;a1\u0026#39;, \u0026#39;b2\u0026#39;, \u0026#39;c3\u0026#39;] 答案：A\n5. 非贪婪匹配需要添加什么字符？\n# A. * # B. + # C. ? # D. # 答案：C\n编程题 1. 验证邮箱格式：\nimport re def validate_email(email): \u0026#34;\u0026#34;\u0026#34;验证邮箱格式\u0026#34;\u0026#34;\u0026#34; pattern = r\u0026#39;^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$\u0026#39; return re.match(pattern, email) is not None # 测试 emails = [ \u0026#39;test@example.com\u0026#39;, \u0026#39;user.name@domain.org\u0026#39;, \u0026#39;invalid-email\u0026#39;, \u0026#39;@nodomain.com\u0026#39;, \u0026#39;missing@.com\u0026#39; ] for email in emails: result = \u0026#34;✓ 有效\u0026#34; if validate_email(email) else \u0026#34;✗ 无效\u0026#34; print(f\u0026#34;{email}: {result}\u0026#34;) 2. 提取 URL 信息：\nimport re def extract_urls(text): \u0026#34;\u0026#34;\u0026#34;提取 URL\u0026#34;\u0026#34;\u0026#34; pattern = r\u0026#39;https?://[a-zA-Z0-9.-]+(?:/[a-zA-Z0-9./_-]*)?\u0026#39; return re.findall(pattern, text) text = \u0026#34;\u0026#34;\u0026#34; 访问 https://www.example.com 获取更多信息。 也可以访问 http://blog.example.org 或 https://shop.example.co.uk/products?id=123 \u0026#34;\u0026#34;\u0026#34; urls = extract_urls(text) for url in urls: print(url) 3. 电话号码提取：\nimport re def extract_phones(text): \u0026#34;\u0026#34;\u0026#34;提取各种格式的电话号码\u0026#34;\u0026#34;\u0026#34; # 中国手机号（11位） phone_pattern = r\u0026#39;1[3-9]\\d{9}\u0026#39; # 固话（区号-号码） tel_pattern = r\u0026#39;\\d{3,4}-\\d{7,8}\u0026#39; phones = [] phones.extend(re.findall(phone_pattern, text)) phones.extend(re.findall(tel_pattern, text)) return phones text = \u0026#34;\u0026#34;\u0026#34; 联系电话：13812345678 座机：010-12345678 手机：13998765432 \u0026#34;\u0026#34;\u0026#34; print(extract_phones(text)) # [\u0026#39;13812345678\u0026#39;, \u0026#39;010-12345678\u0026#39;, \u0026#39;13998765432\u0026#39;] 4. 敏感信息脱敏：\nimport re def mask_sensitive(text): \u0026#34;\u0026#34;\u0026#34;脱敏处理\u0026#34;\u0026#34;\u0026#34; # 手机号脱敏 text = re.sub(r\u0026#39;(1[3-9]\\d{9})\u0026#39;, lambda m: m.group(1)[:3] + \u0026#39;****\u0026#39; + m.group(1)[7:], text) # 邮箱脱敏 text = re.sub(r\u0026#39;(\\w{2})\\w*(@)\u0026#39;, r\u0026#39;\\1***\\2\u0026#39;, text) return text text = \u0026#34;手机: 13812345678, 邮箱: john@example.com\u0026#34; print(mask_sensitive(text)) # 手机: 138****5678, 邮箱: jo***@example.com 问答题 Q1: 什么是正则表达式的贪婪匹配和非贪婪匹配？\n贪婪匹配：量词会尽可能多地匹配字符，如 .* 会匹配尽可能多的字符。\n非贪婪匹配：在量词后加 ?，如 .*? 会匹配尽可能少的字符。\ntext = \u0026#39;\u0026lt;div\u0026gt;content\u0026lt;/div\u0026gt;\u0026#39; # 贪婪 re.findall(r\u0026#39;\u0026lt;div\u0026gt;.*\u0026lt;/div\u0026gt;\u0026#39;, text) # [\u0026#39;\u0026lt;div\u0026gt;content\u0026lt;/div\u0026gt;\u0026#39;] # 非贪婪 re.findall(r\u0026#39;\u0026lt;div\u0026gt;.*?\u0026lt;/div\u0026gt;\u0026#39;, text) # [\u0026#39;\u0026lt;div\u0026gt;content\u0026lt;/div\u0026gt;\u0026#39;] Q2: re.findall() 和 re.finditer() 有什么区别？\n方法 返回值 内存使用 适用场景 findall() 列表 高（一次性返回所有结果） 小数据量 finditer() 迭代器 低（逐个返回结果） 大数据量或流式处理 Q3: 字符类 [abc] 和快捷方式 \\w 有什么区别？\n字符类 说明 [abc] 匹配 a、b 或 c 中的任意一个字符 \\w 匹配字母、数字、下划线 [a-zA-Z0-9_] re.findall(r\u0026#39;[abc]\u0026#39;, \u0026#39;abcd\u0026#39;) # [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] re.findall(r\u0026#39;\\w\u0026#39;, \u0026#39;abcd\u0026#39;) # [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;, \u0026#39;d\u0026#39;] 参考资料 Python 官方文档 - re 模块 正则表达式语法 正则表达式 HOWTO ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-39-regex-basics/","summary":"\u003ch1 id=\"day39---正则表达式基础\"\u003eDay39 - 正则表达式基础\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"1-正则表达式简介\"\u003e1. 正则表达式简介\u003c/h3\u003e\n\u003cp\u003e正则表达式是一种用于匹配字符串的模式表达式，在文本处理、数据提取、验证等场景中广泛应用。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e re\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 最简单的匹配\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello world\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(pattern, text):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;找到匹配！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 常用场景\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 1. 验证邮箱格式\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 2. 提取网页中的链接\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 3. 处理日志文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 4. 数据清洗和转换\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"2-re-模块主要函数\"\u003e2. re 模块主要函数\u003c/h3\u003e\n\u003ch4 id=\"21-rematch---从开头匹配\"\u003e2.1 \u003ccode\u003ere.match()\u003c/code\u003e - 从开头匹配\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e re\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# match() 从字符串开头匹配\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello world\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# \u0026lt;re.Match object\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup())  \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;hello\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003espan())   \u003cspan style=\"color:#75715e\"\u003e# (0, 5)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 如果开头不匹配，返回 None\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;world\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello world\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# None\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用分组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(\\w+), (\\w+)\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello, world\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e result:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(result\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;hello\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(result\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;world\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(result\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroups())  \u003cspan style=\"color:#75715e\"\u003e# (\u0026#39;hello\u0026#39;, \u0026#39;world\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"22-research---搜索匹配\"\u003e2.2 \u003ccode\u003ere.search()\u003c/code\u003e - 搜索匹配\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# search() 在字符串任意位置查找第一个匹配\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;world\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello world\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup())  \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;world\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003espan())   \u003cspan style=\"color:#75715e\"\u003e# (6, 11)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 搜索邮箱\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;联系邮箱: test@example.com 或 admin@test.org\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\w+@\\w+\\.\\w+\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup())  \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;test@example.com\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 找不到返回 None\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;notfound\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# None\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"23-refindall---查找所有匹配\"\u003e2.3 \u003ccode\u003ere.findall()\u003c/code\u003e - 查找所有匹配\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# findall() 返回所有匹配的列表\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;我的邮箱是 test@example.com，副邮箱是 backup@example.org\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 查找所有邮箱\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eemails \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\w+@\\w+\\.\\w+\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(emails)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;test@example.com\u0026#39;, \u0026#39;backup@example.org\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 查找所有数字\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enumbers \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\d+\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;我有 3 个苹果，5 个橙子，共 8 个水果\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(numbers)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;3\u0026#39;, \u0026#39;5\u0026#39;, \u0026#39;8\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用分组 - 返回分组内容的列表\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;红色: #FF0000, 绿色: #00FF00, 蓝色: #0000FF\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecolors \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;#([0-9A-Fa-f]\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{6}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(colors)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;FF0000\u0026#39;, \u0026#39;00FF00\u0026#39;, \u0026#39;0000FF\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"24-refinditer---迭代器版本\"\u003e2.4 \u003ccode\u003ere.finditer()\u003c/code\u003e - 迭代器版本\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# finditer() 返回迭代器，比 findall() 内存效率高\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;邮箱: a@test.com, b@test.com, c@test.com\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efinditer(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\w+@\\w+\\.\\w+\u0026#39;\u003c/span\u003e, text):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;位置 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ematch\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003espan()\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ematch\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup()\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"3-字符类character-classes\"\u003e3. 字符类（Character Classes）\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# [] - 匹配方括号内的任意一个字符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配元音字母\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003evowels \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[aeiouAEIOU]\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Hello World\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(vowels)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;e\u0026#39;, \u0026#39;o\u0026#39;, \u0026#39;o\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配数字或字母\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ealphanum \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[a-zA-Z0-9]\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Hello123!\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(alphanum)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;H\u0026#39;, \u0026#39;e\u0026#39;, \u0026#39;l\u0026#39;, \u0026#39;l\u0026#39;, \u0026#39;o\u0026#39;, \u0026#39;1\u0026#39;, \u0026#39;2\u0026#39;, \u0026#39;3\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# [^] - 否定，匹配不在方括号内的字符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enon_vowels \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[^aeiouAEIOU]\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Hello\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(non_vowels)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;H\u0026#39;, \u0026#39;l\u0026#39;, \u0026#39;l\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 常用简写\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \\d  = [0-9]        数字\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \\D  = [^0-9]       非数字\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \\w  = [a-zA-Z0-9_] 单词字符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \\W  = [^a-zA-Z0-9_] 非单词字符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \\s  = [ \\t\\n\\r\\f\\v] 空白字符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \\S  = [^ \\t\\n\\r\\f\\v] 非空白字符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# .   = 任意字符（除换行符）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;用户: ZhangSan, 年龄: 25, 电话: 138-0000-8888\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eages \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\d+\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(ages)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;25\u0026#39;, \u0026#39;138\u0026#39;, \u0026#39;0000\u0026#39;, \u0026#39;8888\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewords \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\w+\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(words)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;用户\u0026#39;, \u0026#39;ZhangSan\u0026#39;, \u0026#39;年龄\u0026#39;, \u0026#39;25\u0026#39;, \u0026#39;电话\u0026#39;, \u0026#39;138\u0026#39;, \u0026#39;0000\u0026#39;, \u0026#39;8888\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"4-量词quantifiers\"\u003e4. 量词（Quantifiers）\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# *    - 0 次或多次\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# +    - 1 次或多次\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ?    - 0 次或 1 次\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# {n}  - 恰好 n 次\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# {n,} - 至少 n 次\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# {n,m} - n 到 m 次\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# * 示例：匹配任意数量字符\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ab*c\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# ac, abc, abbc, abbbc, ...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ab*c\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ac abc abbc abbbc\u0026#39;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;ac\u0026#39;, \u0026#39;abc\u0026#39;, \u0026#39;abbc\u0026#39;, \u0026#39;abbbc\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# + 示例：至少一个\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ab+c\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# abc, abbc, abbbc, ... (不包括 ac)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ab+c\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ac abc abbc\u0026#39;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;abc\u0026#39;, \u0026#39;abbc\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ? 示例：可选\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;colou?r\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# color, colour\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;colou?r\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;color colour\u0026#39;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;color\u0026#39;, \u0026#39;colour\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# {n} 示例：精确次数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 4 位数字\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;2024年 12345月\u0026#39;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;2024\u0026#39;, \u0026#39;1234\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# {n,m} 示例：范围次数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\d{2,4}\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 2-4 位数字\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\d{2,4}\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;1 12 123 1234 12345\u0026#39;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;12\u0026#39;, \u0026#39;123\u0026#39;, \u0026#39;1234\u0026#39;, \u0026#39;1234\u0026#39;, \u0026#39;5\u0026#39;] - 注意贪婪匹配\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 贪婪 vs 非贪婪（最小匹配）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026lt;div\u0026gt;content\u0026lt;/div\u0026gt;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 贪婪：尽可能多匹配\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026lt;div\u0026gt;.*\u0026lt;/div\u0026gt;\u0026#39;\u003c/span\u003e, text))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;\u0026lt;div\u0026gt;content\u0026lt;/div\u0026gt;\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 非贪婪：尽可能少匹配\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026lt;div\u0026gt;.*?\u0026lt;/div\u0026gt;\u0026#39;\u003c/span\u003e, text))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;\u0026lt;div\u0026gt;content\u0026lt;/div\u0026gt;\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 非贪婪添加 ?\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026lt;div\u0026gt;div1\u0026lt;/div\u0026gt;\u0026lt;div\u0026gt;div2\u0026lt;/div\u0026gt;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026lt;div\u0026gt;.*?\u0026lt;/div\u0026gt;\u0026#39;\u003c/span\u003e, text))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;\u0026lt;div\u0026gt;div1\u0026lt;/div\u0026gt;\u0026#39;, \u0026#39;\u0026lt;div\u0026gt;div2\u0026lt;/div\u0026gt;\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"5-边界匹配\"\u003e5. 边界匹配\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ^  - 字符串开头\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# $  - 字符串结尾\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \\b - 单词边界\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \\B - 非单词边界\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配以数字开头的行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;123abc\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003ehello\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e456xyz\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elines \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;^\\d+\u0026#39;\u003c/span\u003e, text, re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eMULTILINE)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(lines)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;123\u0026#39;, \u0026#39;456\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配以.com结尾的域名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edomains \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\w+\\.com$\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;test.com\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003eexample.org\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003email.com\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(domains)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;test.com\u0026#39;, \u0026#39;mail.com\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \\b 边界示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a cat a the in cat\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配完整的单词 \u0026#39;cat\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecats \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\bcat\\b\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(cats)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;cat\u0026#39;, \u0026#39;cat\u0026#39;] - 两个独立的 cat\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 不使用边界\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecats_all \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;cat\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(cats_all)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;cat\u0026#39;, \u0026#39;cat\u0026#39;, \u0026#39;cat\u0026#39;] - 包括 a[cat] 中的 cat\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \\B 非边界示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;abc abc\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ab\\B\u0026#39;\u003c/span\u003e, text))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;ab\u0026#39;] - abc 中的 ab\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\Bab\\B\u0026#39;\u003c/span\u003e, text))  \u003cspan style=\"color:#75715e\"\u003e# [] - 开头和结尾的 ab 都不匹配\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"6-分组groups\"\u003e6. 分组（Groups）\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# () - 创建分组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 提取邮箱用户名和域名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;邮箱: john@example.com 和 jane@test.org\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ematches \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(\\w+)@(\\w+)\\.(\\w+)\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(matches)  \u003cspan style=\"color:#75715e\"\u003e# [(\u0026#39;john\u0026#39;, \u0026#39;example\u0026#39;, \u0026#39;com\u0026#39;), (\u0026#39;jane\u0026#39;, \u0026#39;test\u0026#39;, \u0026#39;org\u0026#39;)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 嵌套分组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;2024-05-01\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroups())  \u003cspan style=\"color:#75715e\"\u003e# (\u0026#39;2024\u0026#39;, \u0026#39;05\u0026#39;, \u0026#39;01\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;2024\u0026#39; 年\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;05\u0026#39; 月\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;01\u0026#39; 日\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 命名分组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?P\u0026lt;year\u0026gt;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(?P\u0026lt;month\u0026gt;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(?P\u0026lt;day\u0026gt;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(pattern, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;2024-05-01\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;year\u0026#39;\u003c/span\u003e))   \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;2024\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;month\u0026#39;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;05\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;day\u0026#39;\u003c/span\u003e))     \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;01\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroupdict())     \u003cspan style=\"color:#75715e\"\u003e# {\u0026#39;year\u0026#39;: \u0026#39;2024\u0026#39;, \u0026#39;month\u0026#39;: \u0026#39;05\u0026#39;, \u0026#39;day\u0026#39;: \u0026#39;01\u0026#39;}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 非捕获分组 (?:)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;abc123def\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 捕获分组会作为 groups 返回\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?:abc)(\\d+)\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroups())  \u003cspan style=\"color:#75715e\"\u003e# (\u0026#39;123\u0026#39;,)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 分组在替换中的应用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;2024-05-01\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\2/\\3/\\1\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# 05/01/2024\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"7-recompile-编译正则\"\u003e7. re.compile() 编译正则\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 编译正则表达式，提高匹配效率\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecompile(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e-\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e-\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用编译后的 pattern\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;今天是 2024-05-01，明天是 2024-05-02\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(pattern\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(text))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;2024-05-01\u0026#39;, \u0026#39;2024-05-02\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(pattern\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(text)\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup())  \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;2024-05-01\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 编译时指定 flags\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecompile(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello\u0026#39;\u003c/span\u003e, re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eIGNORECASE)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(pattern\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Hello HELLO hello\u0026#39;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;Hello\u0026#39;, \u0026#39;HELLO\u0026#39;, \u0026#39;hello\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"8-re-模块的-flags\"\u003e8. re 模块的 flags\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# re.IGNORECASE / re.I - 忽略大小写\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Hello HELLO\u0026#39;\u003c/span\u003e, re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eI))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# re.MULTILINE / re.M - 多行模式\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;line1\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003eline2\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003eline3\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;^line\\d\u0026#39;\u003c/span\u003e, text, re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eM))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;line1\u0026#39;, \u0026#39;line2\u0026#39;, \u0026#39;line3\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# re.DOTALL / re.S - 点号匹配所有字符（包括换行）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;hello\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003eworld\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello.*world\u0026#39;\u003c/span\u003e, text))    \u003cspan style=\"color:#75715e\"\u003e# [] - 默认不匹配换行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello.*world\u0026#39;\u003c/span\u003e, text, re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eS))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;hello\\nworld\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# re.VERBOSE / re.X - 详细模式（忽略空白和注释）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecompile(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{3}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e  # 区号\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    -      # 分隔符\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e  # 号码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\u003c/span\u003e, re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eVERBOSE)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 可以组合使用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecompile(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hello\u0026#39;\u003c/span\u003e, re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eI \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eM)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"背诵版\"\u003e背诵版\u003c/h2\u003e\n\u003ch3 id=\"核心速查\"\u003e核心速查\u003c/h3\u003e\n┌─────────────────────────────────────────────────────────────┐\n│                    re 模块主要函数                          │\n├─────────────────────────────────────────────────────────────┤\n│  re.match()    │ 从字符串开头匹配                          │\n│  re.search()   │ 搜索第一个匹配                           │\n│  re.findall()  │ 返回所有匹配的列表                        │\n│  re.finditer() │ 返回匹配的迭代器                          │\n│  re.sub()      │ 替换匹配项                               │\n│  re.split()    │ 按匹配分割                               │\n│  re.compile()  │ 编译正则表达式                           │\n└─────────────────────────────────────────────────────────────┘\u003ch3 id=\"字符类速查\"\u003e字符类速查\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e模式\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n          \u003cth\u003e等价\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e\\d\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e数字\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e[0-9]\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e\\D\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e非数字\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e[^0-9]\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e\\w\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e单词字符\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e[a-zA-Z0-9_]\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e\\W\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e非单词字符\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e[^a-zA-Z0-9_]\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e\\s\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e空白字符\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e[ \\t\\n\\r\\f\\v]\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e\\S\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e非空白字符\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e[^ \\t\\n\\r\\f\\v]\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e.\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e任意字符\u003c/td\u003e\n          \u003ctd\u003e-\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"量词速查\"\u003e量词速查\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e量词\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e*\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e0 次或多次\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e+\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e1 次或多次\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e?\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e0 次或 1 次\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e{n}\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e恰好 n 次\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e{n,}\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e至少 n 次\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e{n,m}\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003en 到 m 次\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch2 id=\"考前记忆\"\u003e考前记忆\u003c/h2\u003e\n\u003ch3 id=\"面试重点\"\u003e面试重点\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ccode\u003ematch\u003c/code\u003e vs \u003ccode\u003esearch\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e","tags":"python, regex, re, findall, search, match","title":"Day39 - 正则表达式基础"},{"columns":"python-course","content":"Day40 - 正则表达式高级与综合项目 详细讲解 1. 分组高级用法 1.1 捕获分组与非捕获分组 import re # 捕获分组 - 会保存到 groups() 中 text = \u0026#34;2024-05-01\u0026#34; match = re.search(r\u0026#39;(\\d{4})-(\\d{2})-(\\d{2})\u0026#39;, text) print(match.groups()) # (\u0026#39;2024\u0026#39;, \u0026#39;05\u0026#39;, \u0026#39;01\u0026#39;) # 非捕获分组 (?:...) - 不保存到 groups() match = re.search(r\u0026#39;(\\d{4})-(?:\\d{2})-(\\d{2})\u0026#39;, text) print(match.groups()) # (\u0026#39;2024\u0026#39;, \u0026#39;01\u0026#39;) # 使用场景：提高效率（不需要的分组不用保存） # 当分组多时，非捕获分组性能更好 1.2 命名分组 # (?P\u0026lt;name\u0026gt;pattern) - 命名分组 text = \u0026#34;John Doe \u0026lt;john@example.com\u0026gt;\u0026#34; match = re.search(r\u0026#39;(?P\u0026lt;name\u0026gt;\\w+) (?P\u0026lt;surname\u0026gt;\\w+) \u0026lt;(?P\u0026lt;email\u0026gt;\\w+@\\w+\\.\\w+)\u0026gt;\u0026#39;, text) if match: print(match.groupdict()) # {\u0026#39;name\u0026#39;: \u0026#39;John\u0026#39;, \u0026#39;surname\u0026#39;: \u0026#39;Doe\u0026#39;, \u0026#39;email\u0026#39;: \u0026#39;john@example.com\u0026#39;} # 按名称访问 print(match.group(\u0026#39;name\u0026#39;)) # \u0026#39;John\u0026#39; print(match.group(\u0026#39;email\u0026#39;)) # \u0026#39;john@example.com\u0026#39; # 命名分组在替换中也很方便 text = \u0026#34;2024-05-01\u0026#34; result = re.sub(r\u0026#39;(?P\u0026lt;year\u0026gt;\\d{4})-(?P\u0026lt;month\u0026gt;\\d{2})-(?P\u0026lt;day\u0026gt;\\d{2})\u0026#39;, r\u0026#39;\\g\u0026lt;month\u0026gt;/\\g\u0026lt;day\u0026gt;/\\g\u0026lt;year\u0026gt;\u0026#39;, text) print(result) # 05/01/2024 1.3 反向引用 # \\1, \\2 等 - 引用前面的分组 # 匹配重复的单词 text = \u0026#34;the the cat cat dog\u0026#34; pattern = r\u0026#39;(\\w+) \\1\u0026#39; # \\1 引用第一个分组 print(re.findall(pattern, text)) # [\u0026#39;the\u0026#39;, \u0026#39;cat\u0026#39;] # 匹配 HTML 标签 text = \u0026#34;\u0026lt;div\u0026gt;content\u0026lt;/div\u0026gt; \u0026lt;span\u0026gt;text\u0026lt;/span\u0026gt;\u0026#34; pattern = r\u0026#39;\u0026lt;(\\w+)\u0026gt;.*?\u0026lt;/\\1\u0026gt;\u0026#39; # \\1 引用前面的标签名 print(re.findall(pattern, text)) # [\u0026#39;div\u0026#39;, \u0026#39;span\u0026#39;] # 匹配引号 pattern = r\u0026#39;([\u0026#34;\\\u0026#39;])(.*?)\\1\u0026#39; # \\1 引用开头的引号 print(re.findall(pattern, \u0026#34;\u0026#39;hello\u0026#39; and \\\u0026#34;world\\\u0026#34;\u0026#34;)) # [\u0026#34;\u0026#39;\u0026#34;, \u0026#39;hello\u0026#39;, \u0026#39;\u0026#34;\u0026#39;, \u0026#39;world\u0026#39;] 1.4 条件匹配 # (?(id)yes_pattern|no_pattern) - 如果 id 存在则匹配 yes_pattern，否则匹配 no_pattern # 匹配带引号或不带引号的单词 text = \u0026#39;\u0026#34;hello\u0026#34; world \u0026#34;python\u0026#34;\u0026#39; # 如果有引号，则匹配引号内的内容；否则匹配单词 pattern = r\u0026#39;([\u0026#34;\\\u0026#39;])?(?(1)(.*?)\\1|(\\w+))\u0026#39; matches = re.findall(pattern, text) print(matches) # [(\u0026#39;\u0026#34;\u0026#39;, \u0026#39;hello\u0026#39;, \u0026#39;\u0026#39;), (\u0026#39;\u0026#39;, \u0026#39;\u0026#39;, \u0026#39;world\u0026#39;), (\u0026#39;\u0026#34;\u0026#39;, \u0026#39;python\u0026#39;, \u0026#39;\u0026#39;)] 2. re.sub() 高级用法 2.1 基本替换 import re # 基本替换 text = \u0026#34;Hello World\u0026#34; result = re.sub(r\u0026#39;World\u0026#39;, \u0026#39;Python\u0026#39;, text) print(result) # Hello Python # 使用分组引用 text = \u0026#34;2024-05-01\u0026#34; result = re.sub(r\u0026#39;(\\d{4})-(\\d{2})-(\\d{2})\u0026#39;, r\u0026#39;\\2/\\3/\\1\u0026#39;, text) print(result) # 05/01/2024 # 命名分组引用 result = re.sub(r\u0026#39;(?P\u0026lt;y\u0026gt;\\d{4})-(?P\u0026lt;m\u0026gt;\\d{2})-(?P\u0026lt;d\u0026gt;\\d{2})\u0026#39;, r\u0026#39;\\g\u0026lt;d\u0026gt;-\\g\u0026lt;m\u0026gt;-\\g\u0026lt;y\u0026gt;\u0026#39;, text) print(result) # 01-05-2024 2.2 替换函数 # 传入函数作为替换参数 def expand_date(match): \u0026#34;\u0026#34;\u0026#34;日期转换函数\u0026#34;\u0026#34;\u0026#34; year, month, day = match.groups() months = { \u0026#39;01\u0026#39;: \u0026#39;January\u0026#39;, \u0026#39;02\u0026#39;: \u0026#39;February\u0026#39;, \u0026#39;03\u0026#39;: \u0026#39;March\u0026#39;, \u0026#39;04\u0026#39;: \u0026#39;April\u0026#39;, \u0026#39;05\u0026#39;: \u0026#39;May\u0026#39;, \u0026#39;06\u0026#39;: \u0026#39;June\u0026#39;, \u0026#39;07\u0026#39;: \u0026#39;July\u0026#39;, \u0026#39;08\u0026#39;: \u0026#39;August\u0026#39;, \u0026#39;09\u0026#39;: \u0026#39;September\u0026#39;, \u0026#39;10\u0026#39;: \u0026#39;October\u0026#39;, \u0026#39;11\u0026#39;: \u0026#39;November\u0026#39;, \u0026#39;12\u0026#39;: \u0026#39;December\u0026#39; } return f\u0026#34;{months[month]} {day}, {year}\u0026#34; text = \u0026#34;Date: 2024-05-01\u0026#34; result = re.sub(r\u0026#39;(\\d{4})-(\\d{2})-(\\d{2})\u0026#39;, expand_date, text) print(result) # Date: May 01, 2024 # 数字格式化 def format_number(match): num = int(match.group()) return f\u0026#34;{num:,}\u0026#34; # 添加千分位 text = \u0026#34;金额: 1234567\u0026#34; result = re.sub(r\u0026#39;\\d+\u0026#39;, format_number, text) print(result) # 金额: 1,234,567 2.3 re.subn() - 返回替换次数 # subn() 返回 (新字符串, 替换次数) text = \u0026#34;aaa bbb aaa ccc aaa\u0026#34; result, count = re.subn(r\u0026#39;aaa\u0026#39;, \u0026#39;XXX\u0026#39;, text) print(f\u0026#34;替换后: {result}, 替换次数: {count}\u0026#34;) # 替换后: XXX bbb XXX ccc XXX, 替换次数: 3 3. re.split() 高级用法 import re # 基本分割 text = \u0026#34;apple,banana,cherry\u0026#34; parts = re.split(r\u0026#39;,\u0026#39;, text) print(parts) # [\u0026#39;apple\u0026#39;, \u0026#39;banana\u0026#39;, \u0026#39;cherry\u0026#39;] # 使用分组分割 - 分组会保留在结果中 text = \u0026#34;apple1banana2cherry\u0026#34; parts = re.split(r\u0026#39;(\\d)\u0026#39;, text) print(parts) # [\u0026#39;apple\u0026#39;, \u0026#39;1\u0026#39;, \u0026#39;banana\u0026#39;, \u0026#39;2\u0026#39;, \u0026#39;cherry\u0026#39;] # 限制分割次数 text = \u0026#34;a:b:c:d:e\u0026#34; parts = re.split(r\u0026#39;:\u0026#39;, text, maxsplit=2) print(parts) # [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c:d:e\u0026#39;] # 按多种分隔符分割 text = \u0026#34;apple,bana;na|cherry\u0026#34; parts = re.split(r\u0026#39;[,;|]\u0026#39;, text) print(parts) # [\u0026#39;apple\u0026#39;, \u0026#39;bana\u0026#39;, \u0026#39;na\u0026#39;, \u0026#39;cherry\u0026#39;] 4. 零宽断言（Lookaround） 4.1 正向先行断言 (?=...) # 匹配后面跟着特定内容的前缀 text = \u0026#34;Windows10 Windows11 Windows12\u0026#34; # 匹配前面是 Windows，后面是数字的 Windows result = re.findall(r\u0026#39;Windows(?=\\d)\u0026#39;, text) print(result) # [\u0026#39;Windows\u0026#39;, \u0026#39;Windows\u0026#39;, \u0026#39;Windows\u0026#39;] # 更实用的例子：获取价格（数字前的货币符号） text = \u0026#34;价格: $100, €50, ¥200\u0026#34; result = re.findall(r\u0026#39;[$€¥]\\d+\u0026#39;, text) print(result) # [\u0026#39;$100\u0026#39;, \u0026#39;€50\u0026#39;, \u0026#39;¥200\u0026#39;] # 匹配后面是 .com 的域名部分 text = \u0026#34;example.com test.org hello.com\u0026#34; result = re.findall(r\u0026#39;\\w+(?=\\.com)\u0026#39;, text) print(result) # [\u0026#39;example\u0026#39;, \u0026#39;hello\u0026#39;] 4.2 负向先行断言 (?!...) # 匹配后面不跟着特定内容的前缀 text = \u0026#34;Windows10 WindowsMac Windows11\u0026#34; # 匹配后面不是数字的 Windows result = re.findall(r\u0026#39;Windows(?!\\d)\u0026#39;, text) print(result) # [\u0026#39;WindowsMac\u0026#39;] # 排除特定结尾 text = [\u0026#34;file.txt\u0026#34;, \u0026#34;file.log\u0026#34;, \u0026#34;file.txt.bak\u0026#34;, \u0026#34;data.csv\u0026#34;] txt_files = [f for f in text if re.match(r\u0026#39;.*\\.txt(?!\\.)\u0026#39;, f)] print(txt_files) # [\u0026#39;file.txt\u0026#39;] 4.3 正向后行断言 (?\u0026lt;=...) # 匹配前面跟着特定内容的后缀 text = \u0026#34;价格: 100元, 200元, 300美元\u0026#34; # 匹配\u0026#34;元\u0026#34;前面的数字 result = re.findall(r\u0026#39;(?\u0026lt;=[元])\\d+\u0026#39;, text) print(result) # [\u0026#39;100\u0026#39;, \u0026#39;200\u0026#39;] # 提取 HTML 中的文本内容 html = \u0026#34;\u0026lt;div\u0026gt;Hello\u0026lt;/div\u0026gt;\u0026lt;span\u0026gt;World\u0026lt;/span\u0026gt;\u0026#34; result = re.findall(r\u0026#39;(?\u0026lt;=\u0026lt;[a-z]+\u0026gt;)[^\u0026lt;]+\u0026#39;, html) print(result) # [\u0026#39;Hello\u0026#39;, \u0026#39;World\u0026#39;] # 提取域名后的路径 text = \u0026#34;https://example.com/path1 http://test.org/path2\u0026#34; result = re.findall(r\u0026#39;(?\u0026lt;=//[^/]+/).+\u0026#39;, text) print(result) # [\u0026#39;/path1\u0026#39;, \u0026#39;/path2\u0026#39;] 4.4 负向后行断言 (?\u0026lt;!...) # 匹配前面不跟着特定内容的后缀 text = \u0026#34;100元 200美元 300元 400日元\u0026#34; # 匹配前面不是\u0026#34;元\u0026#34;的数字 result = re.findall(r\u0026#39;(?\u0026lt;![元])\\d+\u0026#39;, text) print(result) # [\u0026#39;200\u0026#39;, \u0026#39;400\u0026#39;] # 更实用的例子：提取不是来自某个前缀的内容 text = \u0026#34;abc123 abc456 xyz789\u0026#34; result = re.findall(r\u0026#39;(?\u0026lt;!abc)\\d+\u0026#39;, text) print(result) # [\u0026#39;3456\u0026#39;, \u0026#39;789\u0026#39;] - abc123 中的 1 被排除 5. 综合项目实践 5.1 日志分析器 import re from collections import Counter from datetime import datetime class LogAnalyzer: \u0026#34;\u0026#34;\u0026#34;日志分析器\u0026#34;\u0026#34;\u0026#34; # 日志格式正则（示例：Apache 访问日志） LOG_PATTERN = re.compile( r\u0026#39;(?P\u0026lt;ip\u0026gt;[\\d.]+) \u0026#39; # IP 地址 r\u0026#39;- - \u0026#39; r\u0026#39;\\[(?P\u0026lt;timestamp\u0026gt;[^\\]]+)\\] \u0026#39; # 时间戳 r\u0026#39;\u0026#34;(?P\u0026lt;method\u0026gt;\\w+) (?P\u0026lt;path\u0026gt;[^\\s]+) [^\u0026#34;]+\u0026#34; \u0026#39; # 请求方法和路径 r\u0026#39;(?P\u0026lt;status\u0026gt;\\d{3}) \u0026#39; # 状态码 r\u0026#39;(?P\u0026lt;size\u0026gt;\\d+)\u0026#39; ) # 错误日志正则 ERROR_PATTERN = re.compile( r\u0026#39;\\[(?P\u0026lt;timestamp\u0026gt;[^\\]]+)\\] \u0026#39; r\u0026#39;\\[(?P\u0026lt;level\u0026gt;\\w+)\\] \u0026#39; r\u0026#39;(?P\u0026lt;message\u0026gt;.+)\u0026#39; ) @classmethod def parse_access_log(cls, log_text): \u0026#34;\u0026#34;\u0026#34;解析访问日志\u0026#34;\u0026#34;\u0026#34; results = [] for line in log_text.strip().split(\u0026#39;\\n\u0026#39;): match = cls.LOG_PATTERN.search(line) if match: results.append(match.groupdict()) return results @classmethod def analyze_traffic(cls, log_text): \u0026#34;\u0026#34;\u0026#34;流量分析\u0026#34;\u0026#34;\u0026#34; entries = cls.parse_access_log(log_text) # 统计各状态码数量 status_counts = Counter(e[\u0026#39;status\u0026#39;] for e in entries) # 统计各路径访问量 path_counts = Counter(e[\u0026#39;path\u0026#39;] for e in entries) # 统计各 IP 访问量 ip_counts = Counter(e[\u0026#39;ip\u0026#39;] for e in entries) # 计算总流量 total_bytes = sum(int(e[\u0026#39;size\u0026#39;]) for e in entries) return { \u0026#39;total_requests\u0026#39;: len(entries), \u0026#39;status_codes\u0026#39;: dict(status_counts), \u0026#39;top_paths\u0026#39;: path_counts.most_common(10), \u0026#39;top_ips\u0026#39;: ip_counts.most_common(10), \u0026#39;total_bytes\u0026#39;: total_bytes } @classmethod def extract_errors(cls, log_text): \u0026#34;\u0026#34;\u0026#34;提取错误信息\u0026#34;\u0026#34;\u0026#34; errors = [] for line in log_text.strip().split(\u0026#39;\\n\u0026#39;): match = cls.ERROR_PATTERN.search(line) if match: errors.append(match.groupdict()) return errors # 使用示例 sample_log = \u0026#39;\u0026#39;\u0026#39; 127.0.0.1 - - [01/May/2024:10:00:00 +0000] \u0026#34;GET /index.html HTTP/1.1\u0026#34; 200 1234 127.0.0.1 - - [01/May/2024:10:00:01 +0000] \u0026#34;GET /style.css HTTP/1.1\u0026#34; 200 5678 127.0.0.2 - - [01/May/2024:10:00:02 +0000] \u0026#34;GET /api/users HTTP/1.1\u0026#34; 404 0 192.168.1.1 - - [01/May/2024:10:00:03 +0000] \u0026#34;POST /login HTTP/1.1\u0026#34; 200 89 192.168.1.1 - - [01/May/2024:10:00:04 +0000] \u0026#34;POST /login HTTP/1.1\u0026#34; 401 23 \u0026#39;\u0026#39;\u0026#39; analyzer = LogAnalyzer() result = analyzer.analyze_traffic(sample_log) print(f\u0026#34;总请求数: {result[\u0026#39;total_requests\u0026#39;]}\u0026#34;) print(f\u0026#34;状态码统计: {result[\u0026#39;status_codes\u0026#39;]}\u0026#34;) print(f\u0026#34;Top 路径: {result[\u0026#39;top_paths\u0026#39;]}\u0026#34;) print(f\u0026#34;Top IPs: {result[\u0026#39;top_ips\u0026#39;]}\u0026#34;) 5.2 文本数据清洗工具 import re class TextCleaner: \u0026#34;\u0026#34;\u0026#34;文本数据清洗工具\u0026#34;\u0026#34;\u0026#34; @staticmethod def clean_html(text): \u0026#34;\u0026#34;\u0026#34;移除 HTML 标签\u0026#34;\u0026#34;\u0026#34; # 移除 script 和 style 内容 text = re.sub(r\u0026#39;\u0026lt;script[^\u0026gt;]*\u0026gt;.*?\u0026lt;/script\u0026gt;\u0026#39;, \u0026#39;\u0026#39;, text, flags=re.DOTALL | re.IGNORECASE) text = re.sub(r\u0026#39;\u0026lt;style[^\u0026gt;]*\u0026gt;.*?\u0026lt;/style\u0026gt;\u0026#39;, \u0026#39;\u0026#39;, text, flags=re.DOTALL | re.IGNORECASE) # 移除所有 HTML 标签 text = re.sub(r\u0026#39;\u0026lt;[^\u0026gt;]+\u0026gt;\u0026#39;, \u0026#39;\u0026#39;, text) # 解码 HTML 实体 text = TextCleaner._decode_html_entities(text) return text.strip() @staticmethod def _decode_html_entities(text): \u0026#34;\u0026#34;\u0026#34;解码 HTML 实体\u0026#34;\u0026#34;\u0026#34; entities = { \u0026#39;\u0026amp;nbsp;\u0026#39;: \u0026#39; \u0026#39;, \u0026#39;\u0026amp;amp;\u0026#39;: \u0026#39;\u0026amp;\u0026#39;, \u0026#39;\u0026amp;lt;\u0026#39;: \u0026#39;\u0026lt;\u0026#39;, \u0026#39;\u0026amp;gt;\u0026#39;: \u0026#39;\u0026gt;\u0026#39;, \u0026#39;\u0026amp;quot;\u0026#39;: \u0026#39;\u0026#34;\u0026#39;, \u0026#39;\u0026amp;#39;\u0026#39;: \u0026#34;\u0026#39;\u0026#34;, \u0026#39;\u0026amp;apos;\u0026#39;: \u0026#34;\u0026#39;\u0026#34; } for entity, char in entities.items(): text = text.replace(entity, char) # 处理数字形式的实体 text = re.sub(r\u0026#39;\u0026amp;#(\\d+);\u0026#39;, lambda m: chr(int(m.group(1))), text) return text @staticmethod def normalize_whitespace(text): \u0026#34;\u0026#34;\u0026#34;规范化空白字符\u0026#34;\u0026#34;\u0026#34; # 将所有连续空白替换为单个空格 text = re.sub(r\u0026#39;\\s+\u0026#39;, \u0026#39; \u0026#39;, text) # 移除首尾空白 return text.strip() @staticmethod def remove_special_chars(text, keep_pattern=\u0026#39;\u0026#39;): \u0026#34;\u0026#34;\u0026#34;移除特殊字符\u0026#34;\u0026#34;\u0026#34; if keep_pattern: pattern = f\u0026#39;[^a-zA-Z0-9{re.escape(keep_pattern)}]\u0026#39; else: pattern = r\u0026#39;[^a-zA-Z0-9\\u4e00-\\u9fff]\u0026#39; # 保留中文 return re.sub(pattern, \u0026#39;\u0026#39;, text) @staticmethod def extract_phones(text): \u0026#34;\u0026#34;\u0026#34;提取电话号码\u0026#34;\u0026#34;\u0026#34; patterns = [ r\u0026#39;1[3-9]\\d{9}\u0026#39;, # 手机号 r\u0026#39;\\d{3,4}-\\d{7,8}\u0026#39;, # 固话 r\u0026#39;\\+\\d{1,3}-\\d{3,4}-\\d{7,8}\u0026#39; # 国际电话 ] phones = [] for pattern in patterns: phones.extend(re.findall(pattern, text)) return list(set(phones)) # 去重 @staticmethod def extract_emails(text): \u0026#34;\u0026#34;\u0026#34;提取邮箱地址\u0026#34;\u0026#34;\u0026#34; pattern = r\u0026#39;[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\u0026#39; return re.findall(pattern, text) @staticmethod def mask_sensitive(text, mask_type=\u0026#39;phone\u0026#39;): \u0026#34;\u0026#34;\u0026#34;脱敏处理\u0026#34;\u0026#34;\u0026#34; if mask_type == \u0026#39;phone\u0026#39;: return re.sub(r\u0026#39;(1[3-9]\\d{9})\u0026#39;, lambda m: m.group(1)[:3] + \u0026#39;****\u0026#39; + m.group(1)[7:], text) elif mask_type == \u0026#39;email\u0026#39;: return re.sub(r\u0026#39;([a-zA-Z0-9]{2})[a-zA-Z0-9]*@\u0026#39;, r\u0026#39;\\1***@\u0026#39;, text) return text # 使用示例 html_text = \u0026#39;\u0026#39;\u0026#39; \u0026lt;div class=\u0026#34;content\u0026#34;\u0026gt; \u0026lt;script\u0026gt;alert(\u0026#34;bad\u0026#34;);\u0026lt;/script\u0026gt; \u0026lt;p\u0026gt;联系我们: 010-12345678 或 13812345678\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;邮箱: contact@example.com\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;地址: 北京市海淀区中关村大街1号\u0026lt;/p\u0026gt; \u0026lt;/div\u0026gt; \u0026#39;\u0026#39;\u0026#39; cleaner = TextCleaner() text = cleaner.clean_html(html_text) print(f\u0026#34;清洗后: {text}\u0026#34;) print(f\u0026#34;提取电话: {cleaner.extract_phones(text)}\u0026#34;) print(f\u0026#34;提取邮箱: {cleaner.extract_emails(text)}\u0026#34;) print(f\u0026#34;脱敏电话: {cleaner.mask_sensitive(text, \u0026#39;phone\u0026#39;)}\u0026#34;) 5.3 URL 解析器 import re from urllib.parse import urlparse, parse_qs class URLParser: \u0026#34;\u0026#34;\u0026#34;URL 解析器\u0026#34;\u0026#34;\u0026#34; # 更完整的 URL 正则 URL_PATTERN = re.compile( r\u0026#39;^(?P\u0026lt;scheme\u0026gt;https?)://\u0026#39; # 协议 r\u0026#39;(?P\u0026lt;domain\u0026gt;[^/:]+)\u0026#39; # 域名 r\u0026#39;(?::(?P\u0026lt;port\u0026gt;\\d+))?\u0026#39; # 端口（可选） r\u0026#39;(?P\u0026lt;path\u0026gt;/[^?#]*)?\u0026#39; # 路径 r\u0026#39;(?:\\?(?P\u0026lt;query\u0026gt;[^#]+))?\u0026#39; # 查询字符串 r\u0026#39;(?:#(?P\u0026lt;fragment\u0026gt;.+))?\u0026#39; # 锚点 ) @classmethod def parse(cls, url): \u0026#34;\u0026#34;\u0026#34;解析 URL\u0026#34;\u0026#34;\u0026#34; # 尝试用正则解析 match = cls.URL_PATTERN.match(url) if match: return match.groupdict() # 回退到 urllib parsed = urlparse(url) return { \u0026#39;scheme\u0026#39;: parsed.scheme, \u0026#39;domain\u0026#39;: parsed.netloc, \u0026#39;port\u0026#39;: parsed.port, \u0026#39;path\u0026#39;: parsed.path, \u0026#39;query\u0026#39;: parsed.query, \u0026#39;fragment\u0026#39;: parsed.fragment } @classmethod def extract_params(cls, url): \u0026#34;\u0026#34;\u0026#34;提取 URL 参数\u0026#34;\u0026#34;\u0026#34; parsed = urlparse(url) params = parse_qs(parsed.query) # 转换为简单字典（值列表转单值） return {k: v[0] if len(v) == 1 else v for k, v in params.items()} @classmethod def build_url(cls, scheme=\u0026#39;https\u0026#39;, domain=\u0026#39;\u0026#39;, path=\u0026#39;/\u0026#39;, params=None, fragment=\u0026#39;\u0026#39;): \u0026#34;\u0026#34;\u0026#34;构建 URL\u0026#34;\u0026#34;\u0026#34; url = f\u0026#34;{scheme}://{domain}{path}\u0026#34; if params: query = \u0026#39;\u0026amp;\u0026#39;.join(f\u0026#34;{k}={v}\u0026#34; for k, v in params.items()) url += f\u0026#34;?{query}\u0026#34; if fragment: url += f\u0026#34;#{fragment}\u0026#34; return url @classmethod def extract_domain_info(cls, domain): \u0026#34;\u0026#34;\u0026#34;提取域名信息\u0026#34;\u0026#34;\u0026#34; # 提取子域名 parts = domain.split(\u0026#39;.\u0026#39;) if len(parts) \u0026gt;= 3: subdomain = parts[0] main_domain = \u0026#39;.\u0026#39;.join(parts[1:]) else: subdomain = None main_domain = domain # 提取顶级域 tld = parts[-1] if parts else \u0026#39;\u0026#39; return { \u0026#39;original\u0026#39;: domain, \u0026#39;subdomain\u0026#39;: subdomain, \u0026#39;domain\u0026#39;: main_domain, \u0026#39;tld\u0026#39;: tld } # 使用示例 urls = [ \u0026#39;https://example.com:8080/path/to/page?id=123\u0026amp;name=test#section\u0026#39;, \u0026#39;http://sub.domain.co.uk/api/v1/users?page=1\u0026#39;, \u0026#39;https://www.test.org\u0026#39; ] parser = URLParser() for url in urls: print(f\u0026#34;\\n解析: {url}\u0026#34;) info = parser.parse(url) print(f\u0026#34; 域名: {info[\u0026#39;domain\u0026#39;]}\u0026#34;) print(f\u0026#34; 路径: {info.get(\u0026#39;path\u0026#39;, \u0026#39;/\u0026#39;)}\u0026#34;) print(f\u0026#34; 参数: {parser.extract_params(url)}\u0026#34;) if info.get(\u0026#39;domain\u0026#39;): domain_info = parser.extract_domain_info(info[\u0026#39;domain\u0026#39;]) print(f\u0026#34; 域名信息: {domain_info}\u0026#34;) 5.4 数据验证器 import re class Validator: \u0026#34;\u0026#34;\u0026#34;常用数据验证器\u0026#34;\u0026#34;\u0026#34; @staticmethod def is_valid_email(email): \u0026#34;\u0026#34;\u0026#34;验证邮箱\u0026#34;\u0026#34;\u0026#34; pattern = r\u0026#39;^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$\u0026#39; return re.match(pattern, email) is not None @staticmethod def is_valid_phone(phone, region=\u0026#39;CN\u0026#39;): \u0026#34;\u0026#34;\u0026#34;验证手机号\u0026#34;\u0026#34;\u0026#34; if region == \u0026#39;CN\u0026#39;: # 中国手机号（11位，以1开头，第2位3-9） pattern = r\u0026#39;^1[3-9]\\d{9}$\u0026#39; elif region == \u0026#39;US\u0026#39;: # 美国电话（10位） pattern = r\u0026#39;^\\d{10}$\u0026#39; else: pattern = r\u0026#39;^\\+?\\d{6,15}$\u0026#39; return re.match(pattern, phone) is not None @staticmethod def is_valid_url(url): \u0026#34;\u0026#34;\u0026#34;验证 URL\u0026#34;\u0026#34;\u0026#34; pattern = r\u0026#39;^https?://[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}(/.*)?$\u0026#39; return re.match(pattern, url) is not None @staticmethod def is_valid_ip(ip): \u0026#34;\u0026#34;\u0026#34;验证 IPv4 地址\u0026#34;\u0026#34;\u0026#34; pattern = r\u0026#39;^(\\d{1,3}\\.){3}\\d{1,3}$\u0026#39; if not re.match(pattern, ip): return False # 检查每段是否在 0-255 return all(0 \u0026lt;= int(octet) \u0026lt;= 255 for octet in ip.split(\u0026#39;.\u0026#39;)) @staticmethod def is_valid_date(date_str, format=\u0026#39;%Y-%m-%d\u0026#39;): \u0026#34;\u0026#34;\u0026#34;验证日期格式\u0026#34;\u0026#34;\u0026#34; from datetime import datetime try: datetime.strptime(date_str, format) return True except ValueError: return False @staticmethod def is_strong_password(password): \u0026#34;\u0026#34;\u0026#34;验证密码强度\u0026#34;\u0026#34;\u0026#34; if len(password) \u0026lt; 8: return False, \u0026#34;密码长度至少8位\u0026#34; has_upper = bool(re.search(r\u0026#39;[A-Z]\u0026#39;, password)) has_lower = bool(re.search(r\u0026#39;[a-z]\u0026#39;, password)) has_digit = bool(re.search(r\u0026#39;\\d\u0026#39;, password)) has_special = bool(re.search(r\u0026#39;[!@#$%^\u0026amp;*(),.?\u0026#34;:{}|\u0026lt;\u0026gt;]\u0026#39;, password)) if not has_upper: return False, \u0026#34;需要包含大写字母\u0026#34; if not has_lower: return False, \u0026#34;需要包含小写字母\u0026#34; if not has_digit: return False, \u0026#34;需要包含数字\u0026#34; if not has_special: return False, \u0026#34;需要包含特殊字符\u0026#34; return True, \u0026#34;密码强度合格\u0026#34; # 使用示例 validator = Validator() test_cases = [ (\u0026#39;email\u0026#39;, \u0026#39;test@example.com\u0026#39;), (\u0026#39;phone\u0026#39;, \u0026#39;13812345678\u0026#39;), (\u0026#39;url\u0026#39;, \u0026#39;https://www.example.com\u0026#39;), (\u0026#39;ip\u0026#39;, \u0026#39;192.168.1.1\u0026#39;), (\u0026#39;date\u0026#39;, \u0026#39;2024-05-01\u0026#39;), ] for type_name, value in test_cases: method = getattr(validator, f\u0026#39;is_valid_{type_name}\u0026#39;) result = method(value) status = \u0026#34;✓\u0026#34; if result else \u0026#34;✗\u0026#34; print(f\u0026#34;{status} {type_name}: {value}\u0026#34;) # 密码强度验证 password = \u0026#34;Test@1234\u0026#34; valid, msg = validator.is_strong_password(password) print(f\u0026#34;\\n密码 \u0026#39;{password}\u0026#39;: {msg}\u0026#34;) 背诵版 高级正则速查 ┌─────────────────────────────────────────────────────────────┐ │ 零宽断言（Lookaround） │ ├─────────────────────────────────────────────────────────────┤ │ (?=...) 正向先行 │ 后面跟着... │ │ (?!...) 负向先行 │ 后面不跟... │ │ (?\u0026lt;=...) 正向后行 │ 前面是... │ │ (?\u0026lt;!...) 负向后行 │ 前面不是... │ ├─────────────────────────────────────────────────────────────┤ │ (?P\u0026lt;name\u0026gt;...) 命名分组 │ │ (?:...) 非捕获分组 │ │ \\1, \\2 反向引用 │ └─────────────────────────────────────────────────────────────┘re.sub 替换函数 # 基本替换 re.sub(pattern, replacement, string) # 替换函数 def replace_func(match): return ... # 返回替换文本 re.sub(pattern, replace_func, string) # 返回替换次数 re.subn(pattern, replacement, string) # 返回 (结果, 次数) 考前记忆 面试重点 零宽断言的区别\n先行：看后面（(?=) 正向，(?!) 负向） 后行：看前面（(?\u0026lt;=) 正向，(?\u0026lt;!) 负向） 不消耗字符，只做条件判断 分组类型\n捕获分组 (...)：保存到 groups 非捕获分组 (?:...)：不保存 命名分组 (?P\u0026lt;name\u0026gt;...)：命名访问 反向引用 \\1\n引用前面分组的内容 用于匹配重复结构 sub 替换函数\n接受 match 对象参数 返回替换字符串 lookaround 用途\n精确提取（前后有特定上下文的内容） 条件匹配 记忆口诀 零宽断言不占位， 先行看后后看前。 分组捕获要记牢， 反向引用\\1到。 sub函数替换强， 日志分析它最棒。 测试题 选择题 1. (?=...) 是什么类型的断言？\n# A. 正向后行断言 # B. 负向后行断言 # C. 正向先行断言 # D. 负向先行断言 答案：C\n2. re.sub() 的第二个参数可以是什么类型？\n# A. 只能是字符串 # B. 只能是函数 # C. 字符串或函数 # D. 只能是列表 答案：C\n3. 命名分组的语法是什么？\n# A. (name:...) # B. \u0026lt;name:...\u0026gt; # C. (?P\u0026lt;name\u0026gt;...) # D. (:name...) 答案：C\n4. (?\u0026lt;=...) 是什么类型的断言？\n# A. 正向先行 # B. 负向先行 # C. 正向后行 # D. 负向后行 答案：C\n5. 反向引用 \\1 的作用是什么？\n# A. 引用第一个分组 # B. 引用整个匹配 # C. 引用字符串开头 # D. 转义数字 答案：A\n编程题 1. 实现一个模板引擎：\nimport re class TemplateEngine: \u0026#34;\u0026#34;\u0026#34;简单的模板引擎\u0026#34;\u0026#34;\u0026#34; def __init__(self, template): self.template = template def render(self, context): \u0026#34;\u0026#34;\u0026#34;渲染模板\u0026#34;\u0026#34;\u0026#34; result = self.template # 替换 {{ variable }} result = re.sub(r\u0026#39;\\{\\{(\\w+)\\}\\}\u0026#39;, lambda m: str(context.get(m.group(1), \u0026#39;\u0026#39;)), result) # 替换 {{ var|filter }} def apply_filter(m): var, filter_name = m.group(1), m.group(2) value = context.get(var, \u0026#39;\u0026#39;) return self._apply_filter(value, filter_name) result = re.sub(r\u0026#39;\\{\\{(\\w+)\\|(\\w+)\\}\\}\u0026#39;, apply_filter, result) # 替换 {% if condition %}...{% endif %} result = self._process_conditionals(result, context) return result @staticmethod def _apply_filter(value, filter_name): \u0026#34;\u0026#34;\u0026#34;应用过滤器\u0026#34;\u0026#34;\u0026#34; filters = { \u0026#39;upper\u0026#39;: lambda v: v.upper(), \u0026#39;lower\u0026#39;: lambda v: v.lower(), \u0026#39;capitalize\u0026#39;: lambda v: v.capitalize(), \u0026#39;trim\u0026#39;: lambda v: v.strip(), \u0026#39;length\u0026#39;: lambda v: len(str(v)) } return filters.get(filter_name, lambda v: v)(value) def _process_conditionals(self, template, context): \u0026#34;\u0026#34;\u0026#34;处理条件语句\u0026#34;\u0026#34;\u0026#34; # 匹配 {% if var %}...{% endif %} pattern = r\u0026#39;\\{%\\s*if\\s+(\\w+)\\s*%\\}(.*?)\\{%\\s*endif\\s*%\\}\u0026#39; def replace_if(match): var = match.group(1) content = match.group(2) if context.get(var): return content return \u0026#39;\u0026#39; return re.sub(pattern, replace_if, template, flags=re.DOTALL) # 使用 template = \u0026#34;\u0026#34;\u0026#34; \u0026lt;h1\u0026gt;{{ title|upper }}\u0026lt;/h1\u0026gt; \u0026lt;p\u0026gt;欢迎, {{ name|capitalize }}\u0026lt;/p\u0026gt; {% if show_footer %} \u0026lt;footer\u0026gt;版权信息\u0026lt;/footer\u0026gt; {% endif %} \u0026#34;\u0026#34;\u0026#34; engine = TemplateEngine(template) context = { \u0026#39;title\u0026#39;: \u0026#39;Welcome\u0026#39;, \u0026#39;name\u0026#39;: \u0026#39;john doe\u0026#39;, \u0026#39;show_footer\u0026#39;: True } print(engine.render(context)) 2. 实现一个爬虫数据提取器：\nimport re class DataExtractor: \u0026#34;\u0026#34;\u0026#34;网页数据提取器\u0026#34;\u0026#34;\u0026#34; @staticmethod def extract_articles(html): \u0026#34;\u0026#34;\u0026#34;提取文章列表\u0026#34;\u0026#34;\u0026#34; # 提取文章标题和链接 pattern = r\u0026#39;\u0026lt;article[^\u0026gt;]*\u0026gt;.*?\u0026lt;a[^\u0026gt;]*href=[\u0026#34;\\\u0026#39;]([^\u0026#34;\\\u0026#39;]+)[\u0026#34;\\\u0026#39;][^\u0026gt;]*\u0026gt;([^\u0026lt;]+)\u0026lt;/a\u0026gt;.*?\u0026lt;/article\u0026gt;\u0026#39; articles = [] for match in re.finditer(pattern, html, re.DOTALL): articles.append({ \u0026#39;url\u0026#39;: match.group(1), \u0026#39;title\u0026#39;: match.group(2).strip() }) return articles @staticmethod def extract_images(html): \u0026#34;\u0026#34;\u0026#34;提取图片\u0026#34;\u0026#34;\u0026#34; pattern = r\u0026#39;\u0026lt;img[^\u0026gt;]+src=[\u0026#34;\\\u0026#39;]([^\u0026#34;\\\u0026#39;]+)[\u0026#34;\\\u0026#39;][^\u0026gt;]*(?:alt=[\u0026#34;\\\u0026#39;]([^\u0026#34;\\\u0026#39;]*)[\u0026#34;\\\u0026#39;])?[^\u0026gt;]*\u0026gt;\u0026#39; images = [] for match in re.finditer(pattern, html): images.append({ \u0026#39;src\u0026#39;: match.group(1), \u0026#39;alt\u0026#39;: match.group(2) if match.lastindex \u0026gt;= 2 else \u0026#39;\u0026#39; }) return images @staticmethod def extract_metadata(html): \u0026#34;\u0026#34;\u0026#34;提取元数据\u0026#34;\u0026#34;\u0026#34; meta = {} # title title_match = re.search(r\u0026#39;\u0026lt;title\u0026gt;([^\u0026lt;]+)\u0026lt;/title\u0026gt;\u0026#39;, html) if title_match: meta[\u0026#39;title\u0026#39;] = title_match.group(1) # meta 标签 meta_pattern = r\u0026#39;\u0026lt;meta[^\u0026gt;]+(?:name|property)=[\u0026#34;\\\u0026#39;]([^\u0026#34;\\\u0026#39;]+)[\u0026#34;\\\u0026#39;][^\u0026gt;]+content=[\u0026#34;\\\u0026#39;]([^\u0026#34;\\\u0026#39;]+)[\u0026#34;\\\u0026#39;]\u0026#39; for match in re.finditer(meta_pattern, html, re.IGNORECASE): meta[match.group(1)] = match.group(2) # keywords kw_match = re.search(r\u0026#39;\u0026lt;meta[^\u0026gt;]+name=[\u0026#34;\\\u0026#39;]keywords[\u0026#34;\\\u0026#39;][^\u0026gt;]+content=[\u0026#34;\\\u0026#39;]([^\u0026#34;\\\u0026#39;]+)[\u0026#34;\\\u0026#39;]\u0026#39;, html, re.IGNORECASE) if kw_match: meta[\u0026#39;keywords\u0026#39;] = [k.strip() for k in kw_match.group(1).split(\u0026#39;,\u0026#39;)] return meta # 使用 sample_html = \u0026#39;\u0026#39;\u0026#39; \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;title\u0026gt;示例页面\u0026lt;/title\u0026gt; \u0026lt;meta name=\u0026#34;description\u0026#34; content=\u0026#34;这是一个示例页面\u0026#34;\u0026gt; \u0026lt;meta name=\u0026#34;keywords\u0026#34; content=\u0026#34;Python, 正则, 爬虫\u0026#34;\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;article\u0026gt; \u0026lt;a href=\u0026#34;/article/1\u0026#34;\u0026gt;第一篇文章\u0026lt;/a\u0026gt; \u0026lt;/article\u0026gt; \u0026lt;article\u0026gt; \u0026lt;a href=\u0026#34;/article/2\u0026#34;\u0026gt;第二篇文章\u0026lt;/a\u0026gt; \u0026lt;/article\u0026gt; \u0026lt;img src=\u0026#34;/images/1.jpg\u0026#34; alt=\u0026#34;图片1\u0026#34;\u0026gt; \u0026lt;img src=\u0026#34;/images/2.jpg\u0026#34; alt=\u0026#34;图片2\u0026#34;\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; \u0026#39;\u0026#39;\u0026#39; extractor = DataExtractor() print(\u0026#34;文章:\u0026#34;, extractor.extract_articles(sample_html)) print(\u0026#34;图片:\u0026#34;, extractor.extract_images(sample_html)) print(\u0026#34;元数据:\u0026#34;, extractor.extract_metadata(sample_html)) 问答题 Q1: 什么是零宽断言？请举例说明正向和负向的区别。\n零宽断言是一种不消耗字符的断言，只用于判断位置前后的条件是否满足。\n# 正向先行 (?=...) - 后面必须是... text = \u0026#34;100元 200美元 300日元\u0026#34; re.findall(r\u0026#39;\\d+(?=元)\u0026#39;, text) # [\u0026#39;100\u0026#39;] - 只匹配后面是\u0026#34;元\u0026#34;的数字 # 负向先行 (?!...) - 后面必须不是... re.findall(r\u0026#39;\\d+(?!元)\u0026#39;, text) # [\u0026#39;200\u0026#39;, \u0026#39;300\u0026#39;] - 后面不是\u0026#34;元\u0026#34;的数字 Q2: 捕获分组和非捕获分组有什么区别？\n类型 语法 保存到 groups 性能 捕获分组 (...) 是 稍慢 非捕获分组 (?:...) 否 稍快 选择依据：\n需要使用分组结果 → 捕获分组 不需要分组结果 → 非捕获分组（性能更好） Q3: re.sub() 的替换函数参数是什么？有什么用？\n替换函数接收一个 match 对象参数，返回替换字符串。\ndef replace_func(match): # match.group(0) - 整个匹配 # match.group(1) - 第一个分组 # match.groupdict() - 命名分组 return replacement re.sub(pattern, replace_func, text) 常用于：\n需要根据匹配内容动态计算替换值 复杂的数据转换 格式化输出 参考资料 Python 官方文档 - re 模块 正则表达式完整教程 Python re 模块高级用法 ","description":"","permalink":"https://blog.uuworld.cn/python-course/python-day-40-regex-advanced-project/","summary":"\u003ch1 id=\"day40---正则表达式高级与综合项目\"\u003eDay40 - 正则表达式高级与综合项目\u003c/h1\u003e\n\u003ch2 id=\"详细讲解\"\u003e详细讲解\u003c/h2\u003e\n\u003ch3 id=\"1-分组高级用法\"\u003e1. 分组高级用法\u003c/h3\u003e\n\u003ch4 id=\"11-捕获分组与非捕获分组\"\u003e1.1 捕获分组与非捕获分组\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e re\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 捕获分组 - 会保存到 groups() 中\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;2024-05-01\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroups())  \u003cspan style=\"color:#75715e\"\u003e# (\u0026#39;2024\u0026#39;, \u0026#39;05\u0026#39;, \u0026#39;01\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 非捕获分组 (?:...) - 不保存到 groups()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(?:\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroups())  \u003cspan style=\"color:#75715e\"\u003e# (\u0026#39;2024\u0026#39;, \u0026#39;01\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用场景：提高效率（不需要的分组不用保存）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 当分组多时，非捕获分组性能更好\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"12-命名分组\"\u003e1.2 命名分组\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# (?P\u0026lt;name\u0026gt;pattern) - 命名分组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;John Doe \u0026lt;john@example.com\u0026gt;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?P\u0026lt;name\u0026gt;\\w+) (?P\u0026lt;surname\u0026gt;\\w+) \u0026lt;(?P\u0026lt;email\u0026gt;\\w+@\\w+\\.\\w+)\u0026gt;\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroupdict())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# {\u0026#39;name\u0026#39;: \u0026#39;John\u0026#39;, \u0026#39;surname\u0026#39;: \u0026#39;Doe\u0026#39;, \u0026#39;email\u0026#39;: \u0026#39;john@example.com\u0026#39;}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 按名称访问\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;name\u0026#39;\u003c/span\u003e))   \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;John\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;email\u0026#39;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# \u0026#39;john@example.com\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 命名分组在替换中也很方便\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;2024-05-01\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?P\u0026lt;year\u0026gt;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(?P\u0026lt;month\u0026gt;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(?P\u0026lt;day\u0026gt;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                 \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\g\u0026lt;month\u0026gt;/\\g\u0026lt;day\u0026gt;/\\g\u0026lt;year\u0026gt;\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# 05/01/2024\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"13-反向引用\"\u003e1.3 反向引用\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \\1, \\2 等 - 引用前面的分组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配重复的单词\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;the the cat cat dog\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(\\w+) \\1\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# \\1 引用第一个分组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(pattern, text))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;the\u0026#39;, \u0026#39;cat\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配 HTML 标签\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026lt;div\u0026gt;content\u0026lt;/div\u0026gt; \u0026lt;span\u0026gt;text\u0026lt;/span\u0026gt;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026lt;(\\w+)\u0026gt;.*?\u0026lt;/\\1\u0026gt;\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# \\1 引用前面的标签名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(pattern, text))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;div\u0026#39;, \u0026#39;span\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配引号\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;([\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e])(.*?)\\1\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# \\1 引用开头的引号\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(pattern, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#39;hello\u0026#39; and \u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003eworld\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e))  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#34;\u0026#39;\u0026#34;, \u0026#39;hello\u0026#39;, \u0026#39;\u0026#34;\u0026#39;, \u0026#39;world\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"14-条件匹配\"\u003e1.4 条件匹配\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# (?(id)yes_pattern|no_pattern) - 如果 id 存在则匹配 yes_pattern，否则匹配 no_pattern\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配带引号或不带引号的单词\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#34;hello\u0026#34; world \u0026#34;python\u0026#34;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 如果有引号，则匹配引号内的内容；否则匹配单词\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;([\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e])?(?(1)(.*?)\\1|(\\w+))\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ematches \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(pattern, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(matches)  \u003cspan style=\"color:#75715e\"\u003e# [(\u0026#39;\u0026#34;\u0026#39;, \u0026#39;hello\u0026#39;, \u0026#39;\u0026#39;), (\u0026#39;\u0026#39;, \u0026#39;\u0026#39;, \u0026#39;world\u0026#39;), (\u0026#39;\u0026#34;\u0026#39;, \u0026#39;python\u0026#39;, \u0026#39;\u0026#39;)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"2-resub-高级用法\"\u003e2. \u003ccode\u003ere.sub()\u003c/code\u003e 高级用法\u003c/h3\u003e\n\u003ch4 id=\"21-基本替换\"\u003e2.1 基本替换\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e re\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 基本替换\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Hello World\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;World\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Python\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# Hello Python\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用分组引用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;2024-05-01\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\2/\\3/\\1\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# 05/01/2024\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 命名分组引用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?P\u0026lt;y\u0026gt;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(?P\u0026lt;m\u0026gt;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(?P\u0026lt;d\u0026gt;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                 \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\g\u0026lt;d\u0026gt;-\\g\u0026lt;m\u0026gt;-\\g\u0026lt;y\u0026gt;\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# 01-05-2024\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"22-替换函数\"\u003e2.2 替换函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 传入函数作为替换参数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eexpand_date\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;日期转换函数\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    year, month, day \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroups()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    months \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;01\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;January\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;02\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;February\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;03\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;March\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;04\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;April\u0026#39;\u003c/span\u003e,   \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;05\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;May\u0026#39;\u003c/span\u003e,      \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;06\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;June\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;07\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;July\u0026#39;\u003c/span\u003e,    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;08\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;August\u0026#39;\u003c/span\u003e,   \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;09\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;September\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;10\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;October\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;11\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;November\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;12\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;December\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003emonths[month]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eday\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e, \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eyear\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Date: 2024-05-01\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{4}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)-(\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#39;\u003c/span\u003e, expand_date, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# Date: May 01, 2024\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 数字格式化\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eformat_number\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    num \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e int(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003enum\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 添加千分位\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;金额: 1234567\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\d+\u0026#39;\u003c/span\u003e, format_number, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# 金额: 1,234,567\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"23-resubn---返回替换次数\"\u003e2.3 \u003ccode\u003ere.subn()\u003c/code\u003e - 返回替换次数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# subn() 返回 (新字符串, 替换次数)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;aaa bbb aaa ccc aaa\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult, count \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esubn(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;aaa\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;XXX\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;替换后: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresult\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e, 替换次数: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecount\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 替换后: XXX bbb XXX ccc XXX, 替换次数: 3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"3-resplit-高级用法\"\u003e3. \u003ccode\u003ere.split()\u003c/code\u003e 高级用法\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e re\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 基本分割\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;apple,banana,cherry\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eparts \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;,\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(parts)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;apple\u0026#39;, \u0026#39;banana\u0026#39;, \u0026#39;cherry\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用分组分割 - 分组会保留在结果中\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;apple1banana2cherry\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eparts \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(\\d)\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(parts)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;apple\u0026#39;, \u0026#39;1\u0026#39;, \u0026#39;banana\u0026#39;, \u0026#39;2\u0026#39;, \u0026#39;cherry\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 限制分割次数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a:b:c:d:e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eparts \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;:\u0026#39;\u003c/span\u003e, text, maxsplit\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(parts)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c:d:e\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 按多种分隔符分割\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;apple,bana;na|cherry\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eparts \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[,;|]\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(parts)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;apple\u0026#39;, \u0026#39;bana\u0026#39;, \u0026#39;na\u0026#39;, \u0026#39;cherry\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"4-零宽断言lookaround\"\u003e4. 零宽断言（Lookaround）\u003c/h3\u003e\n\u003ch4 id=\"41-正向先行断言-\"\u003e4.1 正向先行断言 \u003ccode\u003e(?=...)\u003c/code\u003e\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配后面跟着特定内容的前缀\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Windows10 Windows11 Windows12\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配前面是 Windows，后面是数字的 Windows\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Windows(?=\\d)\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;Windows\u0026#39;, \u0026#39;Windows\u0026#39;, \u0026#39;Windows\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 更实用的例子：获取价格（数字前的货币符号）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;价格: $100, €50, ¥200\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[$€¥]\\d+\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;$100\u0026#39;, \u0026#39;€50\u0026#39;, \u0026#39;¥200\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配后面是 .com 的域名部分\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;example.com test.org hello.com\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\w+(?=\\.com)\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;example\u0026#39;, \u0026#39;hello\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"42-负向先行断言-\"\u003e4.2 负向先行断言 \u003ccode\u003e(?!...)\u003c/code\u003e\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配后面不跟着特定内容的前缀\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Windows10 WindowsMac Windows11\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配后面不是数字的 Windows\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Windows(?!\\d)\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;WindowsMac\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 排除特定结尾\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;file.txt\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;file.log\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;file.txt.bak\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;data.csv\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etxt_files \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [f \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e f \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e text \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;.*\\.txt(?!\\.)\u0026#39;\u003c/span\u003e, f)]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(txt_files)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;file.txt\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"43-正向后行断言-\"\u003e4.3 正向后行断言 \u003ccode\u003e(?\u0026lt;=...)\u003c/code\u003e\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配前面跟着特定内容的后缀\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;价格: 100元, 200元, 300美元\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配\u0026#34;元\u0026#34;前面的数字\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?\u0026lt;=[元])\\d+\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;100\u0026#39;, \u0026#39;200\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 提取 HTML 中的文本内容\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehtml \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026lt;div\u0026gt;Hello\u0026lt;/div\u0026gt;\u0026lt;span\u0026gt;World\u0026lt;/span\u0026gt;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?\u0026lt;=\u0026lt;[a-z]+\u0026gt;)[^\u0026lt;]+\u0026#39;\u003c/span\u003e, html)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;Hello\u0026#39;, \u0026#39;World\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 提取域名后的路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://example.com/path1 http://test.org/path2\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?\u0026lt;=//[^/]+/).+\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;/path1\u0026#39;, \u0026#39;/path2\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"44-负向后行断言-\"\u003e4.4 负向后行断言 \u003ccode\u003e(?\u0026lt;!...)\u003c/code\u003e\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配前面不跟着特定内容的后缀\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;100元 200美元 300元 400日元\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 匹配前面不是\u0026#34;元\u0026#34;的数字\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?\u0026lt;![元])\\d+\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;200\u0026#39;, \u0026#39;400\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 更实用的例子：提取不是来自某个前缀的内容\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;abc123 abc456 xyz789\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?\u0026lt;!abc)\\d+\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(result)  \u003cspan style=\"color:#75715e\"\u003e# [\u0026#39;3456\u0026#39;, \u0026#39;789\u0026#39;] - abc123 中的 1 被排除\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"5-综合项目实践\"\u003e5. 综合项目实践\u003c/h3\u003e\n\u003ch4 id=\"51-日志分析器\"\u003e5.1 日志分析器\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e re\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e collections \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Counter\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e datetime \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e datetime\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eLogAnalyzer\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;日志分析器\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 日志格式正则（示例：Apache 访问日志）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    LOG_PATTERN \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecompile(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?P\u0026lt;ip\u0026gt;[\\d.]+) \u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# IP 地址\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;- - \u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\[(?P\u0026lt;timestamp\u0026gt;[^\\]]+)\\] \u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 时间戳\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#34;(?P\u0026lt;method\u0026gt;\\w+) (?P\u0026lt;path\u0026gt;[^\\s]+) [^\u0026#34;]+\u0026#34; \u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 请求方法和路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?P\u0026lt;status\u0026gt;\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{3}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e) \u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 状态码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?P\u0026lt;size\u0026gt;\\d+)\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 错误日志正则\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ERROR_PATTERN \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecompile(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\[(?P\u0026lt;timestamp\u0026gt;[^\\]]+)\\] \u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\[(?P\u0026lt;level\u0026gt;\\w+)\\] \u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?P\u0026lt;message\u0026gt;.+)\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@classmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eparse_access_log\u003c/span\u003e(cls, log_text):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;解析访问日志\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        results \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e line \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e log_text\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estrip()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e cls\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eLOG_PATTERN\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(line)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                results\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroupdict())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e results\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@classmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eanalyze_traffic\u003c/span\u003e(cls, log_text):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;流量分析\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        entries \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e cls\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eparse_access_log(log_text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 统计各状态码数量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        status_counts \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Counter(e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;status\u0026#39;\u003c/span\u003e] \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e e \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e entries)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 统计各路径访问量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        path_counts \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Counter(e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;path\u0026#39;\u003c/span\u003e] \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e e \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e entries)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 统计各 IP 访问量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ip_counts \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Counter(e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ip\u0026#39;\u003c/span\u003e] \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e e \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e entries)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 计算总流量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        total_bytes \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e sum(int(e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;size\u0026#39;\u003c/span\u003e]) \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e e \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e entries)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;total_requests\u0026#39;\u003c/span\u003e: len(entries),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;status_codes\u0026#39;\u003c/span\u003e: dict(status_counts),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;top_paths\u0026#39;\u003c/span\u003e: path_counts\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emost_common(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;top_ips\u0026#39;\u003c/span\u003e: ip_counts\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emost_common(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;total_bytes\u0026#39;\u003c/span\u003e: total_bytes\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@classmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eextract_errors\u003c/span\u003e(cls, log_text):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;提取错误信息\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        errors \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e line \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e log_text\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estrip()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e cls\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eERROR_PATTERN\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(line)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                errors\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroupdict())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e errors\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esample_log \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e127.0.0.1 - - [01/May/2024:10:00:00 +0000] \u0026#34;GET /index.html HTTP/1.1\u0026#34; 200 1234\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e127.0.0.1 - - [01/May/2024:10:00:01 +0000] \u0026#34;GET /style.css HTTP/1.1\u0026#34; 200 5678\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e127.0.0.2 - - [01/May/2024:10:00:02 +0000] \u0026#34;GET /api/users HTTP/1.1\u0026#34; 404 0\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e192.168.1.1 - - [01/May/2024:10:00:03 +0000] \u0026#34;POST /login HTTP/1.1\u0026#34; 200 89\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e192.168.1.1 - - [01/May/2024:10:00:04 +0000] \u0026#34;POST /login HTTP/1.1\u0026#34; 401 23\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eanalyzer \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e LogAnalyzer()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e analyzer\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eanalyze_traffic(sample_log)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;总请求数: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresult[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;total_requests\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;状态码统计: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresult[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;status_codes\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Top 路径: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresult[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;top_paths\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Top IPs: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresult[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;top_ips\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"52-文本数据清洗工具\"\u003e5.2 文本数据清洗工具\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e re\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eTextCleaner\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;文本数据清洗工具\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclean_html\u003c/span\u003e(text):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;移除 HTML 标签\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 移除 script 和 style 内容\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        text \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026lt;script[^\u0026gt;]*\u0026gt;.*?\u0026lt;/script\u0026gt;\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e, text, flags\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003ere\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eDOTALL \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eIGNORECASE)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        text \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026lt;style[^\u0026gt;]*\u0026gt;.*?\u0026lt;/style\u0026gt;\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e, text, flags\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003ere\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eDOTALL \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eIGNORECASE)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 移除所有 HTML 标签\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        text \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026lt;[^\u0026gt;]+\u0026gt;\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 解码 HTML 实体\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        text \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e TextCleaner\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e_decode_html_entities(text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e text\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estrip()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e_decode_html_entities\u003c/span\u003e(text):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;解码 HTML 实体\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        entities \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026amp;nbsp;\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39; \u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026amp;amp;\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026amp;\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026amp;lt;\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026lt;\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026amp;gt;\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026gt;\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026amp;quot;\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#34;\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026amp;#39;\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#39;\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026amp;apos;\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#39;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e entity, char \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e entities\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eitems():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            text \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e text\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ereplace(entity, char)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 处理数字形式的实体\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        text \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026amp;#(\\d+);\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003elambda\u003c/span\u003e m: chr(int(m\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e))), text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e text\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003enormalize_whitespace\u003c/span\u003e(text):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;规范化空白字符\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 将所有连续空白替换为单个空格\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        text \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\s+\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39; \u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 移除首尾空白\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e text\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estrip()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eremove_special_chars\u003c/span\u003e(text, keep_pattern\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;移除特殊字符\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e keep_pattern:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            pattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[^a-zA-Z0-9\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ere\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eescape(keep_pattern)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e]\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            pattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[^a-zA-Z0-9\\u4e00-\\u9fff]\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 保留中文\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(pattern, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eextract_phones\u003c/span\u003e(text):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;提取电话号码\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        patterns \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;1[3-9]\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{9}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e,           \u003cspan style=\"color:#75715e\"\u003e# 手机号\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\d{3,4}-\\d{7,8}\u0026#39;\u003c/span\u003e,       \u003cspan style=\"color:#75715e\"\u003e# 固话\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\+\\d{1,3}-\\d{3,4}-\\d{7,8}\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 国际电话\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        phones \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e pattern \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e patterns:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            phones\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eextend(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(pattern, text))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e list(set(phones))  \u003cspan style=\"color:#75715e\"\u003e# 去重\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eextract_emails\u003c/span\u003e(text):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;提取邮箱地址\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        pattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efindall(pattern, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emask_sensitive\u003c/span\u003e(text, mask_type\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;phone\u0026#39;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;脱敏处理\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e mask_type \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;phone\u0026#39;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(1[3-9]\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{9}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#39;\u003c/span\u003e, \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                         \u003cspan style=\"color:#66d9ef\"\u003elambda\u003c/span\u003e m: m\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)[:\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;****\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e m\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroup(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)[\u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e:], text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelif\u003c/span\u003e mask_type \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;email\u0026#39;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;([a-zA-Z0-9]\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{2}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)[a-zA-Z0-9]*@\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                         \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\1***@\u0026#39;\u003c/span\u003e, text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e text\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehtml_text \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026lt;div class=\u0026#34;content\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026lt;script\u0026gt;alert(\u0026#34;bad\u0026#34;);\u0026lt;/script\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026lt;p\u0026gt;联系我们: 010-12345678 或 13812345678\u0026lt;/p\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026lt;p\u0026gt;邮箱: contact@example.com\u0026lt;/p\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026lt;p\u0026gt;地址: 北京市海淀区中关村大街1号\u0026lt;/p\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecleaner \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e TextCleaner()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etext \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e cleaner\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eclean_html(html_text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;清洗后: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etext\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;提取电话: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecleaner\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eextract_phones(text)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;提取邮箱: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecleaner\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eextract_emails(text)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;脱敏电话: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecleaner\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emask_sensitive(text, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;phone\u0026#39;\u003c/span\u003e)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"53-url-解析器\"\u003e5.3 URL 解析器\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e re\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e urllib.parse \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e urlparse, parse_qs\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eURLParser\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;URL 解析器\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 更完整的 URL 正则\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    URL_PATTERN \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecompile(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;^(?P\u0026lt;scheme\u0026gt;https?)://\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 协议\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?P\u0026lt;domain\u0026gt;[^/:]+)\u0026#39;\u003c/span\u003e       \u003cspan style=\"color:#75715e\"\u003e# 域名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?::(?P\u0026lt;port\u0026gt;\\d+))?\u0026#39;\u003c/span\u003e      \u003cspan style=\"color:#75715e\"\u003e# 端口（可选）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?P\u0026lt;path\u0026gt;/[^?#]*)?\u0026#39;\u003c/span\u003e       \u003cspan style=\"color:#75715e\"\u003e# 路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?:\\?(?P\u0026lt;query\u0026gt;[^#]+))?\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 查询字符串\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;(?:#(?P\u0026lt;fragment\u0026gt;.+))?\u0026#39;\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# 锚点\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@classmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eparse\u003c/span\u003e(cls, url):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;解析 URL\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 尝试用正则解析\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e cls\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eURL_PATTERN\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e(url)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egroupdict()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 回退到 urllib\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        parsed \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e urlparse(url)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;scheme\u0026#39;\u003c/span\u003e: parsed\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003escheme,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;domain\u0026#39;\u003c/span\u003e: parsed\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003enetloc,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;port\u0026#39;\u003c/span\u003e: parsed\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eport,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;path\u0026#39;\u003c/span\u003e: parsed\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;query\u0026#39;\u003c/span\u003e: parsed\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003equery,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;fragment\u0026#39;\u003c/span\u003e: parsed\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efragment\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@classmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eextract_params\u003c/span\u003e(cls, url):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;提取 URL 参数\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        parsed \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e urlparse(url)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        params \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e parse_qs(parsed\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003equery)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 转换为简单字典（值列表转单值）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e {k: v[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e] \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e len(v) \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e v \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e k, v \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e params\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eitems()}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@classmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ebuild_url\u003c/span\u003e(cls, scheme\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;https\u0026#39;\u003c/span\u003e, domain\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e, path\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/\u0026#39;\u003c/span\u003e, params\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e, fragment\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;构建 URL\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        url \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003escheme\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e://\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edomain\u003cspan style=\"color:#e6db74\"\u003e}{\u003c/span\u003epath\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e params:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            query \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026amp;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ejoin(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ek\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ev\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e k, v \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e params\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eitems())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            url \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;?\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003equery\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e fragment:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            url \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;#\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003efragment\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e url\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@classmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eextract_domain_info\u003c/span\u003e(cls, domain):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;提取域名信息\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 提取子域名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        parts \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e domain\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;.\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e len(parts) \u003cspan style=\"color:#f92672\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            subdomain \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e parts[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            main_domain \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;.\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ejoin(parts[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e:])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            subdomain \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            main_domain \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e domain\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 提取顶级域\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        tld \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e parts[\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e] \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e parts \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;original\u0026#39;\u003c/span\u003e: domain,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;subdomain\u0026#39;\u003c/span\u003e: subdomain,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;domain\u0026#39;\u003c/span\u003e: main_domain,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;tld\u0026#39;\u003c/span\u003e: tld\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eurls \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;https://example.com:8080/path/to/page?id=123\u0026amp;name=test#section\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;http://sub.domain.co.uk/api/v1/users?page=1\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;https://www.test.org\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eparser \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e URLParser()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e url \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e urls:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e解析: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eurl\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    info \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e parser\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eparse(url)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  域名: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003einfo[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;domain\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  路径: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003einfo\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;path\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/\u0026#39;\u003c/span\u003e)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  参数: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eparser\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eextract_params(url)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e info\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;domain\u0026#39;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        domain_info \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e parser\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eextract_domain_info(info[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;domain\u0026#39;\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;  域名信息: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edomain_info\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"54-数据验证器\"\u003e5.4 数据验证器\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e re\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValidator\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;常用数据验证器\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eis_valid_email\u003c/span\u003e(email):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;验证邮箱\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        pattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e(pattern, email) \u003cspan style=\"color:#f92672\"\u003eis\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eis_valid_phone\u003c/span\u003e(phone, region\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;CN\u0026#39;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;验证手机号\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e region \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;CN\u0026#39;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e# 中国手机号（11位，以1开头，第2位3-9）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            pattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;^1[3-9]\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{9}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e$\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelif\u003c/span\u003e region \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;US\u0026#39;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e# 美国电话（10位）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            pattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;^\\d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{10}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e$\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            pattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;^\\+?\\d{6,15}$\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e(pattern, phone) \u003cspan style=\"color:#f92672\"\u003eis\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eis_valid_url\u003c/span\u003e(url):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;验证 URL\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        pattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;^https?://[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}(/.*)?$\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e(pattern, url) \u003cspan style=\"color:#f92672\"\u003eis\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eis_valid_ip\u003c/span\u003e(ip):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;验证 IPv4 地址\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        pattern \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;^(\\d{1,3}\\.)\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{3}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\\d{1,3}$\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e(pattern, ip):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 检查每段是否在 0-255\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e all(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026lt;=\u003c/span\u003e int(octet) \u003cspan style=\"color:#f92672\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e octet \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e ip\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;.\u0026#39;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eis_valid_date\u003c/span\u003e(date_str, format\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;%Y-%m-\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e%d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;验证日期格式\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e datetime \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e datetime\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            datetime\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estrptime(date_str, format)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003e@staticmethod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eis_strong_password\u003c/span\u003e(password):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;验证密码强度\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e len(password) \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;密码长度至少8位\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        has_upper \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e bool(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[A-Z]\u0026#39;\u003c/span\u003e, password))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        has_lower \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e bool(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[a-z]\u0026#39;\u003c/span\u003e, password))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        has_digit \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e bool(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\d\u0026#39;\u003c/span\u003e, password))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        has_special \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e bool(re\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esearch(\u003cspan style=\"color:#e6db74\"\u003er\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[!@#$%^\u0026amp;*(),.?\u0026#34;:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e|\u0026lt;\u0026gt;]\u0026#39;\u003c/span\u003e, password))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e has_upper:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;需要包含大写字母\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e has_lower:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;需要包含小写字母\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e has_digit:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;需要包含数字\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e has_special:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;需要包含特殊字符\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;密码强度合格\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 使用示例\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003evalidator \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Validator()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etest_cases \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    (\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;email\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;test@example.com\u0026#39;\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    (\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;phone\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;13812345678\u0026#39;\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    (\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;url\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;https://www.example.com\u0026#39;\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    (\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ip\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;192.168.1.1\u0026#39;\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    (\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;date\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;2024-05-01\u0026#39;\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e type_name, value \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e test_cases:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    method \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e getattr(validator, \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;is_valid_\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etype_name\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    result \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e method(value)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    status \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;✓\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e result \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;✗\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003estatus\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etype_name\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003evalue\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 密码强度验证\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epassword \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Test@1234\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003evalid, msg \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e validator\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eis_strong_password(password)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e密码 \u0026#39;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003epassword\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003emsg\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"背诵版\"\u003e背诵版\u003c/h2\u003e\n\u003ch3 id=\"高级正则速查\"\u003e高级正则速查\u003c/h3\u003e\n┌─────────────────────────────────────────────────────────────┐\n│                     零宽断言（Lookaround）                   │\n├─────────────────────────────────────────────────────────────┤\n│  (?=...)   正向先行  │ 后面跟着...                          │\n│  (?!...)   负向先行  │ 后面不跟...                          │\n│  (?\u0026lt;=...)  正向后行  │ 前面是...                            │\n│  (?\u0026lt;!...)  负向后行  │ 前面不是...                          │\n├─────────────────────────────────────────────────────────────┤\n│  (?P\u0026lt;name\u0026gt;...)   命名分组                                   │\n│  (?:...)         非捕获分组                                 │\n│  \\1, \\2          反向引用                                   │\n└─────────────────────────────────────────────────────────────┘\u003ch3 id=\"resub-替换函数\"\u003ere.sub 替换函数\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 基本替换\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ere\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(pattern, replacement, string)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 替换函数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ereplace_func\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003ematch\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e...\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 返回替换文本\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ere\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esub(pattern, replace_func, string)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 返回替换次数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ere\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esubn(pattern, replacement, string)  \u003cspan style=\"color:#75715e\"\u003e# 返回 (结果, 次数)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"考前记忆\"\u003e考前记忆\u003c/h2\u003e\n\u003ch3 id=\"面试重点\"\u003e面试重点\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e零宽断言的区别\u003c/strong\u003e\u003c/p\u003e","tags":"python, regex, group, sub, advanced","title":"Day40 - 正则表达式高级与综合项目"},{"columns":"blog-building","content":"问题现象 博客首页打开后，搜索框下方留出了大片空白，快捷链接卡片被推到了屏幕下半部分。用户需要滚动才能看到\u0026quot;专栏\u0026quot;入口，访问路径变长了。\n目标效果：搜索框 → 少量间距 → 快捷链接 → 专栏卡片，首页一屏内尽量展示所有核心入口。\n排查过程 第一层：min-height 冲突 打开浏览器开发者工具，定位到 .home-hero 元素，发现 computed style 显示 min-height: 80vh。这个规则来自主题源文件，但自定义 CSS 里已经加了一条覆盖规则：\n.home-hero { min-height: auto !important; padding: 2rem 0 0.75rem !important; } curl 确认线上 CSS 已经包含这条规则，但刷新页面视觉上没有任何变化——说明有其他规则优先级更高，或者被注释掉的原始规则依然在解析。\n第二层：多处冲突的 min-height 用 grep -n \u0026quot;min-height\u0026quot; /var/www/blog/static/css/tech.css 找到了三处相关规则：\n/* Line 128 */ .home-hero { min-height: 80vh; padding: 80px 20px; } /* Line 393-396 (media query) */ @media (max-width: 768px) { .home-hero { min-height: 60vh !important; padding: 50px 20px !important; } } /* Line 614 (media query) */ @media (min-width: 769px) { .home-hero { min-height: 65vh; padding: 60px 40px; } } 这三处都设置了具体的高度值，而且注释掉不等于删除——CSS 解析器依然会处理注释内的内容在某些构建流程中。更关键的是：自定义 CSS 的覆盖规则写在 line 128 之后，但主题的 media query 规则在 line 393 和 614，相同选择器的后来者优先级更高，且 !important 在 media query 内层会覆盖外层普通规则。\n第三层：处理策略 将三处冲突规则全部注释掉，确保没有规则能绕过自定义的 min-height: auto：\n/* Line 128 - 注释掉 .home-hero { min-height: 80vh; padding: 80px 20px; } */ /* Line 393-396 - 注释掉 @media (max-width: 768px) { .home-hero { min-height: 60vh !important; padding: 50px 20px !important; } } */ /* Line 614 - 注释掉 @media (min-width: 769px) { .home-hero { min-height: 65vh; padding: 60px 40px; } } */ 第四层：间距微调 高度问题解决后，发现搜索框到快捷链接间距仍然偏大（~3rem），调整了 tech.css 里的相关间距：\n.home-hero { min-height: auto !important; padding: 2rem 0 0.75rem !important; } .home-tagline { margin-top: 0.25rem; } .bing-results { margin: 0; } 验证步骤 # 1. 确认 CSS 已更新 curl -s \u0026#34;https://blog.uuworld.cn/css/tech.css\u0026#34; | grep -A3 \u0026#34;^.home-hero {\u0026#34; # 2. 确认三处冲突规则已注释 grep -n \u0026#34;min-height.*vh\u0026#34; /var/www/blog/static/css/tech.css # 3. 强制刷新浏览器 Ctrl+Shift+R，清除 CDN 缓存（如有） 经验总结 Hugo PaperMod 主题的 CSS 变量通过 !important 级联传递，自定义 CSS 需要对所有断点的同名规则做覆盖，否则 media query 内的 !important 会悄悄\u0026quot;夺回\u0026quot;控制权。\n备份永远是第一件事，本次修改前已将 /var/www/blog/layouts/index.html 和 static/css/tech.css 同步到 /home/blog-backup-*/。\n相关文件\n模板：/var/www/blog/layouts/index.html 样式：/var/www/blog/static/css/tech.css 备份：/home/blog-backup-20260430200512/ ","description":"","permalink":"https://blog.uuworld.cn/posts/005-blog-homepage-fix/","summary":"\u003ch2 id=\"问题现象\"\u003e问题现象\u003c/h2\u003e\n\u003cp\u003e博客首页打开后，搜索框下方留出了大片空白，快捷链接卡片被推到了屏幕下半部分。用户需要滚动才能看到\u0026quot;专栏\u0026quot;入口，访问路径变长了。\u003c/p\u003e\n\u003cp\u003e目标效果：搜索框 → 少量间距 → 快捷链接 → 专栏卡片，首页一屏内尽量展示所有核心入口。\u003c/p\u003e\n\u003ch2 id=\"排查过程\"\u003e排查过程\u003c/h2\u003e\n\u003ch3 id=\"第一层min-height-冲突\"\u003e第一层：min-height 冲突\u003c/h3\u003e\n\u003cp\u003e打开浏览器开发者工具，定位到 \u003ccode\u003e.home-hero\u003c/code\u003e 元素，发现 computed style 显示 \u003ccode\u003emin-height: 80vh\u003c/code\u003e。这个规则来自主题源文件，但自定义 CSS 里已经加了一条覆盖规则：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-css\" data-lang=\"css\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003ehome-hero\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emin-height\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eauto\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003erem\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0.75\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003erem\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003ecurl\u003c/code\u003e 确认线上 CSS 已经包含这条规则，但刷新页面视觉上没有任何变化——说明有其他规则优先级更高，或者被注释掉的原始规则依然在解析。\u003c/p\u003e\n\u003ch3 id=\"第二层多处冲突的-min-height\"\u003e第二层：多处冲突的 min-height\u003c/h3\u003e\n\u003cp\u003e用 \u003ccode\u003egrep -n \u0026quot;min-height\u0026quot; /var/www/blog/static/css/tech.css\u003c/code\u003e 找到了三处相关规则：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-css\" data-lang=\"css\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e/* Line 128 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003ehome-hero\u003c/span\u003e { \u003cspan style=\"color:#66d9ef\"\u003emin-height\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e80\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003evh\u003c/span\u003e; \u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e80\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e; }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e/* Line 393-396 (media query) */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003emedia\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003emax-width\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e768px\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  .\u003cspan style=\"color:#a6e22e\"\u003ehome-hero\u003c/span\u003e { \u003cspan style=\"color:#66d9ef\"\u003emin-height\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e60\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003evh\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e; \u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e; }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e/* Line 614 (media query) */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003emedia\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003emin-width\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e769px\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  .\u003cspan style=\"color:#a6e22e\"\u003ehome-hero\u003c/span\u003e { \u003cspan style=\"color:#66d9ef\"\u003emin-height\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e65\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003evh\u003c/span\u003e; \u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e60\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e40\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e; }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这三处都设置了具体的高度值，而且注释掉不等于删除——CSS 解析器依然会处理注释内的内容在某些构建流程中。更关键的是：自定义 CSS 的覆盖规则写在 line 128 之后，但主题的 media query 规则在 line 393 和 614，\u003cstrong\u003e相同选择器的后来者优先级更高\u003c/strong\u003e，且 \u003ccode\u003e!important\u003c/code\u003e 在 media query 内层会覆盖外层普通规则。\u003c/p\u003e","tags":"Hugo, PaperMod, CSS, 排版, 博客","title":"博客首页排版修复：Hero 区域高度与快捷链接间距优化"},{"columns":"","content":"安装包下载 文件 版本 大小 说明 hugo-0.146.0-extended-linux-amd64.tar.gz 0.146.0 18 MB Hugo 静态博客引擎 extended 版（含 PostCSS/SCSS） PaperMod-master.zip master 281 KB PaperMod 主题源码 tailscale_1.96.4_amd64.tar.gz 1.96.4 35 MB Tailscale 客户端（tailscaled + tailscale CLI） derper_v1.96.5_linux_amd64.tar.gz 1.96.5 13 MB Tailscale DERP relay 二进制 lucky_2.26.2_Linux_x86_64.tar.gz 2.26.2 11 MB Lucky ACME 客户端（自动化 SSL 证书） lucky.tar.gz 旧版 11 MB Lucky 旧版本 nginx-1.20.1_almalinux9_x86_64.tar.gz 1.20.1 575 KB Nginx 二进制（仅主程序） 软件安装 Hugo tar -xzf hugo-0.146.0-extended-linux-amd64.tar.gz mv hugo /usr/local/bin/ hugo version Tailscale tar -xzf tailscale_1.96.4_amd64.tar.gz cd tailscale_1.96.4_amd64 ./tailscaled install-systemd DERP relay tar -xzf derper_v1.96.5_linux_amd64.tar.gz ./derper -c /var/lib/derper/derper.conf Lucky（ACME 客户端） tar -xzf lucky_2.26.2_Linux_x86_64.tar.gz cd lucky ./lucky Nginx（AlmaLinux 9） # AlmaLinux 9 用 dnf 安装 dnf install -y nginx # 或下载本包后手动部署 tar -xzf nginx-1.20.1_almalinux9_x86_64.tar.gz mv nginx /usr/sbin/nginx nginx -v 其他工具 工具 用途 Cloudflare CDN / DNS / 安全 Let\u0026rsquo;s Encrypt 免费 SSL 证书 GitHub 代码托管 Hugo 静态博客引擎 Tailscale 内网穿透 / VPN MobaXterm Windows SSH 客户端 工具在精不在多，够用就好。\n","description":"","permalink":"https://blog.uuworld.cn/tools/","summary":"\u003ch1 id=\"安装包下载\"\u003e安装包下载\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e文件\u003c/th\u003e\n          \u003cth\u003e版本\u003c/th\u003e\n          \u003cth\u003e大小\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"/downloads/hugo-0.146.0-extended-linux-amd64.tar.gz\"\u003ehugo-0.146.0-extended-linux-amd64.tar.gz\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e0.146.0\u003c/td\u003e\n          \u003ctd\u003e18 MB\u003c/td\u003e\n          \u003ctd\u003eHugo 静态博客引擎 extended 版（含 PostCSS/SCSS）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"/downloads/PaperMod-master.zip\"\u003ePaperMod-master.zip\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003emaster\u003c/td\u003e\n          \u003ctd\u003e281 KB\u003c/td\u003e\n          \u003ctd\u003ePaperMod 主题源码\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"/downloads/tailscale_1.96.4_amd64.tar.gz\"\u003etailscale_1.96.4_amd64.tar.gz\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e1.96.4\u003c/td\u003e\n          \u003ctd\u003e35 MB\u003c/td\u003e\n          \u003ctd\u003eTailscale 客户端（tailscaled + tailscale CLI）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"/downloads/derper_v1.96.5_linux_amd64.tar.gz\"\u003ederper_v1.96.5_linux_amd64.tar.gz\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e1.96.5\u003c/td\u003e\n          \u003ctd\u003e13 MB\u003c/td\u003e\n          \u003ctd\u003eTailscale DERP relay 二进制\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"/downloads/lucky_2.26.2_Linux_x86_64.tar.gz\"\u003elucky_2.26.2_Linux_x86_64.tar.gz\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e2.26.2\u003c/td\u003e\n          \u003ctd\u003e11 MB\u003c/td\u003e\n          \u003ctd\u003eLucky ACME 客户端（自动化 SSL 证书）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"/downloads/lucky.tar.gz\"\u003elucky.tar.gz\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e旧版\u003c/td\u003e\n          \u003ctd\u003e11 MB\u003c/td\u003e\n          \u003ctd\u003eLucky 旧版本\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"/downloads/nginx-1.20.1_almalinux9_x86_64.tar.gz\"\u003enginx-1.20.1_almalinux9_x86_64.tar.gz\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e1.20.1\u003c/td\u003e\n          \u003ctd\u003e575 KB\u003c/td\u003e\n          \u003ctd\u003eNginx 二进制（仅主程序）\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch2 id=\"软件安装\"\u003e软件安装\u003c/h2\u003e\n\u003ch3 id=\"hugo\"\u003eHugo\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etar -xzf hugo-0.146.0-extended-linux-amd64.tar.gz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emv hugo /usr/local/bin/\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehugo version\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"tailscale\"\u003eTailscale\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etar -xzf tailscale_1.96.4_amd64.tar.gz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecd tailscale_1.96.4_amd64\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e./tailscaled install-systemd\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"derp-relay\"\u003eDERP relay\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etar -xzf derper_v1.96.5_linux_amd64.tar.gz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e./derper -c /var/lib/derper/derper.conf\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"luckyacme-客户端\"\u003eLucky（ACME 客户端）\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etar -xzf lucky_2.26.2_Linux_x86_64.tar.gz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecd lucky\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e./lucky\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"nginxalmalinux-9\"\u003eNginx（AlmaLinux 9）\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# AlmaLinux 9 用 dnf 安装\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ednf install -y nginx\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 或下载本包后手动部署\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etar -xzf nginx-1.20.1_almalinux9_x86_64.tar.gz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emv nginx /usr/sbin/nginx\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enginx -v\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"其他工具\"\u003e其他工具\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e工具\u003c/th\u003e\n          \u003cth\u003e用途\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.cloudflare.com/\"\u003eCloudflare\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eCDN / DNS / 安全\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://letsencrypt.org/\"\u003eLet\u0026rsquo;s Encrypt\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e免费 SSL 证书\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/\"\u003eGitHub\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e代码托管\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://gohugo.io/\"\u003eHugo\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e静态博客引擎\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://tailscale.com/\"\u003eTailscale\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e内网穿透 / VPN\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://mobaxterm.mobatek.net/\"\u003eMobaXterm\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eWindows SSH 客户端\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003cblockquote\u003e\n\u003cp\u003e工具在精不在多，够用就好。\u003c/p\u003e","tags":"","title":"工具箱"},{"columns":"","content":"关于本站 踩过的坑，都是经验。\n我是谁 热爱折腾的开发者，主要方向：\n网络与安全 — Tailscale、WireGuard、DERP 部署 DevOps — Linux 服务器运维、CI/CD 博客折腾 — Hugo、Hexo 等静态博客 技术栈 分类 技术 编程 Go / Python / Shell / JavaScript 容器 Docker / K8s 网络 Tailscale / WireGuard / Nginx 云服务 阿里云 ECS / 腾讯云 / Cloudflare 博客说明 本站基于 Hugo + PaperMod，部署在 阿里云 ECS。\n保持折腾，持续记录。\n","description":"","permalink":"https://blog.uuworld.cn/about/","summary":"\u003ch1 id=\"关于本站\"\u003e关于本站\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e踩过的坑，都是经验。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"我是谁\"\u003e我是谁\u003c/h2\u003e\n\u003cp\u003e热爱折腾的开发者，主要方向：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e网络与安全\u003c/strong\u003e — Tailscale、WireGuard、DERP 部署\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDevOps\u003c/strong\u003e — Linux 服务器运维、CI/CD\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e博客折腾\u003c/strong\u003e — Hugo、Hexo 等静态博客\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"技术栈\"\u003e技术栈\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e分类\u003c/th\u003e\n          \u003cth\u003e技术\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e编程\u003c/td\u003e\n          \u003ctd\u003eGo / Python / Shell / JavaScript\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e容器\u003c/td\u003e\n          \u003ctd\u003eDocker / K8s\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e网络\u003c/td\u003e\n          \u003ctd\u003eTailscale / WireGuard / Nginx\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e云服务\u003c/td\u003e\n          \u003ctd\u003e阿里云 ECS / 腾讯云 / Cloudflare\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"博客说明\"\u003e博客说明\u003c/h2\u003e\n\u003cp\u003e本站基于 \u003cstrong\u003eHugo\u003c/strong\u003e + \u003cstrong\u003ePaperMod\u003c/strong\u003e，部署在 \u003cstrong\u003e阿里云 ECS\u003c/strong\u003e。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e保持折腾，持续记录。\u003c/p\u003e\u003c/blockquote\u003e","tags":"","title":"关于"},{"columns":"blog-building","content":"问题现象 博客在手机端打开 Day 5 这类文章时，中文文字出现了逐字分行的问题：\n创 建 N A T 网 关明明一行能显示的文字，被拆成了一个个单字，视觉上完全无法阅读。\n第一反应：CSS 问题 以为是 word-break 或 white-space 的锅。用 MobaXterm 连上服务器，先把 CSS 文件拉下来看：\nscp root@***.uuworld.cn:/var/www/blog/static/css/tech.css . 找到好几处 word-break: break-word，这个属性在手机端会让浏览器在任意字符之间断行——而中文没有空格，浏览器就把每个字都当成了合法断点，自然就逐字分行显示。\n修改方案：把涉及中文内容的 word-break: break-word 全部改成 word-break: normal，让中文按自然语意换行。\n同步回服务器，重建 Hugo：\nscp tech.css root@***.uuworld.cn:/var/www/blog/static/css/tech.css ssh root@***.uuworld.cn \u0026#34;cd /var/www/blog \u0026amp;\u0026amp; hugo\u0026#34; 验证 CSS 是否更新：\ncurl https://***.uuworld.cn/css/tech.css | grep \u0026#39;word-break\u0026#39; 结果：CSS 已生效。但刷新手机端，问题依旧。\n深入：HTML 里藏了什么 CSS 修改了但没效果，怀疑 HTML 本身就有问题。用 curl 抓页面看：\ncurl http://***.uuworld.cn/acp/acp-day-05-acp-day-5-vpc-nat/ | grep -A5 \u0026#39;典型实验流程\u0026#39; 输出里发现了这个：\n\u0026lt;div class=\u0026#34;goat svg-container \u0026#34;\u0026gt; \u0026lt;svg xmlns=\u0026#34;http://www.w3.org/2000/svg\u0026#34; font-family=\u0026#34;Menlo,Lucida Console,monospace\u0026#34; viewBox=\u0026#34;0 0 192 201\u0026#34;\u0026gt; \u0026lt;g transform=\u0026#39;translate(8,16)\u0026#39;\u0026gt; \u0026lt;text text-anchor=\u0026#39;middle\u0026#39; x=\u0026#39;0\u0026#39; y=\u0026#39;4\u0026#39; fill=\u0026#39;currentColor\u0026#39; style=\u0026#39;font-size:1em\u0026#39;\u0026gt;系\u0026lt;/text\u0026gt; \u0026lt;text text-anchor=\u0026#39;middle\u0026#39; x=\u0026#39;0\u0026#39; y=\u0026#39;20\u0026#39; fill=\u0026#39;currentColor\u0026#39; style=\u0026#39;font-size:1em\u0026#39;\u0026gt;├\u0026lt;/text\u0026gt; \u0026lt;text text-anchor=\u0026#39;middle\u0026#39; x=\u0026#39;0\u0026#39; y=\u0026#39;36\u0026#39; fill=\u0026#39;currentColor\u0026#39; style=\u0026#39;font-size:1em\u0026#39;\u0026gt;├\u0026lt;/text\u0026gt; 问题找到了！Hugo 生成的 HTML 里，代码块被转成了 SVG 图形，每个字符都是独立的 \u0026lt;text\u0026gt; 元素。手机端 SVG 无法正确缩放，浏览器就把每个字符当成独立行来渲染。\n根因定位：Hugo 内置 goat 库 Hugo 二进制文件里内置了 goat 库：\nstrings /usr/local/bin/hugo | grep -i \u0026#39;goat\u0026#39; Goat *goat.SVG github.com/bep/goatHugo v0.146.0 extended 版本的代码块渲染逻辑里，藏着一个内置模板 embedded/templates/_markup/render-codeblock-goat.html。这个模板会自动检测代码块里的树形图字符（├── └─ │），然后把它们转成 SVG 图形。\nDay 5 文章里有这段代码块：\n系统路由表 ├── 创建VPC后自动生成 ├── 不可删除、不可手动创建 └── 可添加自定义路由条目Hugo 检测到 ├── 和 └── 字符，触发 goat 转换，生成了 SVG 而不是普通代码块。\n解决方案：覆盖 Hugo 内置模板 Hugo 的 render hook 机制支持自定义覆盖。只需在项目 layouts 目录下创建同名模板：\nmkdir -p /var/www/blog/layouts/_default/_markup cat \u0026gt; /var/www/blog/layouts/_default/_markup/render-codeblock-goat.html \u0026lt;\u0026lt; \u0026#39;EOF\u0026#39; {{- .Inner -}} EOF 这个空模板只输出原始文本内容，覆盖了 Hugo 内置的 SVG 生成逻辑。\n同时，把 markdown 里的树形图字符也替换成普通列表格式，彻底消除触发条件：\n系统路由表 - 创建VPC后自动生成 - 不可删除、不可手动创建 - 可添加自定义路由条目重建验证：\ncd /var/www/blog \u0026amp;\u0026amp; hugo curl http://***.uuworld.cn/acp/acp-day-05-acp-day-5-vpc-nat/ | grep -c \u0026#39;svg-container\u0026#39; # 输出: 0 经验总结 阶段 动作 结果 第一反应 修改 CSS word-break CSS 生效但问题依旧 深入排查 curl 查看 HTML 发现 SVG 标签 根因定位 strings 检查 Hugo binary 发现内置 goat 库 解决方案 创建 render-codeblock-goat.html 覆盖 0 个 SVG，问题解决 Hugo extended 版本内置了很多额外功能（SCSS/SASS 渲染、goat SVG 等），这些功能在配置文件里完全看不到，但会影响页面输出。遇到类似\u0026quot;改了 CSS 没效果\u0026quot;的问题，记得直接查 HTML 源码，很可能是生成阶段就已经出错了。\n相关文件 /var/www/blog/layouts/_default/_markup/render-codeblock-goat.html — 空模板，覆盖内置 goat 转换 /var/www/blog/static/css/tech.css — 手机端 CSS 优化（word-break: normal） ","description":"","permalink":"https://blog.uuworld.cn/posts/004-blog-mobile-fix/","summary":"\u003ch2 id=\"问题现象\"\u003e问题现象\u003c/h2\u003e\n\u003cp\u003e博客在手机端打开 Day 5 这类文章时，中文文字出现了逐字分行的问题：\u003c/p\u003e\n创\n建\nN\nA\nT\n网\n关\u003cp\u003e明明一行能显示的文字，被拆成了一个个单字，视觉上完全无法阅读。\u003c/p\u003e\n\u003ch2 id=\"第一反应css-问题\"\u003e第一反应：CSS 问题\u003c/h2\u003e\n\u003cp\u003e以为是 \u003ccode\u003eword-break\u003c/code\u003e 或 \u003ccode\u003ewhite-space\u003c/code\u003e 的锅。用 MobaXterm 连上服务器，先把 CSS 文件拉下来看：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003escp root@***.uuworld.cn:/var/www/blog/static/css/tech.css .\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e找到好几处 \u003ccode\u003eword-break: break-word\u003c/code\u003e，这个属性在手机端会让浏览器在任意字符之间断行——而中文没有空格，浏览器就把每个字都当成了合法断点，自然就逐字分行显示。\u003c/p\u003e\n\u003cp\u003e修改方案：把涉及中文内容的 \u003ccode\u003eword-break: break-word\u003c/code\u003e 全部改成 \u003ccode\u003eword-break: normal\u003c/code\u003e，让中文按自然语意换行。\u003c/p\u003e\n\u003cp\u003e同步回服务器，重建 Hugo：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003escp tech.css root@***.uuworld.cn:/var/www/blog/static/css/tech.css\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003essh root@***.uuworld.cn \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;cd /var/www/blog \u0026amp;\u0026amp; hugo\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e验证 CSS 是否更新：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecurl https://***.uuworld.cn/css/tech.css | grep \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;word-break\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e结果：CSS 已生效。但刷新手机端，问题依旧。\u003c/p\u003e\n\u003ch2 id=\"深入html-里藏了什么\"\u003e深入：HTML 里藏了什么\u003c/h2\u003e\n\u003cp\u003eCSS 修改了但没效果，怀疑 HTML 本身就有问题。用 curl 抓页面看：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecurl http://***.uuworld.cn/acp/acp-day-05-acp-day-5-vpc-nat/ | grep -A5 \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;典型实验流程\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输出里发现了这个：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;goat svg-container \u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;\u003cspan style=\"color:#f92672\"\u003esvg\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003exmlns\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://www.w3.org/2000/svg\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efont-family\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Menlo,Lucida Console,monospace\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eviewBox\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;0 0 192 201\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;\u003cspan style=\"color:#f92672\"\u003eg\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003etransform\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;translate(8,16)\u0026#39;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;\u003cspan style=\"color:#f92672\"\u003etext\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003etext-anchor\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;middle\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ex\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;0\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ey\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;4\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efill\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;currentColor\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estyle\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;font-size:1em\u0026#39;\u003c/span\u003e\u0026gt;系\u0026lt;/\u003cspan style=\"color:#f92672\"\u003etext\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;\u003cspan style=\"color:#f92672\"\u003etext\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003etext-anchor\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;middle\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ex\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;0\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ey\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;20\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efill\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;currentColor\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estyle\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;font-size:1em\u0026#39;\u003c/span\u003e\u0026gt;├\u0026lt;/\u003cspan style=\"color:#f92672\"\u003etext\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;\u003cspan style=\"color:#f92672\"\u003etext\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003etext-anchor\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;middle\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ex\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;0\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ey\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;36\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efill\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;currentColor\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estyle\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;font-size:1em\u0026#39;\u003c/span\u003e\u0026gt;├\u0026lt;/\u003cspan style=\"color:#f92672\"\u003etext\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e问题找到了！Hugo 生成的 HTML 里，代码块被转成了 SVG 图形，每个字符都是独立的 \u003ccode\u003e\u0026lt;text\u0026gt;\u003c/code\u003e 元素。手机端 SVG 无法正确缩放，浏览器就把每个字符当成独立行来渲染。\u003c/p\u003e","tags":"Hugo, PaperMod, CSS, 手机适配, 排错","title":"博客手机端渲染优化：从 CSS 排查到 Hugo goat SVG 根因定位"},{"columns":"blog-building","content":"背景 每次在服务器上下载、安装、配置软件后，安装包散落在 /tmp 或下载目录，没有统一管理。下次要用时找不到，或者重复下载。\n博客搭建完成后，决定把「安装包落地」这件事系统化。\n流程设计 下载安装包（本地或代理） ↓ 安装、配置、验证 ↓ 移动到 /var/www/blog/static/downloads/ ↓ 更新 tools/index.md 的下载链接 ↓ Hugo 自动构建发布实际操作 1. 下载安装包 能直接从互联网下载（代理/VPS 可达）：本地 curl/wget 后 scp 上传\n# 本地下载 Hugo curl -sL \u0026#39;https://github.com/gohugoio/hugo/releases/download/v0.146.0/...tar.gz\u0026#39; -o hugo.tar.gz # scp 到服务器 downloads 目录 scp hugo.tar.gz root@***.uuworld.cn:/var/www/blog/static/downloads/ 服务器本地已有：直接 cp 到 downloads\ncp /root/go/bin/derper /var/www/blog/static/downloads/ cd /var/www/blog/static/downloads/ tar -czf derper_v1.96.5_linux_amd64.tar.gz derper 2. 更新 tools 页面 在 content/tools/index.md 添加下载链接：\n| [derper_v1.96.5_linux_amd64.tar.gz](/downloads/derper_v1.96.5_linux_amd64.tar.gz) | 1.96.5 | 13 MB | Tailscale DERP relay 二进制 | 3. 构建发布 cd /var/www/blog /usr/local/bin/hugo --quiet 即可通过 https://***.uuworld.cn/tools/ 下载。\n当前已落地安装包 文件 下载 版本 大小 hugo-0.146.0-extended-linux-amd64.tar.gz Hugo extended 0.146.0 18 MB PaperMod-master.zip PaperMod master 281 KB tailscale_1.96.4_amd64.tar.gz Tailscale 1.96.4 35 MB derper_v1.96.5_linux_amd64.tar.gz DERP relay 1.96.5 13 MB lucky_2.26.2_Linux_x86_64.tar.gz Lucky 2.26.2 11 MB nginx-1.20.1_almalinux9_x86_64.tar.gz Nginx 1.20.1 575 KB 后续规则 安装包不过夜：验证可用后 24 小时内落地到 downloads 保留原始文件名：包含版本号，方便识别 每个包配安装说明：tools 页面附简短安装命令 大文件优先本地下载：服务器访问外网受限，本地下载后 scp ","description":"","permalink":"https://blog.uuworld.cn/posts/003-package-workflow/","summary":"\u003ch2 id=\"背景\"\u003e背景\u003c/h2\u003e\n\u003cp\u003e每次在服务器上下载、安装、配置软件后，安装包散落在 /tmp 或下载目录，没有统一管理。下次要用时找不到，或者重复下载。\u003c/p\u003e\n\u003cp\u003e博客搭建完成后，决定把「安装包落地」这件事系统化。\u003c/p\u003e\n\u003ch2 id=\"流程设计\"\u003e流程设计\u003c/h2\u003e\n下载安装包（本地或代理）\n    ↓\n安装、配置、验证\n    ↓\n移动到 /var/www/blog/static/downloads/\n    ↓\n更新 tools/index.md 的下载链接\n    ↓\nHugo 自动构建发布\u003ch2 id=\"实际操作\"\u003e实际操作\u003c/h2\u003e\n\u003ch3 id=\"1-下载安装包\"\u003e1. 下载安装包\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e能直接从互联网下载\u003c/strong\u003e（代理/VPS 可达）：本地 curl/wget 后 scp 上传\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 本地下载 Hugo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecurl -sL \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;https://github.com/gohugoio/hugo/releases/download/v0.146.0/...tar.gz\u0026#39;\u003c/span\u003e -o hugo.tar.gz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# scp 到服务器 downloads 目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003escp hugo.tar.gz root@***.uuworld.cn:/var/www/blog/static/downloads/\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e服务器本地已有\u003c/strong\u003e：直接 cp 到 downloads\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecp /root/go/bin/derper /var/www/blog/static/downloads/\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecd /var/www/blog/static/downloads/\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etar -czf derper_v1.96.5_linux_amd64.tar.gz derper\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"2-更新-tools-页面\"\u003e2. 更新 tools 页面\u003c/h3\u003e\n\u003cp\u003e在 \u003ccode\u003econtent/tools/index.md\u003c/code\u003e 添加下载链接：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-markdown\" data-lang=\"markdown\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e| [\u003cspan style=\"color:#f92672\"\u003ederper_v1.96.5_linux_amd64.tar.gz\u003c/span\u003e](\u003cspan style=\"color:#a6e22e\"\u003e/downloads/derper_v1.96.5_linux_amd64.tar.gz\u003c/span\u003e) | 1.96.5 | 13 MB | Tailscale DERP relay 二进制 |\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"3-构建发布\"\u003e3. 构建发布\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecd /var/www/blog\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e/usr/local/bin/hugo --quiet\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e即可通过 \u003ccode\u003ehttps://***.uuworld.cn/tools/\u003c/code\u003e 下载。\u003c/p\u003e","tags":"自动化, DevOps, 博客","title":"安装包落地自动化流程"},{"columns":"blog-building","content":"背景 想用一个简洁的技术博客记录折腾过的项目，选型要求：静态站点、主题好看、部署简单、定制灵活。\n最终技术栈：Hugo 0.146 + PaperMod + nginx + 自定义赛博朋克样式。\n目标 静态博客，Markdown 写文章 PaperMod 主题，简洁好看 自定义科技感 UI：粒子背景 + 霓虹光效 通过 nginx 直接托管 /var/www/blog/public/ 支持 /about/ 和 /tools/ 页面 踩坑记录 Hugo 版本与主题兼容 下载 Hugo 0.139.0 配合 PaperMod 时报错：\nERROR 2026/04/25 错过了GaTracker的site.config.googleAnalytics解决：升级到 Hugo 0.146.0 extended 版本，问题消失。\nwget https://github.com/gohugoio/hugo/releases/download/v0.146.0/hugo_extended_0.146.0_linux-amd64.tar.gz tar -xzf hugo_extended_0.146.0_linux-amd64.tar.gz hugo mv hugo /usr/local/bin/ 安装包下载 文件 下载 hugo-0.146.0-extended-linux-amd64.tar.gz Hugo 0.146.0 extended PaperMod-master.zip PaperMod 主题最新源码 about 页面不渲染 content/about.md 放在根目录，访问 /about/ 始终 404。\n解决：改为目录格式 content/about/index.md，Hugo 正确生成了 /about/ 页面。\n博客域名访问受限 博客域名因阿里云 ICP 备案核查无法访问，暂时通过公网 IP 直接访问。\nCSS 样式优先级冲突 PaperMod 主题有自己的深色样式，自定义 CSS 的颜色老被覆盖。\n解决：\n用 curl 检查实际渲染后的 HTML，找到 PaperMod 的真实 class 名称 针对具体类名写样式：.entry-hint-parent、.post-title、.post-content 等 大量使用 !important 强制覆盖 最终效果 科技感深色背景（#030014） 青色（#00f0ff）+ 紫色（#bd00ff）霓虹配色 Canvas 粒子动画背景 文章标题 97% 白色，正文 92% 白色，清晰可读 Hugo 构建速度 96ms，0 错误 部署结构 /var/www/blog/ ├── content/ │ ├── posts/ │ │ └── 001-ali-ecs-derper-deploy.md │ ├── about/index.md │ └── tools/index.md ├── layouts/ │ └── partials/ │ ├── header.html # 注入 Canvas \u0026#43; 扫描线 │ ├── extend_head.html # 注入 tech.css │ └── extend_footer.html # 注入 tech.js ├── static/ │ ├── css/tech.css │ └── js/tech.js ├── public/ # Hugo 构建输出 └── hugo.toml后续计划 继续写技术记录 优化移动端显示 探索评论系统集成 ","description":"","permalink":"https://blog.uuworld.cn/posts/002-blog-deploy/","summary":"\u003ch2 id=\"背景\"\u003e背景\u003c/h2\u003e\n\u003cp\u003e想用一个简洁的技术博客记录折腾过的项目，选型要求：静态站点、主题好看、部署简单、定制灵活。\u003c/p\u003e\n\u003cp\u003e最终技术栈：\u003cstrong\u003eHugo 0.146\u003c/strong\u003e + \u003cstrong\u003ePaperMod\u003c/strong\u003e + \u003cstrong\u003enginx\u003c/strong\u003e + 自定义赛博朋克样式。\u003c/p\u003e\n\u003ch2 id=\"目标\"\u003e目标\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e静态博客，Markdown 写文章\u003c/li\u003e\n\u003cli\u003ePaperMod 主题，简洁好看\u003c/li\u003e\n\u003cli\u003e自定义科技感 UI：粒子背景 + 霓虹光效\u003c/li\u003e\n\u003cli\u003e通过 nginx 直接托管 /var/www/blog/public/\u003c/li\u003e\n\u003cli\u003e支持 /about/ 和 /tools/ 页面\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"踩坑记录\"\u003e踩坑记录\u003c/h2\u003e\n\u003ch3 id=\"hugo-版本与主题兼容\"\u003eHugo 版本与主题兼容\u003c/h3\u003e\n\u003cp\u003e下载 Hugo 0.139.0 配合 PaperMod 时报错：\u003c/p\u003e\nERROR 2026/04/25 错过了GaTracker的site.config.googleAnalytics\u003cp\u003e\u003cstrong\u003e解决\u003c/strong\u003e：升级到 Hugo 0.146.0 extended 版本，问题消失。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewget https://github.com/gohugoio/hugo/releases/download/v0.146.0/hugo_extended_0.146.0_linux-amd64.tar.gz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etar -xzf hugo_extended_0.146.0_linux-amd64.tar.gz hugo\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emv hugo /usr/local/bin/\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"安装包下载\"\u003e安装包下载\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e文件\u003c/th\u003e\n          \u003cth\u003e下载\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"/downloads/hugo/hugo-0.146.0-extended-linux-amd64.tar.gz\"\u003ehugo-0.146.0-extended-linux-amd64.tar.gz\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eHugo 0.146.0 extended\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"/downloads/hugo/PaperMod-master.zip\"\u003ePaperMod-master.zip\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003ePaperMod 主题最新源码\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"about-页面不渲染\"\u003eabout 页面不渲染\u003c/h3\u003e\n\u003cp\u003econtent/about.md 放在根目录，访问 /about/ 始终 404。\u003c/p\u003e","tags":"Hugo, PaperMod, nginx, ali-ecs","title":"Hugo + PaperMod 博客搭建全记录"},{"columns":"blog-building","content":"背景 需要在阿里云 ECS 上部署 Tailscale DERP relay，让 Windows 客户端能通过 DERP 连接到节点。\n目标 域名：derp.***.cn 泛域名证书：.**.cn derper 运行在 443 端口 STUN 运行在 3478 UDP 踩坑记录 1. DNSPod Token 格式 问题：API 返回 401，原因是 SecretId 是腾讯云 CAM 的，不是 DNSPod 的。\n解决：DNSPod Token 格式是 ID,Token（两部分用逗号连接），腾讯云控制台生成的 SecretId/SecretKey 是 CAM 的，不通用。\n2. lucky 安装失败 问题：jsdelivr CDN 在阿里云 ECS 上无法访问，导致 lucky 安装脚本无法下载二进制文件。\n解决：从 GitHub 直接下载 release 包，传到 ECS 再解压安装。\n3. derper 证书参数 问题：新版 derper 参数变了，不再是 -c cert -k key，改为 -certmode manual -certdir。\n解决：新版参数：\ncertmode manual：手动模式 certdir：证书目录，文件名格式 {hostname}.crt / {hostname}.key hostname：指定域名 4. 证书路径 发现：acme.sh 申请的泛域名证书在 /root/.acme.sh/***.cn/，derper 需要复制到 /root/.cache/tailscale/derper-certs/。\n最终配置 ``` ExecStart=/root/go/bin/derper -a :443 -certmode manual -certdir /root/.cache/tailscale/derper-certs -hostname derp.***.cn ```\n验证 ``` curl -sI https://derp.***.cn/ HTTP/1.1 200 OK ```\n待完成 Tailscale 管理后台添加 DERP relay（用户操作） 阿里云安全组开放 443 TCP + 3478 UDP（用户操作） 总结 DERP 部署成功，Windows 客户端通过 derp.***.cn 连接 DERP relay 正常。lucky 在此次任务中未发挥作用。\n安装包下载 文件 下载 tailscale_1.96.4_amd64.tar.gz Tailscale 1.96.4 客户端 derper_v1.96.5_linux_amd64.tar.gz DERP relay 1.96.5 ","description":"","permalink":"https://blog.uuworld.cn/posts/001-ali-ecs-derper-deploy/","summary":"\u003ch2 id=\"背景\"\u003e背景\u003c/h2\u003e\n\u003cp\u003e需要在阿里云 ECS 上部署 Tailscale DERP relay，让 Windows 客户端能通过 DERP 连接到节点。\u003c/p\u003e\n\u003ch2 id=\"目标\"\u003e目标\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e域名：derp.***.cn\u003c/li\u003e\n\u003cli\u003e泛域名证书：\u003cem\u003e.\u003c/em\u003e**.cn\u003c/li\u003e\n\u003cli\u003ederper 运行在 443 端口\u003c/li\u003e\n\u003cli\u003eSTUN 运行在 3478 UDP\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"踩坑记录\"\u003e踩坑记录\u003c/h2\u003e\n\u003ch3 id=\"1-dnspod-token-格式\"\u003e1. DNSPod Token 格式\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e问题\u003c/strong\u003e：API 返回 401，原因是 SecretId 是腾讯云 CAM 的，不是 DNSPod 的。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e解决\u003c/strong\u003e：DNSPod Token 格式是 ID,Token（两部分用逗号连接），腾讯云控制台生成的 SecretId/SecretKey 是 CAM 的，不通用。\u003c/p\u003e\n\u003ch3 id=\"2-lucky-安装失败\"\u003e2. lucky 安装失败\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e问题\u003c/strong\u003e：jsdelivr CDN 在阿里云 ECS 上无法访问，导致 lucky 安装脚本无法下载二进制文件。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e解决\u003c/strong\u003e：从 GitHub 直接下载 release 包，传到 ECS 再解压安装。\u003c/p\u003e\n\u003ch3 id=\"3-derper-证书参数\"\u003e3. derper 证书参数\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e问题\u003c/strong\u003e：新版 derper 参数变了，不再是 -c cert -k key，改为 -certmode manual -certdir。\u003c/p\u003e","tags":"Tailscale, DERP, ali-ecs","title":"ali-ecs DERP 部署全记录"}]