云计算百科
云计算领域专业知识百科平台

Python基础语法教程

🐍 Python 基础语法这一篇就够了

适用版本: Python 3.8+ 目标读者: 初学者及有一定基础想要系统复习的开发者 最后更新: 2026-07-21


目录

  • Python 简介
  • 环境搭建与第一个程序
  • 变量与数据类型
  • 运算符
  • 字符串详解
  • 列表(List)
  • 元组(Tuple)
  • 字典(Dictionary)
  • 集合(Set)
  • 条件判断
  • 循环语句
  • 函数
  • Lambda 表达式
  • 列表推导式与生成器表达式
  • 迭代器与生成器
  • 装饰器
  • 模块与包
  • 文件操作
  • 异常处理
  • 面向对象编程
  • 常用内置函数
  • 类型注解
  • 虚拟环境与包管理
  • 编码规范(PEP 8)
  • 综合练习

  • 1. Python 简介

    1.1 什么是 Python?

    Python 是一种高级、解释型、面向对象的编程语言,由 Guido van Rossum 于 1991 年发布。它以简洁易读的语法和强大的标准库而闻名。

    1.2 Python 的特点

    特点说明
    简洁易读 使用缩进表示代码块,语法接近自然语言
    解释型语言 无需编译,逐行解释执行
    动态类型 变量无需声明类型,运行时自动推断
    跨平台 支持 Windows、macOS、Linux 等
    丰富的库 拥有庞大的标准库和第三方生态
    多范式 支持面向对象、过程式、函数式编程

    1.3 Python 的应用领域

    • Web 开发: Django、Flask、FastAPI
    • 数据科学与人工智能: NumPy、Pandas、PyTorch、TensorFlow
    • 自动化运维: Ansible、SaltStack
    • 网络爬虫: Scrapy、BeautifulSoup、Selenium
    • 桌面应用: PyQt、Tkinter
    • 游戏开发: Pygame

    2. 环境搭建与第一个程序

    2.1 安装 Python

    从 python.org 下载安装包。安装时务必勾选 “Add Python to PATH”。

    验证安装:

    python –version
    # 输出示例: Python 3.11.5

    2.2 第一个程序:Hello, World!

    💡 代码说明:创建第一个 Python 程序,用 print() 函数在屏幕上输出文字:

    # hello.py
    print("Hello, World!")

    🔑 要点总结:运行后屏幕上将显示 Hello, World! ——你已经成功编写了第一个 Python 程序。

    运行:

    python hello.py
    # 输出: Hello, World!

    2.3 交互式解释器(REPL)

    在终端输入 python 即可进入交互模式:

    💡 代码说明:在终端输入 python 进入交互模式,可以逐行输入代码并立即看到结果,适合快速测试:

    >>> 1 + 2
    3
    >>> print("你好,世界!")
    你好,世界!
    >>> exit() # 退出交互模式

    🔑 要点总结:REPL 是学习 Python 的利器——每学一个新语法都可以先在交互环境中试一试。输入 exit() 即可退出。

    2.4 IDE 推荐

    IDE特点
    VS Code 免费、轻量、插件丰富(推荐)
    PyCharm 专业的 Python IDE,功能强大
    Jupyter Notebook 适合数据分析和科学计算
    IDLE Python 自带,入门够用

    3. 变量与数据类型

    3.1 变量命名规则

    💡 代码说明:Python 变量名由字母、数字和下划线组成,但不能以数字开头,也不能使用关键字。来看几个例子:

    # ✅ 合法的变量名
    name = "Alice"
    age = 25
    first_name = "Bob"
    _name = "hidden"
    user123 = "valid"

    # ❌ 非法的变量名
    # 123abc = "error" # 不能以数字开头
    # my-name = "error" # 不能包含连字符
    # class = "error" # 不能使用关键字

    🔑 要点总结:记住三条核心规则:不能数字开头、不能用关键字、区分大小写。按照 snake_case 风格命名是最佳实践。

    命名规范(PEP 8):

    • 变量和函数:小写 + 下划线 snake_case
    • 类名:大驼峰 PascalCase
    • 常量:全大写 UPPER_CASE

    3.2 Python 关键字

    💡 代码说明:Python 保留了一些有特殊含义的单词(关键字),不能用作变量名。通过 keyword 模块可以查看完整列表:

    import keyword
    print(keyword.kwlist)
    # ['False', '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']

    🔑 要点总结:总共 35 个关键字(Python 3.8+),像 if、for、class、def 等都在其中,取名时注意避开。

    3.3 基本数据类型

    💡 代码说明:Python 有六大基本数据类型:整数(int)、浮点数(float)、复数(complex)、布尔值(bool)、字符串(str)和空值(None)。下面的代码展示了每种类型的用法:

    # — 数值型 —
    # int(整数):无大小限制
    a = 10
    b = 5
    big = 999999999999999999999999999999

    # float(浮点数):双精度,约 15-17 位有效数字
    pi = 3.14159
    sci = 1.5e-3 # 科学计数法 = 0.0015

    # complex(复数)
    c = 3 + 4j
    print(c.real) # 3.0
    print(c.imag) # 4.0

    # — 布尔型 —
    # bool:True 或 False(首字母大写)
    is_active = True
    is_empty = False
    # bool 是 int 的子类:True == 1, False == 0
    print(True + True) # 2
    print(isinstance(True, int)) # True

    # — 字符串 —
    # str:使用单引号或双引号
    name = 'Alice'
    message = "Hello"
    multiline = """第一行
    第二行
    第三行"""

    # — None 类型 —
    # None:表示"没有值"或"空"
    result = None

    🔑 要点总结:Python 的整数没有大小限制,布尔值是 int 的子类(True==1),None 表示无值。这些都是日常编程最基础的数据类型。

    3.4 类型检查与转换

    💡 代码说明:使用 type() 查看变量类型,isinstance() 检查继承关系,以及用 int()、float()、str() 等函数在不同类型间转换:

    # type() 查看类型
    x = 42
    print(type(x)) # <class 'int'>

    # isinstance() 检查类型
    print(isinstance(x, int)) # True
    print(isinstance(x, (int, float))) # True(多种类型之一)

    # 类型转换(显式转换)
    num_str = "123"
    num = int(num_str) # 字符串 -> 整数: 123
    f = float("3.14") # 字符串 -> 浮点数: 3.14
    s = str(100) # 整数 -> 字符串: "100"
    b = bool(1) # -> True (非0为True,0/空/None为False)
    lst = list("hello") # 字符串 -> 列表: ['h', 'e', 'l', 'l', 'o']

    🔑 要点总结:isinstance() 比 type() 更灵活(支持子类判断),显式类型转换时要确保数据格式正确,否则会抛出 ValueError。

    3.5 动态类型

    💡 代码说明:Python 是动态类型语言,同一个变量可以在不同时刻指向不同类型的值,无需提前声明:

    # Python 是动态类型语言,变量可以随时改变类型
    x = 10
    print(type(x)) # <class 'int'>

    x = "hello"
    print(type(x)) # <class 'str'>

    x = [1, 2, 3]
    print(type(x)) # <class 'list'>

    🔑 要点总结:动态类型让代码更灵活简洁,但也意味着要小心类型错误——这也是类型注解(第22章)存在的意义。

    3.6 可变与不可变类型

    💡 代码说明:理解可变(list/dict/set)和不可变(int/str/tuple)类型的区别,是掌握 Python 内存行为的关键:

    # 不可变类型:int, float, complex, str, tuple, frozenset, bool
    a = "hello"
    # a[0] = "H" # ❌ TypeError: 'str' object does not support item assignment

    # 可变类型:list, dict, set, bytearray
    b = [1, 2, 3]
    b[0] = 10 # ✅ 可以修改
    print(b) # [10, 2, 3]

    🔑 要点总结:不可变对象无法原地修改,任何修改操作实际是创建新对象;可变对象则可以直接改变其内容。这影响了赋值、传参和拷贝的行为。


    4. 运算符

    4.1 算术运算符

    💡 代码说明:Python 支持加减乘除、整除、取余、幂运算等基本算术运算,以及 abs()、round()、divmod() 等内置数学函数:

    a, b = 10, 3

    print(a + b) # 13 加
    print(a b) # 7 减
    print(a * b) # 30 乘
    print(a / b) # 3.3333333333333335 除(总是返回float)
    print(a // b) # 3 整除(向下取整)
    print(a % b) # 1 取余
    print(a ** b) # 1000 幂运算
    print(abs(5)) # 5 绝对值
    print(round(3.14159, 2)) # 3.14 四舍五入
    print(pow(2, 3)) # 8 等价于 2**3

    # divmod:同时返回商和余数
    quotient, remainder = divmod(10, 3)
    print(quotient, remainder) # 3 1

    🔑 要点总结:注意 / 总是返回 float,// 是向下取整。divmod() 同时返回商和余数,非常实用。

    4.2 比较运算符

    💡 代码说明:比较运算符用于比较两个值的大小关系,返回布尔值。Python 还支持链式比较和 is / == 两种相等性检查:

    a, b = 10, 20

    print(a == b) # False 等于
    print(a != b) # True 不等于
    print(a > b) # False 大于
    print(a < b) # True 小于
    print(a >= b) # False 大于等于
    print(a <= b) # True 小于等于

    # 链式比较(Python 特有)
    x = 5
    print(0 < x < 10) # True(等价于 0 < x and x < 10)

    # is 和 == 的区别
    # == 比较值是否相等
    # is 比较是否为同一个对象(内存地址相同)
    list_a = [1, 2, 3]
    list_b = [1, 2, 3]
    print(list_a == list_b) # True 值相等
    print(list_a is list_b) # False 不同对象

    # 对于小整数(-5 ~ 256)和短字符串,Python 使用缓存
    a = 256; b = 256
    print(a is b) # True(同一缓存对象)
    a = 257; b = 257
    print(a is b) # 可能 True 也可能 False(取决于实现)

    🔑 要点总结:== 比较值,is 比较身份(内存地址)。对于小整数(-5~256),Python 使用缓存机制,所以 is 也可能返回 True——这是常见的面试考点。

    4.3 逻辑运算符

    💡 代码说明:Python 使用 and、or、not(而不是 &&、||、!)。逻辑运算支持短路求值,且可以作用于非布尔值:

    # and, or, not(注意:不是 &&, ||, !)
    x, y = True, False

    print(x and y) # False 且
    print(x or y) # True 或
    print(not x) # False 非

    # 短路求值
    def get_true():
    print("get_true 被调用")
    return True

    def get_false():
    print("get_false 被调用")
    return False

    # and:第一个 False 后面的不会执行
    print(get_false() and get_true()) # 只输出 get_false 被调用,返回 False

    # or:第一个 True 后面的不会执行
    print(get_true() or get_false()) # 只输出 get_true 被调用,返回 True

    # 非布尔值的逻辑运算:返回第一个能决定结果的值
    print(0 and 10) # 0 (0 是 "假值",直接返回)
    print([] and 10) # [] (空列表是 "假值")
    print(0 or 10) # 10 (0 是假值,返回 10)
    print("" or "default") # "default"
    print("hello" or "world") # "hello" (第一个是真值)

    # 常见的默认值模式
    name = "" or "匿名用户"
    print(name) # 匿名用户

    🔑 要点总结:短路求值是性能优化的好帮手。非布尔值的逻辑运算返回第一个能决定结果的值,常用于设置默认值(如 name = input_name or ‘匿名’)。

    4.4 位运算符

    💡 代码说明:位运算符直接操作二进制位,包括按位与(&)、或(|)、异或(^)、取反(~)、左移(<<)、右移(>>):

    a, b = 5, 3 # 二进制: 0101, 0011

    print(a & b) # 1 (0101 & 0011 = 0001) 按位与
    print(a | b) # 7 (0101 | 0011 = 0111) 按位或
    print(a ^ b) # 6 (0101 ^ 0011 = 0110) 按位异或
    print(~a) # -6 按位取反
    print(a << 1) # 10 (0101 << 1 = 1010) 左移
    print(a >> 1) # 2 (0101 >> 1 = 0010) 右移

    🔑 要点总结:位运算在底层操作、权限标志、性能优化等场景很有用,但可读性较差,使用时建议加注释说明意图。

    4.5 赋值运算符

    💡 代码说明:除了基本赋值 =,Python 还支持复合赋值(+=、-= 等)和 Python 3.8 新增的海象运算符 :=:

    x = 10
    x += 5 # 等价于 x = x + 5 → 15
    x -= 3 # 等价于 x = x – 3 → 12
    x *= 2 # 等价于 x = x * 2 → 24
    x /= 4 # → 6.0
    x //= 2 # → 3.0
    x **= 2 # → 9.0
    x %= 5 # → 4.0

    # 海象运算符(Python 3.8+):在表达式中赋值
    # 语法: (变量名 := 表达式)
    if (n := len("hello")) > 3:
    print(f"字符串长度为 {n},大于3") # 字符串长度为 5,大于3

    # 经典用法:循环中避免重复计算
    # 传统写法
    import re
    while True:
    line = input()
    if not line:
    break
    # 海象写法
    # while line := input():
    # # 处理 line

    🔑 要点总结:海象运算符 := 能在表达式内部完成赋值,常用于 if 和 while 中避免重复计算,如 while (line := file.readline())。

    4.6 成员运算符

    💡 代码说明:in 和 not in 用于检查元素是否存在于序列(列表、字符串、字典的键等)中:

    # in 和 not in:检查元素是否在序列中
    fruits = ["apple", "banana", "orange"]

    print("apple" in fruits) # True
    print("grape" not in fruits) # True
    print("e" in "hello") # True(字符串也是序列)

    # 字典中检查键
    user = {"name": "Alice", "age": 25}
    print("name" in user) # True
    print("Alice" in user) # False(检查的是键,不是值)
    print("Alice" in user.values()) # True

    🔑 要点总结:对于字典,in 默认检查键而非值;检查值需要用 .values()。in 对集合的判断是 O(1) 的,非常高效。

    4.7 运算符优先级(从高到低)

    # ** 幂运算
    # +x, -x, ~x 一元运算符
    # *, /, //, % 乘除取余
    # +, – 加减
    # <<, >> 位移
    # & 按位与
    # ^ 按位异或
    # | 按位或
    # ==, !=, >, <, >=, <=, is, is not, in, not in 比较
    # not 逻辑非
    # and 逻辑与
    # or 逻辑或
    # := 海象运算符

    # 不确定时就加括号!
    result = (2 + 3) * 4 # 20


    5. 字符串详解

    5.1 字符串创建

    💡 代码说明:Python 提供了四种字符串定义方式:单引号、双引号、三单引号、三双引号,以及原始字符串(r-string)来忽略转义:

    # 四种引号方式
    s1 = '单引号字符串'
    s2 = "双引号字符串"
    s3 = '''三单引号
    可以跨行'''

    s4 = """三双引号
    也可以跨行"""

    # 引号嵌套
    s5 = "It's a book" # 双引号内包含单引号
    s6 = 'He said "Hello"' # 单引号内包含双引号
    s7 = 'It\\'s a book' # 转义字符

    # 原始字符串(raw string):不处理转义
    path = r"C:\\Users\\name\\new_folder"
    print(path) # C:\\Users\\name\\new_folder(\\n 不会被当成换行)

    🔑 要点总结:日常用单/双引号即可;多行文本用三引号;处理 Windows 路径或正则表达式时,原始字符串 r’…’ 能省去大量转义的麻烦。

    5.2 转义字符

    💡 代码说明:反斜杠 \\ 用于引入特殊字符,如换行 \\n、制表符 \\t、引号 " 等:

    print("Hello\\nWorld") # 换行
    print("Hello\\tWorld") # 制表符
    print("Hello\\rWorld") # 回车
    print("He said \\"Hi\\"") # 双引号
    print('It\\'s a book') # 单引号
    print("Path: C:\\\\data") # 反斜杠
    print("Line1\\\\\\nLine2") # 续行(行末的反斜杠表示下一行继续)

    🔑 要点总结:转义字符让字符串能表达任意特殊字符。需要输出反斜杠本身时用 \\,或使用原始字符串 r’…'。

    5.3 字符串索引与切片

    💡 代码说明:字符串支持索引(单个字符)和切片(子字符串)。语法为 [start:stop:step],start 包含、stop 不包含、step 为步长:

    text = "Python编程"

    # 索引(从0开始)
    print(text[0]) # P
    print(text[1]) # 程 (负数索引从右边开始,-1 是最后一个)
    print(text[6]) # 编

    # 切片 [start:stop:step]
    # start: 起始索引(包含),默认0
    # stop: 结束索引(不包含),默认末尾
    # step: 步长,默认1
    text = "0123456789"

    print(text[0:5]) # 01234 索引0到4
    print(text[2:7]) # 23456
    print(text[:5]) # 01234 省略start,从0开始
    print(text[5:]) # 56789 省略stop,到末尾
    print(text[::2]) # 02468 步长为2
    print(text[::1]) # 9876543210 反转字符串!
    print(text[3:]) # 789 最后3个字符

    🔑 要点总结:切片是 Python 最优雅的特性之一。[::-1] 反转字符串、[-3:] 取最后三个字符——简洁而强大。切片操作同样适用于列表和元组。

    5.4 字符串常用方法

    💡 代码说明:字符串有丰富的方法用于大小写转换、空白处理、查找替换、判断和分割连接。以下是完整的参考示例:

    s = " Hello, Python World! "

    # — 大小写转换 —
    print(s.upper()) # " HELLO, PYTHON WORLD! " 全大写
    print(s.lower()) # " hello, python world! " 全小写
    print(s.title()) # " Hello, Python World! " 每个单词首字母大写
    print(s.capitalize()) # " hello, python world! " 首字母大写
    print(s.swapcase()) # " hELLO, pYTHON wORLD! " 大小写翻转

    # — 空白处理 —
    print(s.strip()) # "Hello, Python World!" 去两端空白
    print(s.lstrip()) # "Hello, Python World! " 去左端空白
    print(s.rstrip()) # " Hello, Python World!" 去右端空白

    # — 查找与替换 —
    print(s.find("Python")) # 9 找到返回索引,找不到返回 -1
    print(s.index("Python")) # 9 找到返回索引,找不到抛出 ValueError
    print(s.rfind("o")) # 16 从右边查找
    print(s.count("o")) # 3 统计出现次数
    print(s.replace("World", "大家")) # " Hello, Python 大家! "
    print(s.replace("o", "O", 1)) # " HellO, Python World! " 只替换1次

    # — 判断方法 —
    print(s.startswith(" He")) # True 是否以指定前缀开始
    print(s.endswith("! ")) # True 是否以指定后缀结束
    print("abc123".isalnum()) # True 是否只含字母和数字
    print("abc".isalpha()) # True 是否只含字母
    print("123".isdigit()) # True 是否只含数字
    print("abc".islower()) # True 是否全小写
    print("ABC".isupper()) # True 是否全大写
    print(" ".isspace()) # True 是否全空白字符
    print("Title".istitle()) # True 是否是标题格式

    # — 分割与连接 —
    csv = "apple,banana,orange"
    print(csv.split(",")) # ['apple', 'banana', 'orange']
    print(csv.split(",", 1)) # ['apple', 'banana,orange'] 只分割1次
    print("a b c".split()) # ['a', 'b', 'c'] 默认按空白分割且会合并多个空白

    # rsplit:从右边开始分割
    print("a,b,c".rsplit(",", 1)) # ['a,b', 'c']

    # splitlines:按行分割
    multiline = "line1\\nline2\\nline3"
    print(multiline.splitlines()) # ['line1', 'line2', 'line3']
    print(multiline.splitlines(keepends=True)) # ['line1\\n', 'line2\\n', 'line3']

    # join:用分隔符连接可迭代对象
    words = ["Python", "is", "awesome"]
    print(" ".join(words)) # Python is awesome
    print("-".join(words)) # Python-is-awesome
    print(", ".join(["a", "b", "c"])) # a, b, c

    # partition:分割成三部分 (前, 分隔符, 后)
    print("hello world".partition(" ")) # ('hello', ' ', 'world')
    # rpartition:从右边开始
    print("hello world hello".rpartition(" ")) # ('hello world', ' ', 'hello')

    # — 填充与对齐 —
    print("42".zfill(5)) # 00042 用0填充左侧
    print("hi".ljust(10, "-")) # hi——– 左对齐
    print("hi".rjust(10, "-")) # ——–hi 右对齐
    print("hi".center(10, "-")) # —-hi—- 居中对齐

    🔑 要点总结:这些方法都不会修改原字符串(字符串不可变),而是返回新字符串。特别推荐记住 split()、join()、strip() 和 replace()——它们是日常编程中使用频率最高的字符串方法。

    5.5 字符串格式化

    💡 代码说明:Python 提供了四种字符串格式化方式。f-string(Python 3.6+)是最推荐的,支持表达式嵌入、格式说明符和调试模式:

    name = "Alice"
    age = 25
    pi = 3.1415926

    # 方法1:f-string(Python 3.6+,推荐!)
    print(f"我叫{name},今年{age}岁")
    print(f"π ≈ {pi:.2f}") # π ≈ 3.14
    print(f"{name:>10}") # ' Alice' 右对齐,宽度10
    print(f"{name:*^10}") # '**Alice***' 居中,* 填充
    print(f"{1000000:,}") # 1,000,000 千分位
    print(f"{0.25:.1%}") # 25.0% 百分比
    print(f"{255:#x}") # 0xff 十六进制
    print(f"{age=}") # age=25 (调试模式)

    # 方法2:str.format()
    print("我叫{},今年{}岁".format(name, age))
    print("我叫{0},今年{1}岁,{0}来自北京".format(name, age)) # 按索引
    print("我叫{name},今年{age}岁".format(name="Bob", age=30)) # 按名称

    # 方法3:% 格式化(旧式,不推荐)
    print("我叫%s,今年%d岁" % (name, age))
    print("π ≈ %.2f" % pi)

    # 方法4:format() 内置函数
    print(format(pi, ".2f")) # 3.14

    🔑 要点总结:f-string 不仅最简洁,而且是效率最高的格式化方式。{age=} 调试模式能打印变量名和值,在排查问题时非常方便。

    5.6 字符串不可变性

    💡 代码说明:字符串是不可变类型——不能通过索引直接修改某个字符。正确的做法是创建新字符串:

    s = "Hello"
    # s[0] = "h" # ❌ TypeError: 'str' object does not support item assignment

    # 正确做法:创建新字符串
    s = "h" + s[1:]
    print(s) # "hello"

    🔑 要点总结:理解不可变性有助于理解 Python 的内存模型:每次修改字符串实际都在创建新对象,频繁拼接时推荐用 join() 而非 + 以获得更好性能。


    6. 列表(List)

    列表是 Python 中最常用的可变序列类型,元素可重复,用 [] 表示。

    6.1 创建列表

    💡 代码说明:列表用 [] 或 list() 创建,可以包含任意类型的元素,支持乘法重复和嵌套。但要注意嵌套列表乘法的陷阱:

    # 多种创建方式
    empty = []
    nums = [1, 2, 3, 4, 5]
    mixed = [1, "hello", 3.14, True, [1, 2]] # 可以包含不同类型
    nested = [[1, 2], [3, 4], [5, 6]] # 嵌套列表

    # 用构造函数创建
    chars = list("hello") # ['h', 'e', 'l', 'l', 'o']
    range_list = list(range(5)) # [0, 1, 2, 3, 4]

    # 列表乘法
    zeros = [0] * 5 # [0, 0, 0, 0, 0]

    # ⚠️ 陷阱:嵌套列表乘法
    grid = [[0] * 3] * 3 # 看起来是3×3矩阵
    grid[0][0] = 1
    print(grid) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]] ← 三行指向同一个子列表!

    # ✅ 正确做法
    grid = [[0] * 3 for _ in range(3)]
    grid[0][0] = 1
    print(grid) # [[1, 0, 0], [0, 0, 0], [0, 0, 0]]

    🔑 要点总结:嵌套列表乘法 [[0]*3]*3 会创建指向同一子列表的多个引用——这是一个经典陷阱!正确的做法是使用列表推导式 [[0]*3 for _ in range(3)]。

    6.2 访问与切片

    💡 代码说明:列表的索引和切片语法与字符串完全一致——正向下标从0开始,负向下标从-1开始:

    fruits = ["苹果", "香蕉", "橙子", "葡萄", "西瓜"]

    # 索引
    print(fruits[0]) # 苹果
    print(fruits[1]) # 西瓜

    # 切片(和字符串一样)
    print(fruits[1:3]) # ['香蕉', '橙子']
    print(fruits[::2]) # ['苹果', '橙子', '西瓜']
    print(fruits[::1]) # ['西瓜', '葡萄', '橙子', '香蕉', '苹果'] 反转

    🔑 要点总结:列表切片返回新列表,不影响原列表。fruits[::-1] 可以快速反转列表,而且切片语法适用于所有序列类型。

    6.3 修改列表

    💡 代码说明:列表是可变的——可以修改单个元素、用切片批量替换、删除元素或清空整个列表:

    fruits = ["苹果", "香蕉", "橙子"]

    # 修改元素
    fruits[1] = "草莓"
    print(fruits) # ['苹果', '草莓', '橙子']

    # 用切片批量修改
    fruits[1:3] = ["芒果", "葡萄"]
    print(fruits) # ['苹果', '芒果', '葡萄']

    # 删除元素
    del fruits[0]
    print(fruits) # ['芒果', '葡萄']

    # 清空列表
    fruits.clear()
    print(fruits) # []

    🔑 要点总结:切片赋值 fruits[1:3] = […] 可以一次替换多个元素,替换的元素数量不必相等——这是列表的一大灵活性。

    6.4 列表方法

    💡 代码说明:列表提供了丰富的方法用于添加(append/extend/insert)、删除(remove/pop)、查找(index/count)和排序(sort):

    # — 添加元素 —
    nums = [1, 2, 3]

    nums.append(4) # [1, 2, 3, 4] 末尾添加一个元素
    nums.extend([5, 6, 7]) # [1, 2, 3, 4, 5, 6, 7] 末尾添加多个元素
    nums.insert(0, 0) # [0, 1, 2, 3, 4, 5, 6, 7] 在指定位置插入

    # append vs extend
    a = [1, 2]
    a.append([3, 4])
    print(a) # [1, 2, [3, 4]] ← 整个列表作为一个元素
    b = [1, 2]
    b.extend([3, 4])
    print(b) # [1, 2, 3, 4] ← 元素逐个加入

    # — 删除元素 —
    nums = [1, 2, 3, 2, 4]

    nums.remove(2) # [1, 3, 2, 4] 删除第一个匹配值(找不到则 ValueError)
    popped = nums.pop() # 弹出并返回最后一个元素 → 4; nums = [1, 3, 2]
    popped = nums.pop(1) # 弹出并返回索引1的元素 → 3; nums = [1, 2]
    # del nums[0] # 删除索引0的元素

    # — 查找与统计 —
    nums = [1, 2, 3, 2, 4, 2]

    print(nums.index(2)) # 1 第一个出现的索引(找不到则 ValueError)
    print(nums.index(2, 2)) # 3 从索引2开始查找
    print(nums.count(2)) # 3 统计出现次数
    print(len(nums)) # 6 列表长度

    # — 排序 —
    nums = [3, 1, 4, 1, 5, 9]

    nums.sort() # 原地升序排序 → [1, 1, 3, 4, 5, 9]
    nums.sort(reverse=True) # 原地降序排序 → [9, 5, 4, 3, 1, 1]

    # sorted():返回新列表,不改变原列表
    original = [3, 1, 4, 1, 5]
    sorted_list = sorted(original) # [1, 1, 3, 4, 5]
    print(original) # [3, 1, 4, 1, 5] 不变

    # 自定义排序:按字符串长度
    words = ["apple", "kiwi", "banana", "pear"]
    words.sort(key=len) # ['kiwi', 'pear', 'apple', 'banana']
    words.sort(key=lambda w: w[1]) # 按最后一个字母排序

    # — 其他常用方法 —
    nums = [1, 2, 3]
    nums.reverse() # 原地反转 → [3, 2, 1]
    # 或用切片:reversed_list = nums[::-1]

    nums_copy = nums.copy() # 浅拷贝
    # 等价于 nums_copy = nums[:] 或 list(nums)

    🔑 要点总结:注意 append 和 extend 的关键区别:append 把参数整体作为一个元素加入,extend 则逐个加入。sort() 原地排序,sorted() 返回新列表。

    6.5 浅拷贝 vs 深拷贝

    💡 代码说明:嵌套列表的拷贝需要特别注意——浅拷贝只复制外层引用,深拷贝才会递归复制所有层级:

    import copy

    original = [[1, 2], [3, 4]]

    # 浅拷贝:只复制外层
    shallow = original.copy() # 或 original[:] 或 list(original)
    shallow[0][0] = 99
    print(original) # [[99, 2], [3, 4]] ← 受影响!

    # 深拷贝:递归复制所有层级
    deep = copy.deepcopy(original)
    deep[0][0] = 100
    print(original) # [[99, 2], [3, 4]] ← 不受影响

    🔑 要点总结:对于嵌套结构,使用 copy.deepcopy() 才能做到真正独立的复制。但深拷贝性能开销较大,只在确实需要时使用。

    6.6 enumerate 与 zip

    💡 代码说明:enumerate() 同时获取索引和元素值,zip() 将多个列表打包成一对对元组,是遍历中最常用的两个内置函数:

    fruits = ["苹果", "香蕉", "橙子"]

    # enumerate: 同时获取索引和值
    for i, fruit in enumerate(fruits):
    print(f"{i}: {fruit}")
    # 0: 苹果
    # 1: 香蕉
    # 2: 橙子

    for i, fruit in enumerate(fruits, start=1):
    print(f"{i}: {fruit}")
    # 1: 苹果
    # 2: 香蕉
    # 3: 橙子

    # zip: 同时遍历多个列表
    names = ["Alice", "Bob", "Charlie"]
    ages = [25, 30, 35]

    for name, age in zip(names, ages):
    print(f"{name} 今年 {age} 岁")

    # zip 会在最短的列表结束时停止
    a = [1, 2, 3]
    b = ['a', 'b']
    print(list(zip(a, b))) # [(1, 'a'), (2, 'b')]

    # 需要严格匹配长度?用 zip_longest
    from itertools import zip_longest
    print(list(zip_longest(a, b, fillvalue=None)))
    # [(1, 'a'), (2, 'b'), (3, None)]

    🔑 要点总结:enumerate(seq, start=1) 让序号从1开始,zip() 按最短列表截断,需要严格匹配时用 zip_longest()。


    7. 元组(Tuple)

    元组是不可变序列类型,用 () 表示。一旦创建,不可修改。

    7.1 创建元组

    💡 代码说明:元组用 () 或 tuple() 创建。特别注意:单元素元组必须在元素后加逗号,否则会被当成普通括号表达式:

    t1 = (1, 2, 3)
    t2 = 1, 2, 3 # 逗号创建,括号可省略(不推荐省略)
    t3 = (1,) # ⚠️ 单元素元组必须有逗号!
    t4 = (1) # 这不是元组,是整数1!
    t5 = () # 空元组
    t6 = tuple([1, 2, 3]) # 从其他序列创建
    t7 = tuple("hello") # ('h', 'e', 'l', 'l', 'o')

    🔑 要点总结:(1,) 是元组,(1) 只是整数 1——逗号才是元组的真正标识,括号在很多情况下可以省略。

    7.2 元组的不可变性

    💡 代码说明:元组创建后不能修改——不能赋值、不能添加、不能删除。但如果元组包含可变对象(如列表),该可变对象的内容可以改变:

    t = (1, 2, 3)
    # t[0] = 10 # ❌ TypeError: 'tuple' object does not support item assignment
    # t.append(4) # ❌ AttributeError: 'tuple' object has no attribute 'append'

    # 【注意】如果元组包含可变对象,可变对象的内容可以改!
    t = ([1, 2], 3)
    t[0].append(3)
    print(t) # ([1, 2, 3], 3) 元组本身不变,但内部的列表变了

    🔑 要点总结:元组的不可变指的是引用不可变——元组中存储的每个元素的引用不能改变,但如果这个引用指向一个可变对象,该对象本身还是可以修改的。

    7.3 元组解包

    💡 代码说明:序列解包是 Python 的一大特色,可以一次性将元组(或列表)的元素赋值给多个变量。* 可以收集多余元素:

    # 序列解包(unpacking)
    point = (3, 4)
    x, y = point
    print(x, y) # 3 4

    # 多变量同时赋值(本质是元组打包再解包)
    a, b = 1, 2

    # 交换变量(Python 特有写法)
    a, b = b, a

    # 星号表达式:收集多余元素
    first, *middle, last = [1, 2, 3, 4, 5]
    print(first) # 1
    print(middle) # [2, 3, 4]
    print(last) # 5

    head, *tail = [1, 2, 3]
    print(head) # 1
    print(tail) # [2, 3]

    # 忽略不需要的值(_ 作为占位符)
    _, _, z = (1, 2, 3)
    print(z) # 3

    🔑 要点总结:解包让交换变量 a, b = b, a 变得异常简洁,*middle 收集中间元素、_ 忽略不关心的值——这些都是 Pythonic 的编码风格。

    7.4 为什么使用元组?

  • 不可变性保证数据不会被意外修改
  • 作为字典的键(列表不能)
  • 性能略优于列表
  • 语义表达:暗示这是一组不应修改的数据(如坐标、RGB值)
  • 💡 代码说明:元组不只是「不可变的列表」——它还可以作为字典键、利用 namedtuple 创建轻量数据类:

    # 元组作为字典的键
    scores = {("Alice", "Math"): 95, ("Alice", "English"): 88}
    print(scores[("Alice", "Math")]) # 95

    # namedtuple:带名称的元组
    from collections import namedtuple

    Point = namedtuple("Point", ["x", "y"])
    p = Point(3, 4)
    print(p.x, p.y) # 3 4
    print(p[0], p[1]) # 3 4(仍支持索引访问)
    # p.x = 5 # ❌ 不可修改(和普通元组一样)

    🔑 要点总结:当你有一组不应被修改的数据(如坐标、RGB值、数据库记录)时,元组通过不可变性传达了一组数据的语义。namedtuple 则是轻量数据类的绝佳选择。


    8. 字典(Dictionary)

    字典是键值对的集合,键必须不可变(字符串、数字、元组),{key: value} 表示。Python 3.7+ 字典保持插入顺序。

    8.1 创建与访问

    💡 代码说明:字典是 Python 的核心数据结构,用 {} 或 dict() 创建,有六种创建方式。访问时推荐使用 get() 而非直接索引:

    # 创建字典
    d1 = {"name": "Alice", "age": 25, "city": "北京"}
    d2 = dict(name="Bob", age=30) # 键为字符串时可用
    d3 = dict([("name", "Charlie"), ("age", 35)]) # 从键值对序列创建
    d4 = dict(zip(["a", "b", "c"], [1, 2, 3])) # {'a': 1, 'b': 2, 'c': 3}
    d5 = dict.fromkeys(["a", "b", "c"], 0) # {'a': 0, 'b': 0, 'c': 0}
    d6 = {} # 空字典

    # 访问值
    print(d1["name"]) # Alice
    # print(d1["gender"]) # ❌ KeyError(键不存在时)

    # get():键不存在时返回默认值(推荐!)
    print(d1.get("name")) # Alice
    print(d1.get("gender", "未知")) # 未知(键不存在,返回默认值)

    # setdefault():如果键不存在,设置默认值并返回
    d1.setdefault("score", 0) # 不存在则设置为 0
    print(d1) # {…, 'score': 0}

    🔑 要点总结:get(key, default) 在键不存在时返回默认值而不抛异常;setdefault() 则在键不存在时同时设置默认值——两者都能避免 KeyError。

    8.2 修改字典

    💡 代码说明:字典支持添加、修改、更新、删除和合并操作。Python 3.9+ 还引入了 | 和 |= 字典合并运算符:

    user = {"name": "Alice", "age": 25}

    # 添加/修改
    user["city"] = "上海" # 添加新键
    user["age"] = 26 # 修改已有键
    print(user) # {'name': 'Alice', 'age': 26, 'city': '上海'}

    # update():批量更新
    user.update({"age": 27, "email": "alice@example.com"})
    print(user) # {'name': 'Alice', 'age': 27, 'city': '上海', 'email': 'alice@example.com'}
    # 也可以用 update(key=value, …)
    user.update(phone="123456", country="中国")

    # 删除
    del user["phone"] # 删除指定键(不存在则 KeyError)
    popped = user.pop("email") # 弹出并返回值(不存在则 KeyError)
    popped = user.pop("email", None) # 不存在时返回默认值
    last = user.popitem() # 弹出最后一个键值对(Python 3.7+ LIFO)
    user.clear() # 清空

    # 字典合并(Python 3.9+)
    d1 = {"a": 1, "b": 2}
    d2 = {"b": 3, "c": 4}
    merged = d1 | d2 # {'a': 1, 'b': 3, 'c': 4} 后者覆盖前者
    d1 |= d2 # 原地合并

    🔑 要点总结:pop(key, default) 比 del 更安全。d1 | d2 合并字典时,相同键的值会被 d2 覆盖,非常直观。

    8.3 遍历字典

    💡 代码说明:字典支持遍历键(.keys())、值(.values())和键值对(.items())。遍历时不要直接修改字典大小:

    user = {"name": "Alice", "age": 25, "city": "北京"}

    # 遍历键
    for key in user:
    print(key)

    for key in user.keys():
    print(key)

    # 遍历值
    for value in user.values():
    print(value)

    # 遍历键值对
    for key, value in user.items():
    print(f"{key}: {value}")

    # 安全遍历并修改:先收集再修改
    # ❌ 不要在遍历时修改字典大小
    # for key in user:
    # del user[key] # RuntimeError!

    # ✅ 先收集要删除的键
    to_delete = [key for key in user if key.startswith("a")]
    for key in to_delete:
    del user[key]

    🔑 要点总结:遍历字典时修改其大小会引发 RuntimeError。正确的做法是先收集要删除的键,循环结束后再批量删除。

    8.4 字典推导式

    💡 代码说明:字典推导式用 {key: value for …} 语法快速创建或变换字典,支持条件过滤:

    # {key_expr: value_expr for item in iterable}

    # 平方数字典
    squares = {x: x**2 for x in range(5)}
    print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

    # 交换键值
    original = {"a": 1, "b": 2, "c": 3}
    swapped = {v: k for k, v in original.items()}
    print(swapped) # {1: 'a', 2: 'b', 3: 'c'}

    # 条件过滤
    even_squares = {x: x**2 for x in range(10) if x % 2 == 0}
    print(even_squares) # {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}

    🔑 要点总结:字典推导式比传统的 for 循环更简洁,是 Pythonic 风格的体现。常见用法包括创建映射表、交换键值、过滤特定项等。

    8.5 defaultdict 与 Counter

    💡 代码说明:collections 模块的 defaultdict 和 Counter 是字典的强力扩展,能极大简化分组和统计类代码:

    # — defaultdict: 带默认值的字典 —
    from collections import defaultdict

    # 按类型统计(无需检查键是否存在)
    words = ["apple", "banana", "apple", "orange", "banana", "apple"]
    word_count = defaultdict(int) # int() 返回 0
    for word in words:
    word_count[word] += 1 # 不存在自动初始化为 0
    print(word_count) # defaultdict(<class 'int'>, {'apple': 3, 'banana': 2, 'orange': 1})

    # 分组
    groups = defaultdict(list)
    for word in words:
    groups[len(word)].append(word)
    print(groups) # defaultdict(<class 'list'>, {5: ['apple', 'apple'], 6: ['banana', 'orange', 'banana']})

    # — Counter: 计数器 —
    from collections import Counter

    cnt = Counter(words)
    print(cnt) # Counter({'apple': 3, 'banana': 2, 'orange': 1})
    print(cnt.most_common(2)) # [('apple', 3), ('banana', 2)] 前2个最常见元素
    print(cnt["grape"]) # 0 (不存在的键返回 0)

    🔑 要点总结:defaultdict 省去了检查键是否存在的样板代码;Counter 让频率统计变为一行代码。两者都是日常编程中的高频工具。


    9. 集合(Set)

    集合是无序、不重复元素的集合,用 {} 表示。元素必须不可变。

    9.1 创建集合

    💡 代码说明:集合用 {} 或 set() 创建,元素自动去重且无序。注意:set() 创建空集合,{} 创建的是空字典:

    # 创建集合
    s1 = {1, 2, 3, 4}
    s2 = set([1, 2, 2, 3, 3, 4]) # {1, 2, 3, 4} 自动去重
    s3 = set("hello") # {'h', 'e', 'l', 'o'} l只出现一次
    s4 = set() # 空集合(不能用 {},那是空字典)

    # 集合推导式
    squares = {x**2 for x in range(10)} # {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}

    🔑 要点总结:集合支持推导式,和列表推导式语法类似。因为元素不可变,集合中不能包含列表或字典。

    9.2 集合操作

    💡 代码说明:集合支持数学中的交、并、差、对称差运算,以及子集/超集判断。运算符(| & – ^)和方法效果相同:

    a = {1, 2, 3, 4}
    b = {3, 4, 5, 6}

    # — 数学集合运算 —
    print(a | b) # {1, 2, 3, 4, 5, 6} 并集(a.union(b))
    print(a & b) # {3, 4} 交集(a.intersection(b))
    print(a b) # {1, 2} 差集(a.difference(b))
    print(b a) # {5, 6}
    print(a ^ b) # {1, 2, 5, 6} 对称差集(a.symmetric_difference(b))

    # — 集合关系 —
    print(a <= b) # False a 是 b 的子集?(a.issubset(b))
    print(a >= b) # False a 是 b 的超集?(a.issuperset(b))
    print(a.isdisjoint({7, 8})) # True 没有交集?

    # — 修改方法 —
    s = {1, 2, 3}
    s.add(4) # {1, 2, 3, 4} 添加元素
    s.update([5, 6]) # {1, 2, 3, 4, 5, 6} 批量添加
    s.remove(3) # 删除(元素不存在则 KeyError)
    s.discard(3) # 删除(元素不存在也不报错!推荐)
    s.pop() # 随机弹出一个元素(空集合则 KeyError)
    s.clear() # 清空

    # 集合的原地运算(以 _update 结尾)
    a = {1, 2, 3}
    a.intersection_update({2, 3, 4}) # a 变为 {2, 3}

    🔑 要点总结:原地运算方法(如 intersection_update())以 _update 结尾,直接修改原集合。discard() 比 remove() 更安全——元素不存在时不会报错。

    9.3 集合的应用场景

    💡 代码说明:集合在实际应用中最常见的三个场景:去重、快速成员检查(O(1))、集合运算(找交集/差集)。frozenset 是不可变版本,可作为字典键:

    # 1. 去重
    numbers = [1, 2, 2, 3, 3, 3, 4]
    unique = list(set(numbers)) # [1, 2, 3, 4](顺序不保证)

    # 保持顺序的去重(Python 3.7+)
    unique_ordered = list(dict.fromkeys(numbers)) # [1, 2, 3, 4]

    # 2. 成员检查(O(1) 比列表的 O(n) 快)
    large_set = set(range(1000000))
    print(500000 in large_set) # 非常快

    # 3. 找共同元素
    list1 = [1, 2, 3, 4]
    list2 = [3, 4, 5, 6]
    common = set(list1) & set(list2) # {3, 4}

    # 4. Frozen Set(不可变集合,可作为字典的键)
    fs = frozenset([1, 2, 3])
    # fs.add(4) # ❌ AttributeError
    d = {fs: "frozen"} # ✅ 可以作为键

    🔑 要点总结:当需要频繁判断元素是否存在时,将列表转为集合可以大幅提升性能(从 O(n) 降到 O(1))。保持顺序的去重可以用 dict.fromkeys() 实现。


    10. 条件判断

    10.1 if / elif / else

    💡 代码说明:条件判断是程序流程控制的基础。Python 使用 if-elif-else 结构,注意每个条件后必须有冒号:

    score = 85

    if score >= 90:
    grade = "A"
    elif score >= 80:
    grade = "B"
    elif score >= 70:
    grade = "C"
    elif score >= 60:
    grade = "D"
    else:
    grade = "F"

    print(f"成绩等级: {grade}") # 成绩等级: B

    # 简写(适合简单情况)
    x = 10
    status = "正数" if x > 0 else "非正数"
    # 等价于:
    # if x > 0:
    # status = "正数"
    # else:
    # status = "非正数"

    # 嵌套的三元运算符
    y = 5
    result = "大" if y > 10 else ("小" if y > 0 else "零或负")
    print(result) # 小

    🔑 要点总结:三元表达式 a if condition else b 适合简单的条件赋值。Python 3.10 之前用 elif 链替代 switch-case。

    10.2 真值测试

    Python 中以下值被视为 False(假值),其余为 True:

    💡 代码说明:Python 中以下值被视为假:False、None、各种零值、空序列和空集合。其余所有值都是真。自定义类的真值由 bool() 或 len() 决定:

    # 假值列表
    falsy = [
    False, # 布尔假
    None, # 空值
    0, # 整数零
    0.0, # 浮点零
    0j, # 复数零
    "", # 空字符串
    [], # 空列表
    (), # 空元组
    {}, # 空字典
    set(), # 空集合
    range(0), # 空范围
    ]

    for value in falsy:
    print(f"{value!r:10} -> {bool(value)}")

    # 真值测试在条件判断中的应用
    name = ""
    if name:
    print(f"你好,{name}")
    else:
    print("名称为空") # 输出这个

    # 自定义类的真值:实现 __bool__() 或 __len__() 方法
    class MyCollection:
    def __init__(self, items):
    self.items = items

    def __len__(self):
    return len(self.items)

    c = MyCollection([])
    print(bool(c)) # False

    🔑 要点总结:利用真值测试可以写出简洁的代码:if name: 代替 if name != ‘’,if items: 代替 if len(items) > 0。这是 Pythonic 风格的体现。

    10.3 match / case(Python 3.10+)

    💡 代码说明:Python 3.10 引入的结构化模式匹配 match-case 比传统的 if-elif 更强大——支持多值匹配、序列解构、字典匹配和守卫条件:

    # 类似其他语言的 switch
    def describe(status_code):
    match status_code:
    case 200:
    return "成功"
    case 301 | 302: # 多个值
    return "重定向"
    case 404:
    return "未找到"
    case 500:
    return "服务器错误"
    case _: # 默认(通配符)
    return "未知状态"

    # 结构匹配(更强大的用法)
    def process_point(point):
    match point:
    case (0, 0):
    return "原点"
    case (0, y):
    return f"Y 轴, y={y}"
    case (x, 0):
    return f"X 轴, x={x}"
    case (x, y) if x == y: # 带守卫条件
    return f"在第一/三象限对角线上"
    case (x, y):
    return f"坐标 ({x}, {y})"

    print(process_point((0, 0))) # 原点
    print(process_point((0, 5))) # Y 轴, y=5
    print(process_point((3, 3))) # 在第一/三象限对角线上
    print(process_point((2, 5))) # 坐标 (2, 5)

    # 匹配列表结构
    def analyze_list(lst):
    match lst:
    case []:
    return "空列表"
    case [first, *rest]:
    return f"首元素: {first}, 剩余: {rest}"

    print(analyze_list([1, 2, 3])) # 首元素: 1, 剩余: [2, 3]

    # 匹配字典结构
    def analyze_dict(d):
    match d:
    case {"name": name, "age": age}:
    return f"姓名: {name}, 年龄: {age}"
    case {"name": name}:
    return f"姓名: {name}, 年龄未知"
    case _:
    return "未知格式"

    🔑 要点总结:match-case 不是简单的 switch 替代品——它是真正的模式匹配,能同时匹配结构并绑定变量。特别适合解析复杂数据结构、实现状态机等场景。


    11. 循环语句

    11.1 for 循环

    💡 代码说明:for 循环是 Python 最常用的循环方式,可以遍历列表、字典、range 对象等任何可迭代对象:

    # 遍历列表
    fruits = ["苹果", "香蕉", "橙子"]
    for fruit in fruits:
    print(fruit)

    # 遍历字典
    user = {"name": "Alice", "age": 25}
    for key, value in user.items():
    print(f"{key}: {value}")

    # 遍历范围
    for i in range(5): # 0, 1, 2, 3, 4
    print(i)

    for i in range(2, 7): # 2, 3, 4, 5, 6 (start, stop)
    print(i)

    for i in range(0, 10, 2): # 0, 2, 4, 6, 8 (start, stop, step)
    print(i)

    for i in range(10, 0, 1): # 10, 9, 8, …, 1 倒序
    print(i)

    # 用 enumerate 获取索引
    for i, fruit in enumerate(fruits, start=1):
    print(f"{i}. {fruit}")

    🔑 要点总结:range(start, stop, step) 生成整数序列,enumerate() 同时获取索引和值。Python 的 for 循环简洁而强大。

    11.2 while 循环

    💡 代码说明:while 循环在条件为真时反复执行。适合不知道循环次数的场景,或者实现无限循环+break 的模式:

    # 基本 while 循环
    count = 0
    while count < 5:
    print(count)
    count += 1

    # 使用标志的 while 循环
    running = True
    attempts = 0
    while running:
    attempts += 1
    # … 处理逻辑 …
    if attempts >= 3:
    running = False

    # 无限循环 + break
    while True:
    user_input = input("输入 'quit' 退出: ")
    if user_input == "quit":
    break
    print(f"你输入了: {user_input}")

    🔑 要点总结:注意防止无限循环——确保循环条件最终会变为 False,或者在循环体内使用 break 退出。while True + break 是一种常见的交互式程序模式。

    11.3 循环控制

    💡 代码说明:break 立即退出循环,continue 跳过当前迭代,pass 什么都不做只作占位。for…else 在循环正常结束(非 break 退出)时执行:

    # break:立即退出整个循环
    for i in range(10):
    if i == 5:
    break
    print(i, end=" ") # 0 1 2 3 4

    print() # 换行

    # continue:跳过当前迭代,进入下一次
    for i in range(10):
    if i % 2 == 0:
    continue
    print(i, end=" ") # 1 3 5 7 9

    print()

    # pass:占位符,什么都不做
    for i in range(5):
    if i == 2:
    pass # 以后再来处理
    print(i, end=" ") # 0 1 2 3 4

    print()

    # for … else:循环正常结束时执行 else
    for i in range(5):
    print(i)
    else:
    print("循环正常结束") # 会执行

    for i in range(5):
    if i == 3:
    break
    else:
    print("不会执行") # ← break 后不执行 else

    # while … else 同样适用
    n = 0
    while n < 5:
    n += 1
    else:
    print("while 正常结束") # 执行

    🔑 要点总结:for…else 是 Python 特有的语法,特别适合搜索-未找到的模式:在循环中找到目标就 break,else 块处理未找到的情况。

    11.4 循环技巧

    💡 代码说明:利用 zip() 同时遍历多个序列、reversed() 反向遍历、sorted() 按排序遍历——这些技巧让你的循环代码更优雅:

    # 遍历两个序列(zip)
    names = ["Alice", "Bob", "Charlie"]
    scores = [95, 87, 92]
    for name, score in zip(names, scores):
    print(f"{name}: {score}分")

    # 反向遍历
    for i in reversed(range(5)):
    print(i, end=" ") # 4 3 2 1 0
    print()

    # 排序遍历
    nums = [3, 1, 4, 1, 5]
    for n in sorted(nums):
    print(n, end=" ") # 1 1 3 4 5
    print()

    for n in sorted(nums, reverse=True):
    print(n, end=" ") # 5 4 3 1 1
    print()

    🔑 要点总结:掌握这些内置函数,可以大幅减少循环中的索引操作,写出更 Pythonic 的代码。


    12. 函数

    12.1 定义与调用

    💡 代码说明:使用 def 关键字定义函数,return 返回值。函数文档字符串(docstring)用三引号书写,可通过 doc 或 help() 查看:

    # 基本函数
    def greet(name):
    """向指定的人打招呼(函数文档字符串)"""
    return f"你好,{name}!"

    print(greet("Alice")) # 你好,Alice!
    print(greet.__doc__) # 向指定的人打招呼(函数文档字符串)
    help(greet) # 返回更详细的信息

    # 多个参数
    def add(a, b):
    return a + b

    # 无返回值:默认返回 None
    def log_message(msg):
    print(f"[LOG] {msg}")
    # 隐式 return None

    result = log_message("test")
    print(result) # None

    🔑 要点总结:Python 函数如果没有显式 return,默认返回 None。养成写 docstring 的好习惯,它能被 IDE 和 help() 识别。

    12.2 参数类型

    💡 代码说明:Python 函数支持四种参数类型:位置参数、默认参数、*args(可变位置参数)、**kwargs(可变关键字参数)。参数顺序必须严格按照这个顺序:

    # — 位置参数 —
    def power(base, exp):
    return base ** exp

    print(power(2, 3)) # 8(位置参数)
    print(power(exp=3, base=2)) # 8(关键字参数)

    # — 默认参数 —
    def greet(name, greeting="你好"):
    return f"{greeting}{name}!"

    print(greet("Alice")) # 你好,Alice!
    print(greet("Bob", "早上好")) # 早上好,Bob!

    # ⚠️ 默认参数的陷阱:不要用可变对象作为默认值!
    def bad_append(item, lst=[]):
    lst.append(item)
    return lst

    print(bad_append(1)) # [1]
    print(bad_append(2)) # [1, 2] ← 累积了!默认列表是函数定义时创建的,每次调用共享

    # ✅ 正确做法
    def good_append(item, lst=None):
    if lst is None:
    lst = []
    lst.append(item)
    return lst

    # — 可变参数 *args(位置参数) —
    def my_sum(*args):
    """接受任意数量的位置参数"""
    total = 0
    for num in args:
    total += num
    return total

    print(my_sum(1, 2)) # 3
    print(my_sum(1, 2, 3, 4, 5)) # 15
    print(my_sum()) # 0

    # — 可变参数 **kwargs(关键字参数) —
    def print_info(**kwargs):
    """接受任意数量的关键字参数"""
    for key, value in kwargs.items():
    print(f"{key}: {value}")

    print_info(name="Alice", age=25, city="北京")
    # name: Alice
    # age: 25
    # city: 北京

    # — 所有参数类型组合 —
    def all_params(pos1, pos2, *args, default="默认值", **kwargs):
    """
    参数顺序(必须严格遵守):
    1. 位置参数(必填)
    2. *args(可变位置)
    3. 默认参数(关键字参数)
    4. **kwargs(可变关键字)
    """

    print(f"pos1: {pos1}")
    print(f"pos2: {pos2}")
    print(f"args: {args}")
    print(f"default: {default}")
    print(f"kwargs: {kwargs}")

    all_params(1, 2, 3, 4, 5, default="自定义", name="Alice", age=25)

    🔑 要点总结:最常见的陷阱是可变默认参数(如 def f(lst=[]))——默认值在函数定义时只创建一次,多次调用会共享!正确做法是用 None 作默认值,函数内再初始化。

    12.3 仅限关键字参数

    💡 代码说明:在参数列表中使用 * 可以强制后面的参数必须以关键字形式传递,提高代码可读性。/ 则相反,强制前面的参数只能按位置传递:

    # * 之后的参数必须以关键字形式传递
    def config(host, *, port=8080, debug=False):
    print(f"host={host}, port={port}, debug={debug}")

    config("localhost") # host=localhost, port=8080, debug=False
    config("localhost", port=3000) # ✅
    config("localhost", debug=True) # ✅
    # config("localhost", 3000) # ❌ TypeError: 位置参数太多了

    # 仅限位置参数(Python 3.8+)/ 之前的参数只能按位置传递
    def func(a, b, /, c, d):
    """
    a, b: 仅限位置参数(不能以关键字形式传递)
    c, d: 可以是位置或关键字
    """

    print(f"a={a}, b={b}, c={c}, d={d}")

    func(1, 2, 3, 4) # ✅
    func(1, 2, c=3, d=4) # ✅
    # func(a=1, b=2, c=3, d=4) # ❌ TypeError: a 和 b 仅限位置

    🔑 要点总结:仅限关键字参数让 API 设计更清晰——调用者必须显式写出参数名,减少参数顺序出错的可能。

    12.4 参数解包

    💡 代码说明:* 将列表/元组解包为位置参数,** 将字典解包为关键字参数。两种解包可以组合使用:

    # 列表/元组解包为位置参数
    def add(a, b, c):
    return a + b + c

    nums = [1, 2, 3]
    print(add(*nums)) # 6 等价于 add(1, 2, 3)
    print(add(*(4, 5, 6))) # 15

    # 字典解包为关键字参数
    def greet(name, age):
    return f"{name} 今年 {age} 岁"

    info = {"name": "Alice", "age": 25}
    print(greet(**info)) # Alice 今年 25 岁

    # 组合使用
    def full_func(a, b, c, d, e):
    return a + b + c + d + e

    nums1 = [1, 2]
    nums2 = {"d": 4, "e": 5}
    print(full_func(*nums1, 3, **nums2)) # 15

    🔑 要点总结:参数解包让你能动态地构建函数调用,在编写通用工具函数和转发调用时特别有用。

    12.5 作用域与 global / nonlocal

    💡 代码说明:Python 变量遵循 LEGB 查找规则(Local -> Enclosing -> Global -> Built-in)。使用 global 在函数内修改全局变量,nonlocal 修改外层函数的变量:

    # — LEGB 规则(变量查找顺序)—
    # L: Local — 函数内部
    # E: Enclosing — 外层函数内部
    # G: Global — 模块级别
    # B: Built-in — 内置命名空间

    x = "global" # 全局变量

    def outer():
    x = "enclosing" # 闭包变量

    def inner():
    x = "local" # 局部变量
    print(f"inner: {x}") # local

    inner()
    print(f"outer: {x}") # enclosing

    outer()
    print(f"global: {x}") # global

    # — global 关键字:在函数内修改全局变量 —
    count = 0

    def increment():
    global count
    count += 1

    increment()
    print(count) # 1

    # — nonlocal 关键字:修改外层函数的变量 —
    def make_counter():
    count = 0

    def counter():
    nonlocal count # 使用外层的 count
    count += 1
    return count

    return counter

    c = make_counter()
    print(c()) # 1
    print(c()) # 2
    print(c()) # 3

    🔑 要点总结:尽量避免滥用 global——它会让代码难以理解和测试。nonlocal 在闭包中很有用,能让内部函数修改外层函数的局部变量。

    12.6 闭包

    💡 代码说明:闭包是函数式编程的核心概念——内部函数记住并访问其创建时的外层变量,即使外层函数已经返回:

    # 闭包:内部函数记住了其创建时的环境
    def make_multiplier(factor):
    def multiplier(x):
    return x * factor # factor 被"记住"了
    return multiplier

    double = make_multiplier(2)
    triple = make_multiplier(3)

    print(double(5)) # 10
    print(triple(5)) # 15

    # 查看闭包变量
    print(double.__closure__[0].cell_contents) # 2

    🔑 要点总结:闭包是实现装饰器、工厂函数和回调的基础。closure 属性可以查看闭包捕获的变量,有助于调试。


    13. Lambda 表达式

    Lambda 是创建小型匿名函数的语法,只能包含单个表达式。

    💡 代码说明:闭包是函数式编程的核心概念——内部函数记住并访问其创建时的外层变量,即使外层函数已经返回:

    # 语法: lambda 参数: 表达式

    # 基本用法
    add = lambda a, b: a + b
    print(add(3, 5)) # 8

    # 等价于
    def add(a, b):
    return a + b

    # — 常见使用场景 —
    # 1. sort() 的 key 参数
    students = [
    {"name": "Alice", "score": 85},
    {"name": "Bob", "score": 92},
    {"name": "Charlie", "score": 78},
    ]
    students.sort(key=lambda s: s["score"], reverse=True)
    print(students)
    # [{'name': 'Bob', 'score': 92}, {'name': 'Alice', 'score': 85}, {'name': 'Charlie', 'score': 78}]

    # 2. filter():过滤序列
    nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    even = list(filter(lambda x: x % 2 == 0, nums))
    print(even) # [2, 4, 6, 8, 10]

    # 3. map():映射序列
    squared = list(map(lambda x: x ** 2, nums))
    print(squared) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

    # 4. reduce():累积(需要导入)
    from functools import reduce
    total = reduce(lambda acc, x: acc + x, nums)
    print(total) # 55

    # — Lambda vs 列表推导式 —
    # 大部分情况下列表推导式更 Pythonic:

    # 用 filter + lambda
    even1 = list(filter(lambda x: x % 2 == 0, nums))

    # 用列表推导式(推荐!)
    even2 = [x for x in nums if x % 2 == 0]

    # 用 map + lambda
    squared1 = list(map(lambda x: x ** 2, nums))

    # 用列表推导式(推荐!)
    squared2 = [x ** 2 for x in nums]

    🔑 要点总结:闭包是实现装饰器、工厂函数和回调的基础。closure 属性可以查看闭包捕获的变量,有助于调试。


    14. 列表推导式与生成器表达式

    14.1 列表推导式

    💡 代码说明:列表推导式是 Python 的标志性特性,用 [expression for item in iterable if condition] 语法在一行内完成映射和过滤:

    # 基本语法: [expression for item in iterable if condition]

    nums = list(range(10))

    # 基本
    squares = [x ** 2 for x in nums]
    print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

    # 带条件过滤
    even_squares = [x ** 2 for x in nums if x % 2 == 0]
    print(even_squares) # [0, 4, 16, 36, 64]

    # if-else 表达式(注意位置)
    parity = ["even" if x % 2 == 0 else "odd" for x in nums]
    print(parity) # ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']

    # 嵌套推导式
    # 展平二维列表
    matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    flattened = [num for row in matrix for num in row]
    print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9]

    # 等价于
    flattened = []
    for row in matrix:
    for num in row:
    flattened.append(num)

    # 笛卡尔积
    pairs = [(x, y) for x in range(3) for y in range(3)]
    print(pairs)
    # [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

    🔑 要点总结:列表推导式比传统的 for+append 更简洁高效(底层是 C 实现的)。但不要过度嵌套——超过两层的推导式会牺牲可读性。

    14.2 生成器表达式

    💡 代码说明:生成器表达式语法和列表推导式一样,只是用 () 替代 []。它惰性求值,适合处理海量数据:

    # 语法和列表推导式一样,只是用 () 而不是 []
    # 优势:惰性求值,节省内存(适合海量数据)

    # 列表推导式:立即生成所有数据到内存
    squares_list = [x ** 2 for x in range(1000000)] # 占用大量内存

    # 生成器表达式:按需生成,几乎不占内存
    squares_gen = (x ** 2 for x in range(1000000)) # 轻量级

    # 迭代生成器
    for i in squares_gen:
    print(i)
    if i > 50:
    break # 只计算需要的部分

    # sum/max/min 等可以直接接受生成器表达式
    total = sum(x ** 2 for x in range(1000000)) # 不需要再写一层括号
    print(total)

    🔑 要点总结:当数据量很大(百万级)时,生成器表达式几乎不占内存。传递给 sum()、max() 等函数时,可以省略额外的括号。

    14.3 字典推导式

    💡 代码说明:字典推导式 {key: value for …} 快速创建或变换字典,是从两个列表创建映射表的绝佳方式:

    # {key_expr: value_expr for item in iterable if condition}

    # 基本
    squares = {x: x**2 for x in range(5)}
    print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

    # 过滤
    even_squares = {x: x**2 for x in range(10) if x % 2 == 0}
    print(even_squares) # {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}

    # 从两个列表创建字典
    keys = ["name", "age", "city"]
    values = ["Alice", 25, "北京"]
    info = {k: v for k, v in zip(keys, values)}
    print(info) # {'name': 'Alice', 'age': 25, 'city': '北京'}

    🔑 要点总结:结合 zip() 使用字典推导式,可以一行代码将两个列表变为字典。支持条件过滤,语法与列表推导式一致。

    14.4 集合推导式

    💡 代码说明:集合推导式 {expr for …} 自动去重,本质上就是花括号包裹的列表推导式:

    # {expression for item in iterable if condition}

    # 基本
    squares_set = {x**2 for x in range(5, 6)}
    print(squares_set) # {0, 1, 4, 9, 16, 25} 自动去重

    # 字符串去重并保持顺序(用字典推导式)
    text = "abracadabra"
    unique_chars = "".join(dict.fromkeys(text))
    print(unique_chars) # "abrcd"

    🔑 要点总结:集合推导式在需要去重的同时做变换时非常有用,比先建列表再转集合更高效。


    15. 迭代器与生成器

    15.1 可迭代对象 vs 迭代器

    💡 代码说明:可迭代对象(Iterable)可以放进 for 循环,迭代器(Iterator)则是记住遍历位置的懒加载对象。用 iter() 从可迭代对象获取迭代器,next() 逐个取值:

    # 可迭代对象 (Iterable):实现了 __iter__() 方法
    # 迭代器 (Iterator):实现了 __iter__() 和 __next__() 方法

    # 判断类型
    from collections.abc import Iterable, Iterator

    lst = [1, 2, 3]
    print(isinstance(lst, Iterable)) # True (列表是可迭代对象)
    print(isinstance(lst, Iterator)) # False (列表不是迭代器)

    it = iter(lst)
    print(isinstance(it, Iterator)) # True

    # iter() 和 next()
    it = iter(lst)
    print(next(it)) # 1
    print(next(it)) # 2
    print(next(it)) # 3
    # print(next(it)) # StopIteration 异常

    🔑 要点总结:迭代器只能前进不能后退,遍历结束后再调用 next() 会抛出 StopIteration。这种一次性的特性让迭代器非常节省内存。

    15.2 生成器函数(yield)

    💡 代码说明:使用 yield 关键字的函数是生成器——每次 yield 暂停并返回值,下次调用 next() 时从暂停处继续。yield from 可以委托给子生成器:

    # yield:暂停函数,返回值,下次从暂停处继续

    # 基本生成器
    def countdown(n):
    print(f"开始倒计时: {n}")
    while n > 0:
    yield n
    n -= 1
    print("结束!")

    for num in countdown(3):
    print(f"倒计时: {num}")
    # 开始倒计时: 3
    # 倒计时: 3
    # 倒计时: 2
    # 倒计时: 1
    # 结束!

    # — 无限序列生成器 —
    def fibonacci():
    """生成无限的斐波那契数列"""
    a, b = 0, 1
    while True:
    yield a
    a, b = b, a + b

    fib = fibonacci()
    print([next(fib) for _ in range(10)])
    # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

    # — yield from: 委托给子生成器 —
    def flat_list(nested):
    """递归展平任意嵌套的列表"""
    for item in nested:
    if isinstance(item, list):
    yield from flat_list(item) # Python 3.3+
    else:
    yield item

    nested = [1, [2, 3], [4, [5, 6]]]
    print(list(flat_list(nested))) # [1, 2, 3, 4, 5, 6]

    # — 管道生成器 —
    def read_lines(filename):
    """逐行读取文件"""
    with open(filename, "r", encoding="utf-8") as f:
    for line in f:
    yield line.strip()

    def filter_comments(lines):
    """过滤注释行"""
    for line in lines:
    if not line.startswith("#"):
    yield line

    # 使用
    # valid_lines = filter_comments(read_lines("config.txt"))
    # for line in valid_lines:
    # print(line)

    🔑 要点总结:生成器是实现流式处理、惰性计算的利器。yield from 在需要递归处理嵌套结构时特别有用,比如展平任意深度的嵌套列表。

    15.3 send() 与双向通信

    💡 代码说明:生成器不仅可以通过 yield 向外产出值,还可以通过 send() 接收外部传入的值,实现双向通信(协程的基础):

    # 生成器不仅可以产出值,还可以通过 send() 接收值
    def running_average():
    """维持运行平均值的协程"""
    total = 0
    count = 0
    average = None
    while True:
    # yield 的返回值是通过 send() 传入的值
    x = yield average
    if x is None:
    break
    total += x
    count += 1
    average = total / count

    avg = running_average()
    next(avg) # 启动生成器(推进到第一个 yield)
    print(avg.send(10)) # 10.0
    print(avg.send(20)) # 15.0
    print(avg.send(30)) # 20.0
    avg.close() # 关闭生成器

    🔑 要点总结:send() 让生成器升级为协程。首次调用必须用 next() 或 send(None) 启动。用完后调用 close() 关闭生成器释放资源。


    16. 装饰器

    装饰器是一种在不修改原函数代码的情况下增强其功能的设计模式。

    16.1 函数是一等公民

    💡 代码说明:在 Python 中,函数是一等公民——可以赋值给变量、作为参数传递、作为返回值返回。这是理解装饰器的基础:

    # Python 中函数是对象,可以赋给变量、作为参数、作为返回值
    def greet(name):
    return f"Hello, {name}"

    # 赋值给变量
    say_hello = greet
    print(say_hello("Alice")) # Hello, Alice

    # 作为参数传递
    def call_twice(func, arg):
    return func(arg), func(arg)

    print(call_twice(greet, "Bob")) # ('Hello, Bob', 'Hello, Bob')

    # 作为返回值(内部函数/闭包)
    def make_greeting(prefix):
    def greeting(name):
    return f"{prefix}, {name}"
    return greeting

    hello = make_greeting("Hello")
    print(hello("Charlie")) # Hello, Charlie

    🔑 要点总结:正因为函数是一等公民,Python 才能优雅地实现装饰器、回调、高阶函数等函数式编程模式。

    16.2 基本装饰器

    💡 代码说明:装饰器本质上是一个接受函数、返回新函数的包装器。使用 @decorator 语法糖,@functools.wraps 保留原函数的元信息:

    import functools
    import time

    # — 装饰器模式 —
    def timer(func):
    """记录函数执行时间的装饰器"""
    @functools.wraps(func) # 保留原函数的元信息
    def wrapper(*args, **kwargs):
    start = time.perf_counter()
    result = func(*args, **kwargs)
    elapsed = time.perf_counter() start
    print(f"{func.__name__} 执行耗时: {elapsed:.4f} 秒")
    return result
    return wrapper

    # 使用装饰器(语法糖)
    @timer
    def slow_function(n):
    """一个耗时的函数"""
    total = sum(i ** 2 for i in range(n))
    return total

    # 等价于: slow_function = timer(slow_function)
    slow_function(1000000) # slow_function 执行耗时: 0.1234 秒

    print(slow_function.__name__) # slow_function(被 @wraps 保留了)
    print(slow_function.__doc__) # 一个耗时的函数

    # 不带 @wraps 的话 __name__ 会变成 "wrapper"

    🔑 要点总结:@functools.wraps(func) 至关重要——没有它,被装饰函数的 name 和 doc 会变成 wrapper 的信息。这是装饰器最常见也最容易忘记的细节。

    16.3 带参数的装饰器

    💡 代码说明:带参数的装饰器本质上是装饰器工厂——外层函数接收参数,返回真正的装饰器:

    # 装饰器工厂:返回装饰器的函数
    def retry(max_attempts=3, delay=1):
    """重试装饰器:函数失败后自动重试"""
    def decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
    for attempt in range(1, max_attempts + 1):
    try:
    return func(*args, **kwargs)
    except Exception as e:
    if attempt == max_attempts:
    raise # 最后一次尝试仍然失败则抛出异常
    print(f"[重试 {attempt}/{max_attempts}] {e}")
    time.sleep(delay)
    return None
    return wrapper
    return decorator

    @retry(max_attempts=3, delay=0.5)
    def unstable_network_call():
    import random
    if random.random() < 0.7:
    raise ConnectionError("网络连接失败")
    return "成功"

    # 尝试调用
    # result = unstable_network_call()
    # print(result)

    🔑 要点总结:装饰器工厂比基本装饰器多一层嵌套。理解装饰器本质上是函数调用这一点,就不会对三层嵌套感到困惑。

    16.4 常用装饰器

    💡 代码说明:Python 内置了三个常用装饰器:@staticmethod(静态方法)、@classmethod(类方法)和 @property(属性访问控制)。@property 让你能用属性语法调用方法,同时保留验证逻辑:

    # — @staticmethod: 静态方法 —
    class MyClass:
    @staticmethod
    def helper():
    """不需要访问 self 或 cls"""
    return "I'm a static method"

    # — @classmethod: 类方法 —
    class Person:
    species = "Homo sapiens"

    def __init__(self, name):
    self.name = name

    @classmethod
    def from_birth_year(cls, name, birth_year):
    """工厂方法"""
    return cls(f"{name} ({2026 birth_year}岁)")

    @classmethod
    def get_species(cls):
    return cls.species

    # — @property: 属性装饰器 —
    class Circle:
    def __init__(self, radius):
    self._radius = radius

    @property
    def radius(self):
    """getter"""
    return self._radius

    @radius.setter
    def radius(self, value):
    """setter: 设置时添加验证"""
    if value < 0:
    raise ValueError("半径不能为负数")
    self._radius = value

    @radius.deleter
    def radius(self):
    """deleter"""
    del self._radius

    @property
    def area(self):
    """只读计算属性"""
    return 3.14159 * self._radius ** 2

    c = Circle(5)
    print(c.radius) # 5(调用 getter,不需要 c.radius())
    print(c.area) # 78.53975
    c.radius = 10 # 调用 setter(带验证)
    # c.radius = -1 # 抛出 ValueError

    🔑 要点总结:@property 是 Python 实现 getter/setter 的优雅方式——外部代码用 obj.attr 访问,内部自动调用相应方法。@classmethod 常用于实现工厂方法。


    17. 模块与包

    17.1 模块导入

    💡 代码说明:Python 的模块系统通过 import 导入外部代码,支持多种导入方式和条件导入:

    # — 导入方式 —
    # 1. 导入整个模块
    import math
    print(math.sqrt(16)) # 4.0

    # 2. 导入模块并起别名
    import numpy as np
    # arr = np.array([1, 2, 3])

    # 3. 从模块导入特定函数/类
    from math import sqrt, pi
    print(sqrt(25)) # 5.0
    print(pi) # 3.141592…

    # 4. 从模块导入全部(不推荐,会污染命名空间)
    # from math import *

    # 5. 条件导入
    try:
    import ujson as json # 如果装了更快的版本
    except ImportError:
    import json # 使用标准库

    # — 模块搜索路径 —
    import sys
    print(sys.path) # 模块搜索路径列表

    # — 查看模块内容 —
    import math
    print(dir(math)) # 列出模块所有属性和方法
    print(math.__doc__) # 模块文档
    # help(math) # 在 REPL 中查看帮助

    🔑 要点总结:推荐用 import module 或 from module import specific_item,避免 from module import *(会污染命名空间)。条件导入让代码在不同环境下自动适配。

    17.2 包的结构

    💡 代码说明:包是包含 init.py 的目录,用于组织多个模块。init.py 中可以定义 all 控制导出、导入子模块方便用户使用:

    # 包是一个包含 __init__.py 文件的目录

    # 典型包结构:
    # my_package/
    # ├── __init__.py # 包的初始化文件
    # ├── core.py # 核心模块
    # ├── utils/
    # │ ├── __init__.py
    # │ ├── helpers.py
    # │ └── validators.py
    # └── tests/
    # ├── __init__.py
    # └── test_core.py

    # — __init__.py 示例 —
    """
    my_package 包初始化
    """

    # 控制 from my_package import * 导出的内容
    __all__ = ["core_func", "utils"]

    # 可在此处导入子模块,方便用户
    from .core import core_func
    from . import utils

    # 包的版本
    __version__ = "1.0.0"

    🔑 要点总结:即使 init.py 为空文件也没关系,它的存在标志着该目录是一个 Python 包(Python 3.3+ 的隐式命名空间包除外)。

    17.3 相对导入与绝对导入

    💡 代码说明:在包内部,使用 .(当前目录)和 …(上级目录)进行相对导入。绝对导入从项目根目录开始:

    # — 在包内部,使用相对导入 —
    # 文件: my_package/utils/helpers.py

    # 相对导入: . 表示当前目录,.. 表示上级目录
    # from . import validators # 同目录
    # from ..core import core_func # 上级目录的 core 模块

    # 绝对导入: 从顶层开始
    # from my_package.core import core_func

    🔑 要点总结:包内部推荐使用相对导入(更灵活、不依赖项目名),对外公开的 API 使用绝对导入。

    17.4 常用标准库模块

    💡 代码说明:Python 标准库极其丰富,覆盖了操作系统接口、日期时间、JSON 处理、正则表达式、高级集合类和迭代工具等:

    # — os: 操作系统接口 —
    import os
    print(os.name) # 'nt' (Windows) 或 'posix' (Linux/Mac)
    print(os.getcwd()) # 当前工作目录
    # os.listdir(".") # 列出目录内容
    # os.mkdir("new_dir") # 创建目录
    # os.remove("file.txt") # 删除文件
    print(os.path.join("dir", "subdir", "file.txt")) # 跨平台路径拼接
    print(os.path.exists("some_file.txt")) # 文件是否存在
    print(os.path.dirname("/path/to/file.txt")) # /path/to
    print(os.path.basename("/path/to/file.txt")) # file.txt

    # — sys: 系统相关 —
    import sys
    print(sys.version) # Python 版本
    print(sys.argv) # 命令行参数
    # sys.exit(0) # 退出程序

    # — random: 随机数 —
    import random
    print(random.random()) # [0.0, 1.0) 的随机浮点数
    print(random.randint(1, 10)) # [1, 10] 的随机整数
    print(random.choice([1, 2, 3])) # 随机选择一个元素
    print(random.sample(range(100), 5)) # 随机选择5个不重复的元素
    random.shuffle([1, 2, 3, 4, 5]) # 原地打乱列表
    random.seed(42) # 设置随机种子(可复现)

    # — datetime: 日期时间 —
    from datetime import datetime, timedelta, date

    now = datetime.now()
    print(now) # 2026-07-21 14:30:00.123456
    print(now.strftime("%Y-%m-%d %H:%M:%S")) # 2026-07-21 14:30:00
    parsed = datetime.strptime("2026-07-21", "%Y-%m-%d")
    print(parsed) # 2026-07-21 00:00:00

    tomorrow = now + timedelta(days=1)
    last_week = now timedelta(weeks=1)
    print(tomorrow)
    print(last_week)

    # — json: JSON 处理 —
    import json

    data = {"name": "Alice", "age": 25, "skills": ["Python", "JavaScript"]}
    json_str = json.dumps(data, indent=2, ensure_ascii=False)
    print(json_str)
    parsed = json.loads(json_str)
    print(parsed["name"]) # Alice

    # — re: 正则表达式 —
    import re

    text = "联系方式: alice@example.com, bob_123@gmail.com"
    emails = re.findall(r'[\\w.+-]+@[\\w-]+\\.[\\w.-]+', text)
    print(emails) # ['alice@example.com', 'bob_123@gmail.com']

    # — collections: 更多集合类型 —
    from collections import Counter, defaultdict, OrderedDict, deque
    # Counter / defaultdict 已在前面介绍

    # deque: 双端队列(高效的两端操作)
    dq = deque([1, 2, 3])
    dq.append(4) # 右边添加 → deque([1, 2, 3, 4])
    dq.appendleft(0) # 左边添加 → deque([0, 1, 2, 3, 4])
    dq.pop() # 右边弹出 → 4
    dq.popleft() # 左边弹出 → 0

    # — itertools: 迭代器工具 —
    import itertools

    # 无限迭代器
    print(list(itertools.islice(itertools.count(10, 2), 5))) # [10, 12, 14, 16, 18]
    print(list(itertools.islice(itertools.cycle("ABC"), 6))) # ['A', 'B', 'C', 'A', 'B', 'C']

    # 组合迭代器
    print(list(itertools.product("AB", "12"))) # [('A', '1'), ('A', '2'), ('B', '1'), ('B', '2')]
    print(list(itertools.permutations("ABC", 2))) # 排列: 6种
    print(list(itertools.combinations("ABC", 2))) # 组合: 3种
    print(list(itertools.combinations_with_replacement("ABC", 2))) # 有放回组合

    # 过滤迭代器
    print(list(itertools.compress("ABCD", [1, 0, 1, 0]))) # ['A', 'C']
    print(list(itertools.dropwhile(lambda x: x < 3, [1, 2, 3, 4, 1, 2]))) # [3, 4, 1, 2]
    print(list(itertools.takewhile(lambda x: x < 3, [1, 2, 3, 4, 1, 2]))) # [1, 2]

    # 分组
    data = [("a", 1), ("a", 2), ("b", 3), ("b", 4)]
    for key, group in itertools.groupby(data, lambda x: x[0]):
    print(key, "->", list(group))
    # a -> [('a', 1), ('a', 2)]
    # b -> [('b', 3), ('b', 4)]

    # — functools: 高阶函数 —
    from functools import reduce, partial, lru_cache

    # partial: 固定部分参数
    def power(base, exp):
    return base ** exp

    square = partial(power, exp=2) # 固定 exp=2
    cube = partial(power, exp=3) # 固定 exp=3
    print(square(5)) # 25
    print(cube(5)) # 125

    # lru_cache: 缓存函数结果(记忆化)
    @lru_cache(maxsize=128)
    def fibonacci(n):
    """计算斐波那契数(带缓存)"""
    if n < 2:
    return n
    return fibonacci(n 1) + fibonacci(n 2)

    print(fibonacci(100)) # 354224848179261915075(瞬间计算)
    print(fibonacci.cache_info()) # CacheInfo(hits=98, misses=101, maxsize=128, currsize=101)

    🔑 要点总结:标准库是 Python 的一大优势——自带电池。itertools 和 collections 是提高代码效率的两大利器,pathlib 是处理文件路径的现代化选择,建议优先使用。


    18. 文件操作

    18.1 基本读写

    💡 代码说明:使用 open() 打开文件,配合 with 语句确保自动关闭。支持多种读取方式(全部、分块、单行、所有行、逐行迭代)和文件模式:

    # — 写入文件 —
    # 模式: 'w' (写), 'a' (追加), 'x' (排他创建)
    with open("example.txt", "w", encoding="utf-8") as f:
    f.write("Hello, World!\\n")
    f.write("这是第二行。\\n")
    f.writelines(["第三行\\n", "第四行\\n"])

    # — 读取文件 —
    # 模式: 'r' (读,默认)
    with open("example.txt", "r", encoding="utf-8") as f:
    # 方式1: 读取全部
    content = f.read()
    print(content)

    with open("example.txt", "r", encoding="utf-8") as f:
    # 方式2: 读取指定字符数
    chunk = f.read(10)
    print(chunk) # Hello, Wor

    with open("example.txt", "r", encoding="utf-8") as f:
    # 方式3: 读取单行
    line = f.readline()
    print(line) # Hello, World!

    with open("example.txt", "r", encoding="utf-8") as f:
    # 方式4: 读取所有行到列表
    lines = f.readlines()
    print(lines) # ['Hello, World!\\n', '这是第二行。\\n', …]

    with open("example.txt", "r", encoding="utf-8") as f:
    # 方式5: 逐行迭代(推荐,内存友好)
    for line in f:
    print(line.strip())

    # — 文件模式 —
    # 'r' – 只读(文件必须存在)
    # 'w' – 只写(文件存在则清空,不存在则创建)
    # 'a' – 追加(文件存在则在末尾添加)
    # 'x' – 排他创建(文件已存在则失败)
    # 'r+' – 读写
    # 'b' – 二进制模式(如 'rb', 'wb')
    # 't' – 文本模式(默认,如 'rt', 'wt')

    🔑 要点总结:逐行迭代(for line in f)是最推荐的大文件读取方式——不会一次性将整个文件加载到内存。始终使用 encoding=‘utf-8’ 避免编码问题。

    18.2 上下文管理器(with 语句)

    💡 代码说明:with 语句确保资源(如文件)在使用后自动释放,即使发生异常也不会泄漏。它等价于 try/finally 的语法糖:

    # with 语句确保文件正确关闭,即使发生异常
    # 等价于:
    # f = open("file.txt")
    # try:
    # data = f.read()
    # finally:
    # f.close()

    with open("example.txt", "r", encoding="utf-8") as f:
    data = f.read()
    # 文件在这里自动关闭(离开 with 块时)

    # 同时操作多个文件
    with open("source.txt", "r", encoding="utf-8") as src, \\
    open("dest.txt", "w", encoding="utf-8") as dst:
    dst.write(src.read())

    🔑 要点总结:任何需要获取-使用-释放模式的资源(文件、锁、连接)都应使用 with 语句,这是 Python 资源管理的最佳实践。

    18.3 文件与目录操作

    💡 代码说明:os 和 shutil 模块提供了文件和目录的增删改查操作。Python 3.4+ 的 pathlib.Path 提供了更面向对象的路径操作方式:

    import os
    import shutil

    # — 文件操作 —
    # 检查是否存在
    print(os.path.exists("example.txt")) # True/False
    print(os.path.isfile("example.txt")) # 是文件?
    print(os.path.isdir("some_dir")) # 是目录?

    # 获取文件信息
    print(os.path.getsize("example.txt")) # 文件大小(字节)
    print(os.path.getmtime("example.txt")) # 最后修改时间戳

    # 重命名/移动
    os.rename("old_name.txt", "new_name.txt")
    # shutil.move("source.txt", "destination/")

    # 复制文件
    # shutil.copy("source.txt", "destination/")

    # 删除文件
    os.remove("example.txt")

    # — 目录操作 —
    # 创建目录
    os.mkdir("single_dir") # 创建单层目录(父目录必须存在)
    os.makedirs("parent/child/grandchild") # 递归创建多层目录

    # 列出目录内容
    entries = os.listdir(".")
    for entry in entries:
    print(entry)

    # 递归遍历
    for root, dirs, files in os.walk("."):
    for file in files:
    print(os.path.join(root, file))

    # 删除目录
    # os.rmdir("empty_dir") # 只能删除空目录
    # shutil.rmtree("dir_path") # 递归删除整个目录树

    # — pathlib(Python 3.4+,面向对象的路径操作,推荐!)—
    from pathlib import Path

    p = Path("data") / "subdir" / "file.txt"
    print(p) # data\\subdir\\file.txt (Windows)
    print(p.name) # file.txt
    print(p.stem) # file
    print(p.suffix) # .txt
    print(p.parent) # data\\subdir

    # 创建目录
    Path("my_folder").mkdir(exist_ok=True)
    Path("nested/deep/folder").mkdir(parents=True, exist_ok=True)

    # 读写(Python 3.5+)
    # text = Path("file.txt").read_text(encoding="utf-8")
    # Path("output.txt").write_text("Hello", encoding="utf-8")

    # 遍历目录
    # for file in Path(".").glob("*.py"):
    # print(file)
    # for file in Path(".").rglob("*.py"): # 递归
    # print(file)

    🔑 要点总结:pathlib 比传统的 os.path 更直观——用 / 拼接路径、.read_text() 一行读取文件。建议在新项目中使用 pathlib 替代字符串路径操作。

    18.4 CSV 与 JSON 文件

    💡 代码说明:Python 内置的 csv 和 json 模块让结构化数据的读写变得简单。csv.DictReader 用列名访问数据,json.dump/load 处理 JSON:

    import csv
    import json

    # — CSV 读取 —
    with open("data.csv", "r", encoding="utf-8", newline="") as f:
    reader = csv.reader(f)
    for row in reader:
    print(row)

    # CSV 写入
    with open("output.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["姓名", "年龄", "城市"]) # 标题行
    writer.writerows([ # 多行数据
    ["Alice", 25, "北京"],
    ["Bob", 30, "上海"],
    ])

    # DictReader / DictWriter(使用列名)
    # with open("data.csv", "r", encoding="utf-8") as f:
    # reader = csv.DictReader(f)
    # for row in reader:
    # print(row["姓名"])

    # — JSON 读写 —
    data = {"users": [{"name": "Alice", "age": 25}, {"name": "Bob", "age": 30}]}

    # 写入
    with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, indent=2, ensure_ascii=False)

    # 读取
    with open("data.json", "r", encoding="utf-8") as f:
    loaded = json.load(f)
    print(loaded["users"][0]["name"]) # Alice

    🔑 要点总结:处理 CSV 时建议使用 DictReader/DictWriter,代码更易读。JSON 的 ensure_ascii=False 能正确显示中文,indent 参数让输出格式化。


    19. 异常处理

    19.1 try / except / else / finally

    💡 代码说明:异常处理的核心结构:try 块放可能出错的代码,except 捕获特定异常,else 在无异常时运行,finally 无论如何都执行:

    # — 基本结构 —
    try:
    num = int(input("请输入一个整数: "))
    result = 100 / num
    except ValueError as e: # 捕获特定异常
    print(f"格式错误: {e}")
    except ZeroDivisionError:
    print("不能除以零!")
    except (TypeError, OverflowError) as e: # 捕获多种异常
    print(f"类型或溢出错误: {e}")
    except Exception as e: # 捕获所有异常(基类)
    print(f"未知错误: {e}")
    else: # 无异常时执行
    print(f"结果是: {result}")
    finally: # 无论如何都执行
    print("清理资源…")

    # — 常见异常类型 —
    # ValueError 值错误
    # TypeError 类型错误
    # KeyError 字典键不存在
    # IndexError 索引越界
    # AttributeError 对象没有该属性
    # NameError 变量名不存在
    # FileNotFoundError 文件未找到
    # IOError I/O 错误
    # ZeroDivisionError 除以零
    # ImportError 导入失败
    # RuntimeError 运行时错误
    # StopIteration 迭代结束
    # AssertionError 断言失败

    🔑 要点总结:永远捕获最具体的异常类型,不要使用裸露的 except:(它会捕获 SystemExit 和 KeyboardInterrupt)。常见的异常类型有十多种,IDE 会帮你补全。

    19.2 自定义异常

    💡 代码说明:通过继承 Exception 创建自定义异常,可以携带更多上下文信息。raise … from … 建立异常链,保留原始错误信息:

    # 自定义异常类
    class ValidationError(Exception):
    """数据验证异常"""

    def __init__(self, field, message="验证失败"):
    self.field = field
    self.message = message
    super().__init__(f"{field}: {message}")

    class InsufficientFundsError(Exception):
    """余额不足异常"""

    def __init__(self, balance, amount):
    self.balance = balance
    self.amount = amount
    super().__init__(
    f"余额不足:当前余额 {balance},需要 {amount},"
    f"差额 {amount balance}"
    )

    # 使用自定义异常
    def withdraw(balance, amount):
    if amount > balance:
    raise InsufficientFundsError(balance, amount)
    return balance amount

    try:
    withdraw(100, 200)
    except InsufficientFundsError as e:
    print(e)

    # 异常链(raise … from …)
    def process_file(filepath):
    try:
    with open(filepath, "r") as f:
    return f.read()
    except FileNotFoundError as e:
    raise RuntimeError(f"处理文件 {filepath} 失败") from e

    🔑 要点总结:自定义异常让错误信息更具体、更容易调试。异常链 from e 保留了原始错误的完整堆栈,是调试复杂系统的重要工具。

    19.3 最佳实践

    💡 代码说明:Python 社区推崇 EAFP(请求原谅比请求许可更容易)风格——先尝试,失败再处理——而不是 LBYL(三思而后行)的预检查风格:

    # ❌ 不要这样做:泛泛捕获所有异常
    # try:
    # risky_operation()
    # except: # 捕获包括 SystemExit、KeyboardInterrupt 等
    # pass # 静默吞掉异常

    # ✅ 正确做法
    # try:
    # risky_operation()
    # except Exception as e: # 明确捕获 Exception
    # logger.error(f"操作失败: {e}", exc_info=True)
    # raise # 重新抛出或适当处理

    # ✅ EAFP: Easier to Ask for Forgiveness than Permission
    # 请求原谅比请求许可更容易(Python 风格)
    # 先尝试,失败再处理
    # def get_item(lst, index):
    # try:
    # return lst[index]
    # except IndexError:
    # return None

    # ✅ LBYL: Look Before You Leap(其他语言风格)
    # def get_item(lst, index):
    # if 0 <= index < len(lst):
    # return lst[index]
    # return None

    🔑 要点总结:EAFP 利用异常处理替代条件检查,代码更简洁,且在并发环境下更安全。但要注意:只捕获预期的异常,不要让 except 掩盖 bug。


    20. 面向对象编程

    20.1 类与对象

    💡 代码说明:Python 使用 class 定义类,init 初始化实例,self 指向实例本身。类属性被所有实例共享,双下划线前缀触发名称改写实现私有:

    class Person:
    """人类"""

    # 类属性(所有实例共享)
    species = "Homo sapiens"

    # 实例初始化方法
    def __init__(self, name, age):
    # 实例属性
    self.name = name # 公有属性
    self.age = age
    self._secret = None # 约定:受保护属性(单下划线)
    self.__private = 0 # 名称改写:_Person__private

    # 实例方法
    def introduce(self):
    return f"我叫{self.name},今年{self.age}岁。"

    # 字符串表示(给开发者看的)
    def __repr__(self):
    return f"Person(name='{self.name}', age={self.age})"

    # 字符串表示(给用户看的,print 调用)
    def __str__(self):
    return f"{self.name} ({self.age}岁)"

    # 创建实例
    alice = Person("Alice", 25)
    bob = Person("Bob", 30)

    print(alice.introduce()) # 我叫Alice,今年25岁。
    print(alice) # Alice (25岁) 调用 __str__
    print(repr(alice)) # Person(name='Alice', age=25) 调用 __repr__

    # 访问类属性
    print(Person.species) # Homo sapiens
    print(alice.species) # Homo sapiens(实例也可访问)

    # 名称改写
    # print(alice.__private) # ❌ AttributeError
    print(alice._Person__private) # 0(可以绕过但不推荐)

    🔑 要点总结:Python 没有真正的私有属性——双下划线前缀只是名称改写为 _ClassName__attr,这是一种约定而非强制。单下划线前缀 _attr 表示受保护,更多是给开发者看的提示。

    20.2 继承

    💡 代码说明:Python 支持单继承和多继承。子类可以重写父类方法,使用 isinstance() 和 issubclass() 检查继承关系:

    class Animal:
    def __init__(self, name):
    self.name = name

    def speak(self):
    return "…"

    class Dog(Animal):
    def speak(self):
    return "汪汪!"

    def wag_tail(self):
    return f"{self.name} 摇尾巴"

    class Cat(Animal):
    def speak(self):
    return "喵喵!"

    dog = Dog("旺财")
    cat = Cat("咪咪")

    print(dog.name, "说:", dog.speak()) # 旺财 说: 汪汪!
    print(cat.name, "说:", cat.speak()) # 咪咪 说: 喵喵!
    print(dog.wag_tail()) # 旺财 摇尾巴

    # 检查继承关系
    print(isinstance(dog, Dog)) # True
    print(isinstance(dog, Animal)) # True
    print(isinstance(dog, Cat)) # False
    print(issubclass(Dog, Animal)) # True

    # 多重继承
    class Flyable:
    def fly(self):
    return "飞行中…"

    class Swimmable:
    def swim(self):
    return "游泳中…"

    class Duck(Animal, Flyable, Swimmable):
    def speak(self):
    return "嘎嘎!"

    duck = Duck("唐老鸭")
    print(duck.speak()) # 嘎嘎!
    print(duck.fly()) # 飞行中…
    print(duck.swim()) # 游泳中…

    # MRO(方法解析顺序)
    print(Duck.__mro__) # 查看方法搜索顺序

    🔑 要点总结:多重继承在需要混入多个功能时很方便(如 Duck 同时继承 Animal、Flyable、Swimmable),但不要过度使用。MRO(方法解析顺序)决定了多继承时方法的查找路径。

    20.3 super() 与父类调用

    💡 代码说明:super() 用于调用父类的方法,在 init 和方法重写中特别常用。它遵循 MRO 顺序,在多重继承下也能正确工作:

    class Employee:
    def __init__(self, name, salary):
    self.name = name
    self.salary = salary

    def work(self):
    return f"{self.name} 正在工作"

    def get_details(self):
    return f"Name: {self.name}, Salary: {self.salary}"

    class Manager(Employee):
    def __init__(self, name, salary, department):
    # 调用父类的 __init__
    super().__init__(name, salary)
    self.department = department

    def work(self):
    # 调用父类方法并扩展
    base_result = super().work()
    return f"{base_result},管理 {self.department} 部门"

    def get_details(self):
    return f"{super().get_details()}, Dept: {self.department}"

    mgr = Manager("Alice", 15000, "技术部")
    print(mgr.work()) # Alice 正在工作,管理 技术部 部门
    print(mgr.get_details()) # Name: Alice, Salary: 15000, Dept: 技术部

    🔑 要点总结:重写父类方法时,通常应先调用 super().method(),然后再添加子类的特定逻辑——这样可以确保父类的初始化或预处理不被遗漏。

    20.4 魔术方法(Magic / Dunder Methods)

    💡 代码说明:魔术方法(双下划线包围的方法)让自定义类支持运算符重载、迭代、比较、上下文管理等语言特性。以下 Vector 类展示了常用的魔术方法:

    class Vector:
    def __init__(self, x, y):
    self.x = x
    self.y = y

    # 字符串表示
    def __repr__(self):
    return f"Vector({self.x}, {self.y})"

    # 算术运算
    def __add__(self, other):
    return Vector(self.x + other.x, self.y + other.y)

    def __sub__(self, other):
    return Vector(self.x other.x, self.y other.y)

    def __mul__(self, scalar):
    """标量乘法"""
    return Vector(self.x * scalar, self.y * scalar)

    def __rmul__(self, scalar):
    """右侧乘法(scalar * vector)"""
    return self.__mul__(scalar)

    def __neg__(self):
    return Vector(self.x, self.y)

    def __abs__(self):
    """向量的模"""
    return (self.x ** 2 + self.y ** 2) ** 0.5

    # 比较运算
    def __eq__(self, other):
    return self.x == other.x and self.y == other.y

    def __lt__(self, other):
    """按模长比较"""
    return abs(self) < abs(other)

    # 使对象可迭代
    def __iter__(self):
    return iter([self.x, self.y])

    # 使对象可用 in 检查
    def __contains__(self, value):
    return value in (self.x, self.y)

    # 使对象可调用
    def __call__(self):
    """返回向量的模"""
    return abs(self)

    # 属性访问
    def __getitem__(self, index):
    if index == 0: return self.x
    if index == 1: return self.y
    raise IndexError("索引只能是 0 或 1")

    def __len__(self):
    return 2 # 总是返回 2

    # 上下文管理器
    def __enter__(self):
    print(f"进入 Vector 上下文: {self}")
    return self

    def __exit__(self, exc_type, exc_val, exc_tb):
    print(f"退出 Vector 上下文: {self}")

    # — 使用 —
    v1 = Vector(3, 4)
    v2 = Vector(1, 2)

    print(v1 + v2) # Vector(4, 6)
    print(v1 v2) # Vector(2, 2)
    print(v1 * 3) # Vector(9, 12)
    print(3 * v1) # Vector(9, 12)(__rmul__)
    print(v1) # Vector(-3, -4)
    print(abs(v1)) # 5.0
    print(v1 == Vector(3, 4)) # True
    print(v1 < Vector(1, 1)) # False (5.0 > 1.414)
    # 迭代
    for coord in v1:
    print(coord) # 3 4
    print(3 in v1) # True
    print(v1()) # 5.0(可调用)
    print(v1[0], v1[1]) # 3 4
    print(len(v1)) # 2

    # 上下文管理器
    with Vector(5, 12) as v:
    print(f"处理中: {v}")
    # 进入 Vector 上下文: Vector(5, 12)
    # 处理中: Vector(5, 12)
    # 退出 Vector 上下文: Vector(5, 12)

    🔑 要点总结:魔术方法是 Python 数据模型的精髓——掌握了它们,你的类就能像内置类型一样自然地被使用。repr(给开发者)和 str(给用户)的区别是面试常考题。

    20.5 @dataclass 数据类

    💡 代码说明:Python 3.7+ 的 @dataclass 装饰器自动生成 init、repr、eq 等方法,大幅减少样板代码:

    from dataclasses import dataclass, field
    from typing import List

    # Python 3.7+ 的 dataclass 自动生成 __init__、__repr__、__eq__ 等方法
    @dataclass
    class Point:
    x: float
    y: float

    # 不需要手写 __init__ 和 __repr__!
    # __eq__ 也自动生成

    def distance_to_origin(self):
    return (self.x ** 2 + self.y ** 2) ** 0.5

    p1 = Point(3.0, 4.0)
    p2 = Point(3.0, 4.0)
    print(p1) # Point(x=3.0, y=4.0)
    print(p1 == p2) # True(自动比较字段值)
    print(p1.distance_to_origin()) # 5.0

    # 更复杂的配置
    @dataclass
    class Student:
    name: str
    age: int
    grades: List[float] = field(default_factory=list) # 默认值使用 factory
    active: bool = True

    def average_grade(self):
    if not self.grades:
    return 0.0
    return sum(self.grades) / len(self.grades)

    student = Student(name="Alice", age=20, grades=[85.0, 92.0, 78.0])
    print(student) # Student(name='Alice', age=20, grades=[85.0, 92.0, 78.0], active=True)
    print(student.average_grade()) # 85.0

    🔑 要点总结:对于主要存储数据的类,@dataclass 是极佳选择。field(default_factory=list) 正确处理了可变默认值的问题,比手写 init 更安全。


    21. 常用内置函数

    21.1 类型相关

    💡 代码说明:这些内置函数帮助检查类型(type/isinstance)、获取对象信息(id/dir/help):

    # type() – 获取类型
    print(type(42)) # <class 'int'>

    # isinstance() – 类型检查
    print(isinstance(42, int)) # True

    # id() – 获取对象内存地址
    x = [1, 2, 3]
    print(id(x)) # 某个整数地址

    # dir() – 列出属性和方法
    print(dir([])) # 列表的所有方法

    # help() – 查看帮助
    # help(str) # 在 REPL 中

    🔑 要点总结:dir() 在探索陌生模块或对象时极其有用;id() 帮助理解对象标识(配合 is 使用)。

    21.2 数学运算

    💡 代码说明:Python 内置了常用数学函数:abs(绝对值)、round(四舍五入)、max/min(最值,支持 key 参数)、sum(求和)、pow(幂运算)、divmod(商和余数):

    # abs() – 绝对值
    print(abs(5)) # 5

    # round() – 四舍五入
    print(round(3.14159, 2)) # 3.14

    # max() / min()
    print(max(1, 5, 3)) # 5
    print(min([3, 1, 4, 1, 5])) # 1

    # max 的 key 参数
    words = ["apple", "kiwi", "banana", "pear"]
    print(max(words, key=len)) # banana

    # sum()
    print(sum([1, 2, 3, 4, 5])) # 15
    print(sum([1, 2, 3], 10)) # 16(初始值 10)

    # pow()
    print(pow(2, 8)) # 256
    print(pow(2, 8, 1000)) # 256(取模)

    # divmod()
    print(divmod(10, 3)) # (3, 1)

    🔑 要点总结:max/min 的 key 参数非常强大——按长度找最长单词、按价格找最贵商品,一行搞定。sum 的第二个参数是初始值,默认为 0。

    21.3 序列操作

    💡 代码说明:序列操作内置函数:len(长度)、sorted(排序返回新列表)、reversed(反向)、enumerate(枚举)、zip(打包)、filter(过滤)、map(映射)、any/all(逻辑判断):

    # len() – 长度
    print(len("hello")) # 5
    print(len([1, 2, 3])) # 3

    # sorted() – 排序(返回新列表)
    nums = [3, 1, 4, 1, 5]
    print(sorted(nums)) # [1, 1, 3, 4, 5]
    print(sorted(nums, reverse=True)) # [5, 4, 3, 1, 1]
    print(nums) # [3, 1, 4, 1, 5](原列表不变)

    # reversed() – 反向迭代器
    for i in reversed([1, 2, 3]):
    print(i) # 3, 2, 1

    # range() – 范围
    print(list(range(5))) # [0, 1, 2, 3, 4]

    # enumerate() – 枚举
    for i, v in enumerate(['a', 'b', 'c'], start=1):
    print(f"{i}: {v}") # 1: a, 2: b, 3: c

    # zip() – 打包
    a = [1, 2, 3]
    b = ['a', 'b', 'c']
    print(list(zip(a, b))) # [(1, 'a'), (2, 'b'), (3, 'c')]

    # filter() – 过滤
    nums = [1, 2, 3, 4, 5, 6]
    evens = list(filter(lambda x: x % 2 == 0, nums))
    print(evens) # [2, 4, 6]

    # map() – 映射
    squared = list(map(lambda x: x**2, nums))
    print(squared) # [1, 4, 9, 16, 25, 36]

    # any() / all()
    print(any([False, False, True])) # True(至少一个为真)
    print(all([True, True, False])) # False(必须全部为真)

    🔑 要点总结:sorted() 不改变原序列,any() 和 all() 在条件检查中非常实用。filter 和 map 返回迭代器(不是列表),需要用 list() 转换或直接遍历。

    21.4 输入输出

    💡 代码说明:print() 的 sep 和 end 参数可以定制输出格式,file 参数可以将输出重定向到文件:

    # print() – 打印
    print("Hello", "World", sep=" | ", end="!!!\\n")
    # Hello | World!!!

    # 写入文件
    # with open("log.txt", "w") as f:
    # print("错误信息", file=f)

    # input() – 用户输入
    # name = input("请输入姓名: ")
    # print(f"你好,{name}")

    # open() – 打开文件
    # f = open("file.txt", "r", encoding="utf-8")

    🔑 要点总结:print() 的可定制性远超想象——sep 控制分隔符、end 控制结尾字符、file 可重定向输出。input() 读取用户输入,总是返回字符串。

    21.5 其他常用函数

    💡 代码说明:其他高频函数包括:hasattr/getattr/setattr/delattr(动态操作属性)、callable(判断可调用)、ord/chr(字符编码转换)、bin/oct/hex(进制转换)、eval/exec(动态执行):

    # — 对象相关 —
    # hasattr() / getattr() / setattr() / delattr()
    class Person:
    def __init__(self, name):
    self.name = name

    p = Person("Alice")
    print(hasattr(p, "name")) # True
    print(getattr(p, "name")) # "Alice"
    print(getattr(p, "age", "未知")) # "未知"(默认值)
    setattr(p, "age", 25) # 等价于 p.age = 25
    delattr(p, "age") # 等价于 del p.age

    # callable() – 判断是否可调用
    print(callable(print)) # True
    print(callable("hello")) # False

    # — 字符串转换 —
    # repr() / ascii()
    print(repr("Hello\\nWorld")) # "Hello\\nWorld"(开发者表示)
    print(ascii("你好")) # '你好'

    # ord() / chr() – 字符与 Unicode 码点
    print(ord('A')) # 65
    print(ord('中')) # 20013
    print(chr(65)) # 'A'
    print(chr(20013)) # '中'

    # bin() / oct() / hex() – 进制转换
    print(bin(10)) # '0b1010'
    print(oct(10)) # '0o12'
    print(hex(255)) # '0xff'

    # — 迭代工具 —
    # iter() / next()
    it = iter([1, 2, 3])
    print(next(it)) # 1

    # — 编译/执行 —
    # compile() / exec() / eval() – 动态执行代码(注意安全风险)
    result = eval("1 + 2 * 3") # 7(计算表达式)
    # exec("print('Hello from exec')") # 执行代码块

    # — 全局/局部命名空间 —
    # globals() / locals() – 返回命名空间字典
    x = 42
    print(globals()['x']) # 42

    🔑 要点总结:getattr(obj, attr, default) 在不确定属性是否存在时非常安全。eval() 执行表达式、exec() 执行代码块,但需谨慎使用——执行不可信的输入有安全风险。


    22. 类型注解

    Python 是动态类型语言,但从 3.5+ 开始支持类型注解(Type Hints),帮助 IDE 和工具做静态检查。

    22.1 基本类型注解

    💡 代码说明:Python 类型注解使用 变量: 类型 语法,函数注解使用 def func(arg: Type) -> ReturnType。注解不强制类型,但能帮助 IDE 和 mypy 做静态检查:

    # 变量注解
    name: str = "Alice"
    age: int = 25
    price: float = 3.99
    is_active: bool = True

    # 函数注解
    def greet(name: str) > str:
    return f"Hello, {name}"

    def divide(a: float, b: float) > float:
    if b == 0:
    raise ValueError("除数不能为零")
    return a / b

    # 参数默认值
    def repeat(text: str, times: int = 1) > str:
    return text * times

    🔑 要点总结:类型注解是可选的,但越来越多的项目开始使用它们。结合 VS Code / PyCharm,类型注解能提供更好的代码补全和错误提示。

    22.2 复杂类型注解

    💡 代码说明:使用 typing 模块(或 Python 3.10+ 新语法)可以注解容器类型、可选类型、联合类型、回调函数、字面量类型和结构化字典等复杂场景:

    from typing import (
    List, Dict, Set, Tuple, Optional, Union,
    Callable, Any, Sequence, Iterable, Literal, TypedDict
    )

    # 容器类型
    def process_numbers(nums: List[int]) > Dict[int, int]:
    return {n: n ** 2 for n in nums}

    def matrix_multiply(a: List[List[float]], b: List[List[float]]) > List[List[float]]:
    # …
    pass

    # 元组(固定长度)
    point: Tuple[float, float] = (3.0, 4.0)
    record: Tuple[str, int, bool] = ("Alice", 25, True)

    # Optional: 可以是某类型或 None
    def find_user(user_id: int) > Optional[Dict[str, Any]]:
    # 可能返回 None
    pass

    # Union: 多种类型中之一(Python 3.10+ 可用 X | Y)
    def parse_value(value: str) > Union[int, float, str]:
    try:
    return int(value)
    except ValueError:
    try:
    return float(value)
    except ValueError:
    return value

    # Python 3.10+ 新语法(推荐)
    def parse_value_v2(value: str) > int | float | str:
    pass

    # Optional 的新写法(Python 3.10+)
    def maybe_get_name() > str | None:
    pass

    # Callable: 函数类型
    def apply(func: Callable[[int, int], int], a: int, b: int) > int:
    return func(a, b)

    # Any: 任意类型(禁用类型检查)
    def flexible(data: Any) > Any:
    return data

    # Literal: 字面量类型
    def set_mode(mode: Literal["read", "write", "append"]) > None:
    pass

    set_mode("read") # ✅
    # set_mode("delete") # ❌ 类型检查器会报错

    # TypedDict: 带类型的字典
    class User(TypedDict):
    name: str
    age: int
    email: str | None

    def create_user(data: User) > None:
    print(data["name"])

    🔑 要点总结:Python 3.10+ 推荐使用 int | None 替代 Optional[int],int | str 替代 Union[int, str]——更简洁直观。Literal 限定参数的合法值,让类型检查更精确。

    22.3 自定义泛型

    💡 代码说明:使用 TypeVar 创建类型变量,实现泛型函数和泛型类——让类型检查器能根据输入推断输出的具体类型:

    from typing import TypeVar, Generic

    T = TypeVar('T') # 类型变量

    def first(items: List[T]) > T | None:
    """返回列表第一个元素,保持类型"""
    return items[0] if items else None

    a: int = first([1, 2, 3]) # 类型检查器知道返回 int
    b: str = first(["a", "b", "c"]) # 类型检查器知道返回 str

    # 泛型类
    K = TypeVar('K')
    V = TypeVar('V')

    class Stack(Generic[T]):
    def __init__(self) > None:
    self._items: List[T] = []

    def push(self, item: T) > None:
    self._items.append(item)

    def pop(self) > T | None:
    return self._items.pop() if self._items else None

    int_stack = Stack[int]()
    int_stack.push(1)
    int_stack.push(2)
    # int_stack.push("hello") # ❌ 类型检查器会报错

    🔑 要点总结:泛型在编写可复用的容器类(如 Stack、Queue)和工具函数时特别有用——既保持类型安全,又不失灵活性。


    23. 虚拟环境与包管理

    23.1 venv 虚拟环境

    # 创建虚拟环境
    python -m venv myenv

    # 激活虚拟环境
    # Windows:
    myenv\\Scripts\\activate
    # macOS/Linux:
    # source myenv/bin/activate

    # 退出虚拟环境
    deactivate

    23.2 pip 包管理

    # 安装包
    pip install requests
    pip install pandas==2.0.3 # 安装特定版本
    pip install "django>=4.0,<5.0" # 版本范围

    # 升级包
    pip install –upgrade requests

    # 卸载包
    pip uninstall requests

    # 列出已安装的包
    pip list
    pip list –outdated # 列出可升级的包

    # 显示包详情
    pip show requests

    # 依赖管理
    pip freeze > requirements.txt # 导出依赖
    pip install -r requirements.txt # 安装依赖

    # 搜索包
    # pip search <keyword> # 已在 PyPI 网站搜索

    23.3 requirements.txt 示例

    # requirements.txt
    requests>=2.28,<3.0
    numpy==1.24.3
    pandas>=2.0
    flask>=2.3
    python-dotenv>=1.0
    black>=23.0 # 代码格式化
    pylint>=2.17 # 代码检查
    pytest>=7.4 # 测试框架


    24. 编码规范(PEP 8)

    24.1 缩进与空白

    💡 代码说明:PEP 8 规定使用 4 空格缩进、每行最多 79 字符、运算符两侧加空格、函数和类之间空两行:

    # ✅ 使用 4 个空格缩进(不要用 Tab)
    def my_function():
    if condition:
    do_something()

    # ❌ 不要混用 Tab 和空格
    # ❌ 不要用 2 个或 8 个空格

    # 每行最多 79 个字符(文档/注释 72)
    # 操作符两边各加一个空格
    x = 1 + 2
    y = x * 3

    # 函数和类之间空两行
    # 方法之间空一行

    🔑 要点总结:遵循 PEP 8 让你和团队其他成员的代码风格一致。可以用 black 工具自动格式化,省去手动调整的麻烦。

    24.2 命名约定

    💡 代码说明:Python 社区遵循一致的命名约定:函数/变量用 snake_case,类用 PascalCase,常量全大写,私有属性前缀单下划线:

    # 包/模块: 简短小写,可用下划线
    # my_package, utils

    # 函数/方法/变量: 小写 + 下划线
    def calculate_average(numbers):
    total_sum = 0
    return total_sum / len(numbers)

    # 类: 大驼峰
    class ShoppingCart:
    pass

    # 异常: 类名 + Error
    class ValidationError(Exception):
    pass

    # 常量: 全大写 + 下划线
    MAX_CONNECTIONS = 100
    DEFAULT_TIMEOUT = 30

    # 私有属性/方法: 前缀单下划线
    class MyClass:
    def __init__(self):
    self._internal_data = {}

    def _private_method(self):
    pass

    # 避免名称改写: 后缀单下划线
    # class_(class 是关键字)
    # list_(list 是内置函数)

    🔑 要点总结:一致的命名让代码意图一目了然——MAX_SIZE 一眼就是常量,_internal 表示内部使用,ValidationError 一看就是异常类。

    24.3 导入顺序

    💡 代码说明:import 语句应按标准库 -> 第三方库 -> 本地模块的顺序排列,每组之间空一行:

    # 1. 标准库
    import os
    import sys

    # 2. 第三方库
    import numpy as np
    import requests

    # 3. 本地模块
    from .utils import helper
    from mypackage.core import core_func

    🔑 要点总结:isort 工具可以自动按此规则排序 import 语句,一劳永逸。

    24.4 注释与文档字符串

    💡 代码说明:好的注释说明为什么而不是做了什么。文档字符串用三引号,推荐 Google 风格或 NumPy 风格的格式:

    # 单行注释:说明代码意图(不说明做了什么,而是为什么这么做)
    # 复杂正则表达式: 匹配 Email 地址 (RFC 5322)
    email_pattern = r'…'

    # 文档字符串: 三引号
    def fetch_data(url: str, timeout: int = 10) > dict | None:
    """
    从指定 URL 获取 JSON 数据。

    Args:
    url: API 地址
    timeout: 超时时间(秒)

    Returns:
    成功时返回解析后的字典,失败返回 None

    Raises:
    ValueError: URL 格式不正确
    requests.RequestException: 网络请求失败
    """
    pass

    🔑 要点总结:Args:、Returns:、Raises: 是文档字符串的标准字段,IDE 和文档生成工具(如 Sphinx)能识别并自动生成漂亮的 API 文档。

    24.5 代码格式化工具

    # Black: 自动代码格式化
    pip install black
    black my_script.py

    # isort: 自动排序 import 语句
    pip install isort
    isort my_script.py

    # Flake8 / Pylint: 代码质量检查
    pip install flake8 pylint
    flake8 my_script.py
    pylint my_script.py

    # mypy: 静态类型检查
    pip install mypy
    mypy my_script.py


    25. 综合练习

    练习 1:学生成绩管理系统

    💡 代码说明:综合运用类与对象、字典操作、列表推导式、排序等知识,实现一个完整的学生成绩管理系统。包含添加学生、记录成绩、计算平均分、排名和生成报告等功能:

    """
    学生成绩管理系统
    功能:
    1. 添加学生及其成绩
    2. 计算平均分
    3. 查找最高分学生
    4. 按成绩排序
    """

    class StudentGradeManager:
    def __init__(self):
    self.students: dict[str, list[float]] = {}

    def add_student(self, name: str) > None:
    """添加学生"""
    if name not in self.students:
    self.students[name] = []
    print(f"已添加学生: {name}")
    else:
    print(f"学生 {name} 已存在")

    def add_grade(self, name: str, grade: float) > None:
    """添加成绩"""
    if 0 <= grade <= 100:
    self.students.setdefault(name, [])
    self.students[name].append(grade)
    print(f"{name} 的成绩 {grade} 已记录")
    else:
    raise ValueError("成绩必须在 0-100 之间")

    def get_average(self, name: str) > float | None:
    """获取学生平均分"""
    grades = self.students.get(name)
    return sum(grades) / len(grades) if grades else None

    def get_overall_average(self) > float:
    """获取全班平均分"""
    all_grades = [
    grade
    for grades in self.students.values()
    for grade in grades
    ]
    return sum(all_grades) / len(all_grades) if all_grades else 0.0

    def top_student(self) > tuple[str, float] | None:
    """获取平均分最高的学生"""
    if not self.students:
    return None
    return max(
    ((name, self.get_average(name)) for name in self.students),
    key=lambda x: x[1]
    )

    def rank_students(self) > list[tuple[str, float]]:
    """按平均分从高到低排名"""
    ranked = [
    (name, self.get_average(name))
    for name in self.students
    ]
    return sorted(ranked, key=lambda x: x[1], reverse=True)

    def report(self) > str:
    """生成成绩报告"""
    lines = ["=" * 40, "学生成绩报告", "=" * 40]
    for name in self.students:
    avg = self.get_average(name)
    grades = self.students[name]
    lines.append(
    f"{name}: 成绩 {grades}, 平均分 {avg:.1f}"
    )
    lines.append("-" * 40)
    lines.append(f"全班平均分: {self.get_overall_average():.1f}")
    top = self.top_student()
    if top:
    lines.append(f"最高分学生: {top[0]} ({top[1]:.1f})")
    return "\\n".join(lines)

    # — 使用示例 —
    if __name__ == "__main__":
    mgr = StudentGradeManager()

    # 添加学生和成绩
    mgr.add_student("Alice")
    mgr.add_student("Bob")
    mgr.add_student("Charlie")

    mgr.add_grade("Alice", 85)
    mgr.add_grade("Alice", 92)
    mgr.add_grade("Bob", 78)
    mgr.add_grade("Bob", 83)
    mgr.add_grade("Charlie", 95)
    mgr.add_grade("Charlie", 88)

    # 打印报告
    print(mgr.report())
    print(f"\\n排名: {mgr.rank_students()}")

    🔑 要点总结:这个练习涵盖了 Python 基础语法的方方面面——面向对象设计、数据结构选择、异常处理、列表推导式、条件判断等。建议先理解代码结构,再动手自己实现一遍。

    练习 2:装饰器练习 — 实现 API 限流

    💡 代码说明:这是一个实战级别的装饰器练习——实现 API 调用频率限制(Rate Limiting)。利用闭包保存调用历史,在超限时抛出异常:

    import time
    from functools import wraps
    from collections import defaultdict

    def rate_limit(max_calls: int, period: float):
    """
    限流装饰器:在指定时间周期内限制函数调用次数

    Args:
    max_calls: 最大调用次数
    period: 时间周期(秒)
    """
    calls = defaultdict(list) # {函数名: [调用时间列表]}

    def decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
    now = time.time()
    func_name = func.__name__

    # 清理过期的调用记录
    calls[func_name] = [
    t for t in calls[func_name]
    if now t < period
    ]

    # 检查是否超出限制
    if len(calls[func_name]) >= max_calls:
    wait_time = period (now calls[func_name][0])
    raise RuntimeError(
    f"API 限流:在 {period} 秒内最多调用 {max_calls} 次。"
    f"请等待 {wait_time:.1f} 秒。"
    )

    # 记录调用时间
    calls[func_name].append(now)
    return func(*args, **kwargs)

    return wrapper

    return decorator

    # — 使用 —
    @rate_limit(max_calls=3, period=5)
    def api_call(endpoint: str) > str:
    """模拟 API 调用"""
    return f"API 响应: {endpoint}"

    # 测试
    if __name__ == "__main__":
    for i in range(5):
    try:
    result = api_call(f"/users/{i}")
    print(result)
    except RuntimeError as e:
    print(f"错误: {e}")
    time.sleep(0.5)

    🔑 要点总结:这个限流装饰器展示了装饰器的实际应用价值——将横切关注点(限流)从业务逻辑(API 调用)中干净地分离出来。理解了这个例子,装饰器的核心思想就掌握了。

    练习 3:生成器练习 — 文件解析

    💡 代码说明:使用生成器和正则表达式,实现一个日志文件解析器。通过 yield 逐行产出解析结果,再用管道式生成器进行过滤和统计:

    """
    解析日志文件并提取特定模式的数据
    """

    def parse_log_file(filepath: str):
    """
    逐行读取日志文件,解析为结构化数据

    日志格式: [2026-07-21 14:30:00] [INFO] User Alice logged in
    """
    import re

    # 日志行正则
    pattern = re.compile(
    r'\\[(?P<timestamp>[^\\]]+)\\]\\s+'
    r'\\[(?P<level>[A-Z]+)\\]\\s+'
    r'(?P<message>.+)'
    )

    with open(filepath, 'r', encoding='utf-8') as f:
    for line_num, line in enumerate(f, start=1):
    line = line.strip()
    if not line:
    continue
    match = pattern.match(line)
    if match:
    yield {
    'line': line_num,
    'timestamp': match.group('timestamp'),
    'level': match.group('level'),
    'message': match.group('message'),
    }
    else:
    yield {
    'line': line_num,
    'raw': line,
    'error': '解析失败',
    }

    def filter_errors(records):
    """过滤出 ERROR 级别的记录"""
    for record in records:
    if record.get('level') == 'ERROR':
    yield record

    def count_by_level(records):
    """按日志级别统计"""
    from collections import Counter
    return Counter(record.get('level', 'PARSE_ERROR') for record in records)

    # 创建测试日志文件
    def create_test_log():
    log_content = """[2026-07-21 10:00:00] [INFO] Application started
    [2026-07-21 10:00:05] [DEBUG] Loading config file
    [2026-07-21 10:00:10] [INFO] Server listening on port 8080
    [2026-07-21 10:01:00] [WARNING] Memory usage exceeds 80%
    [2026-07-21 10:02:00] [ERROR] Connection timeout: database
    [2026-07-21 10:02:30] [ERROR] Failed to send email notification
    [2026-07-21 10:03:00] [INFO] Retry successful
    [2026-07-21 10:05:00] [INFO] Application shutdown
    malformed line without proper format
    """

    with open("test_log.txt", "w", encoding="utf-8") as f:
    f.write(log_content)

    if __name__ == "__main__":
    create_test_log()

    # 解析日志
    records = list(parse_log_file("test_log.txt"))

    # 统计
    print("=== 日志统计 ===")
    counter = count_by_level(records)
    for level, count in counter.items():
    print(f" {level}: {count} 条")

    # 显示错误
    print("\\n=== 错误日志 ===")
    for error in filter_errors(records):
    print(f" 行 {error['line']}: {error['message']}")

    🔑 要点总结:生成器管道模式(parse -> filter -> analyze)在处理大文件时特别有价值——每一行只被处理一次,数据流式经过各个处理环节,几乎不占内存。建议将此模式用于实际的日志分析任务中。


    附录 A:Python 内置异常层级

    BaseException
    ├── SystemExit
    ├── KeyboardInterrupt
    ├── GeneratorExit
    └── Exception
    ├── StopIteration
    ├── StopAsyncIteration
    ├── ArithmeticError
    │ ├── FloatingPointError
    │ ├── OverflowError
    │ └── ZeroDivisionError
    ├── AssertionError
    ├── AttributeError
    ├── BufferError
    ├── EOFError
    ├── ImportError
    │ └── ModuleNotFoundError
    ├── LookupError
    │ ├── IndexError
    │ └── KeyError
    ├── MemoryError
    ├── NameError
    │ └── UnboundLocalError
    ├── OSError
    │ ├── BlockingIOError
    │ ├── ChildProcessError
    │ ├── ConnectionError
    │ ├── FileExistsError
    │ ├── FileNotFoundError
    │ ├── InterruptedError
    │ ├── IsADirectoryError
    │ ├── NotADirectoryError
    │ ├── PermissionError
    │ ├── ProcessLookupError
    │ └── TimeoutError
    ├── ReferenceError
    ├── RuntimeError
    │ ├── NotImplementedError
    │ └── RecursionError
    ├── SyntaxError
    │ └── IndentationError
    │ └── TabError
    ├── SystemError
    ├── TypeError
    ├── ValueError
    │ └── UnicodeError
    └── Warning

    附录 B:推荐学习资源

    在线资源

    资源说明链接
    Python 官方文档 权威参考,中文版 docs.python.org/zh-cn
    菜鸟教程 中文入门教程 runoob.com/python3
    Real Python 英文高质量教程 realpython.com
    LeetCode 编程练习 leetcode.cn
    PyPI Python 包索引 pypi.org

    推荐书籍

    • 《Python 编程:从入门到实践》 – Eric Matthes(入门首选)
    • 《流畅的 Python》 – Luciano Ramalho(深入理解 Python)
    • 《Python Cookbook》 – David Beazley(实战技巧)
    • 《Effective Python》 – Brett Slatkin(最佳实践)

    📝 学习建议

  • 动手实践:每学一个概念,立即写代码验证
  • 阅读错误信息:Python 的错误信息很友好,仔细阅读
  • 善用 REPL:交互式解释器是测试小段代码的最佳工具
  • 阅读优秀代码:在 GitHub 上找高质量的 Python 项目学习
  • 做项目驱动:找一个感兴趣的小项目,边做边学

  • 本教程由 AI 辅助生成,内容覆盖 Python 3.8+ 核心语法。如有疏漏,欢迎指正!

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Python基础语法教程
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!