笔记 / Python · 更新于 2026-10-15

Python


一、 Python 基础语法与环境

1.1 注释与输入输出

1. 单行与多行注释

# 这是单行注释

'''
这是多行注释(单引号)
用于解释复杂逻辑或作 Docstring
'''

"""
这也是多行注释(双引号)
"""

2. 标准输出 print()

# 基础输出
print("Hello World")

# 多值输出(默认空格分隔)
print("姓名:", "张三", "年龄:", 18)  # 输出: 姓名: 张三 年龄: 18

# 自定义分隔符 (sep) 与 结尾符 (end)
print("2024", "01", "15", sep="-")  # 输出: 2024-01-15
print("Hello", end=" ")              # 不换行,末尾加空格
print("World")                       # 输出: Hello World

3. 标准输入 input()

# input() 接收的所有输入均为 字符串(str) 类型
name = input("请输入姓名: ")
age_str = input("请输入年龄: ")

# 转为数字类型进行计算
age = int(age_str)
print(f"你好,{name}!明年你 {age + 1} 岁。")

1.2 变量、多重赋值与动态类型

1. 变量概念与动态类型

Python 中的变量无需显式声明类型,变量的类型由赋给它的值决定,且可随时改变。

x = 10        # x 当前为 int 类型
x = "Hello"   # x 变为 str 类型
x = [1, 2, 3] # x 变为 list 类型

2. 打包、拆包与链式赋值

# 1. 链式赋值
a = b = c = 100

# 2. 多重赋值 / 元组拆包 (Unpacking)
name, age, gender = "张三", 18, "男"

# 3. 变量值快速交换 (Swapping)
x, y = 10, 20
x, y = y, x   # x=20, y=10

# 4. 变量删除
del x         # 解除变量绑定,再次调用会引发 NameError

1.3 标识符命名规范与核心关键字

1. 标识符硬性规则

2. 行业通用命名 PEP 8 规范

标识符类型 推荐规范 示例
变量名 / 函数名 小写 + 下划线 (Snake Case) user_name, calculate_score()
类名 大驼峰命名法 (Pascal Case) StudentManager, UserProfile
常量 全大写 + 下划线 MAX_CONNECTIONS, PI
私有属性/变量 单/双下划线开头 _private_var, __hidden_attr

3. 核心关键字列表速查 (import keyword; 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

1.4 基本数据类型与类型转换

1. 核心基本数据类型

# 检查数据类型 type()
print(type(10))        # <class 'int'>
print(type(3.14))      # <class 'float'>
print(type(True))      # <class 'bool'>
print(type(None))      # <class 'NoneType'>

2. 显式类型转换 API

转换 API 作用 示例与结果
int(x) 转为整数(截断小数) int(3.8) -> 3, int("100") -> 100
float(x) 转为浮点数 float(10) -> 10.0, float("3.14") -> 3.14
str(x) 转为字符串 str(100) -> "100", str(True) -> "True"
bool(x) 转为布尔值(假值转为 False) bool(0) -> False, bool("") -> False

💡 假值 (Falsy values) 汇总:0, 0.0, "" (空串), None, [] (空列表), () (空元组), {} (空字典), set() (空集合)。其余皆为 True。


1.5 运算符全解与优先级速查表

1. 算术运算符

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 (幂运算 10^3)

2. 赋值与复合赋值运算符

x = 10
x += 5  # x = x + 5 (15)
x -= 3  # x = x - 3 (12)
x *= 2  # x = x * 2 (24)
x /= 4  # x = x / 4 (6.0)

3. 比较(关系)运算符

返回布尔值:== (等于), != (不等于), > (大于), < (小于), >= (大于等于), <= (小于等于)。

print(10 == 10.0) # True
print(10 != 3)    # True

4. 逻辑运算符与短路求值

# 短路机制(Short-circuit evaluation)
False and print("不会执行")  # 左侧为 False,右侧直接跳过
True or print("不会执行")   # 左侧为 True,右侧直接跳过

5. 成员运算符与身份运算符

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

  1. () (括号)
  2. ** (幂运算)
  3. +x, -x, ~x (正负号、按位取反)
  4. *, /, //, % (乘、除、整除、取余)
  5. +, - (加、减)
  6. <<, >> (按位移位)
  7. & (按位与)
  8. ^, | (按位异或、按位或)
  9. ==, !=, >, <, >=, <= (比较运算符)
  10. is, is not (身份运算符)
  11. in, not in (成员运算符)
  12. not (逻辑非)
  13. and (逻辑与)
  14. or (逻辑或)

二、 控制流结构


2.1 条件判断 (if-elif-else / 三元运算符)

1. 基础 if-elif-else 结构

分支结构根据条件表述(布尔值)决定执行哪一部分代码。只要有一个条件满足,后面的分支将被忽略。

score = 85

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

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

2. 隐式布尔值判断(Pythonic 风格)

在条件判断中,无需显式写 len(lst) > 0 或 flag == True,直接利用 Python 对象的真伪性(Truthiness):

items = []

# 推荐 (Pythonic)
if not items:
    print("容器为空")

# 不推荐
if len(items) == 0:
    print("容器为空")

3. 三元运算符 (Conditional Expression)

用于将简单的 if-else 条件判断简化为单行表达式: - 语法:真值结果 if 条件表达式 else 假值结果

age = 18
# 单行替代传统的 4 行 if-else
status = "成年" if age >= 18 else "未成年"

# 嵌套三元运算符(不建议过于复杂,影响可读性)
x = 0
result = "正数" if x > 0 else ("负数" if x < 0 else "零")

2.2 模式匹配 (match-case - Python 3.10+)

Python 3.10 引入了类似于其他语言 switch-case 的结构,但功能更强大,支持结构化解包匹配。

1. 基础匹配与通配符 _

status_code = 404

match status_code:
    case 200:
        print("成功 (OK)")
    case 400 | 404:  # 使用 | 表示 OR 逻辑
        print("客户端错误")
    case 500:
        print("服务器错误")
    case _:          # 通配符 _ 匹配任意未处理的情况 (相当于 default)
        print("未知状态码")

2. 带条件守卫 (Guard) 与序列解包的高级匹配

point = (0, 5)

match point:
    case (0, 0):
        print("原点")
    case (0, y):  # 解包并将第二个值绑定给 y
        print(f"Y 轴上的点,y = {y}")
    case (x, 0):
        print(f"X 轴上的点,x = {x}")
    case (x, y) if x == y:  # 条件守卫 (if 表达式)
        print(f"在对角线上: ({x}, {y})")
    case (x, y):
        print(f"普通坐标: ({x}, {y})")

2.3 循环结构 (while / for-in / range)

1. while 循环

基于条件判断进行循环,当条件为 True 时持续执行,直到条件变为 False。

count = 1
while count <= 3:
    print(f"当前计数: {count}")
    count += 1  # 务必包含修改条件的语句,避免死循环

2. for-in 循环

用于遍历可迭代对象(如字符串、列表、元组、字典、集合、range 等)。

# 遍历字符串
for char in "Python":
    print(char, end=" ")  # 输出: P y t h o n

3. range() 函数生成等差数列

range(start, stop[, step]) 生成整数序列,遵循 左闭右开 原则(包含 start,不包含 stop)。

range(5)          # 生成 0, 1, 2, 3, 4
range(2, 6)       # 生成 2, 3, 4, 5
range(10, 0, -2)  # 生成 10, 8, 6, 4, 2 (负步长反向递减)

# 实战:累加 1 到 100
total = 0
for i in range(1, 101):
    total += i
print(total)  # 输出: 5050

4. 循环辅助利器:enumerate() 与 zip()

# 1. enumerate(): 获取索引和元素
fruits = ["apple", "banana", "orange"]
for index, fruit in enumerate(fruits, start=1):
    print(f"序号 {index}: {fruit}")

# 2. zip(): 并行遍历多个可迭代对象
names = ["张三", "李四"]
scores = [95, 88]
for name, score in zip(names, scores):
    print(f"{name} 得分: {score}")

2.4 循环控制 (break / continue / loop-else)

1. break 与 continue

# continue 示例:打印 1-5 中的奇数
for i in range(1, 6):
    if i % 2 == 0:
        continue  # 偶数跳过
    print(i)      # 输出: 1, 3, 5

# break 示例:查找元素
for i in range(10):
    if i == 3:
        break     # 遇到 3 立即退出循环
    print(i)      # 输出: 0, 1, 2

2. 循环特有语法:loop-else 结构

for-else 和 while-else 是 Python 独有的结构: - else 块执行条件:当循环正常执行完毕(没有触发 break)时执行。 - 典型场景:用于搜索/检索任务。若找到了直接 break,不触发 else;若找遍了都没找到,触发 else 处理未找到的逻辑。

numbers = [1, 3, 5, 7, 9]
target = 4

for num in numbers:
    if num == target:
        print("找到了目标元素!")
        break
else:
    # 只有当 for 循环完整运行且没有被 break 打断时才会触发
    print("未找到目标元素!")

3. 嵌套循环与控制

# 打印九九乘法表
for i in range(1, 10):
    for j in range(1, i + 1):
        print(f"{j}x{i}={i*j}", end="\t")
    print()  # 换行

三、 容器类数据类型


3.1 列表 (List) 与 一维/多维列表

列表是可变 (Mutable)、有序的元素序列,允许重复元素,元素类型可不相同。

1. 列表常用 API 概览 (CRUD)

lst = [10, 20, 30]

# --- 1. 增加元素 ---
lst.append(40)         # 末尾追加单元素: [10, 20, 30, 40]
lst.extend([50, 60])   # 末尾合并序列: [10, 20, 30, 40, 50, 60]
lst.insert(1, 15)      # 指定索引插入: [10, 15, 20, 30, 40, 50, 60]

# --- 2. 删除元素 ---
val = lst.pop()        # 弹出末尾元素 (60),可传索引指定弹出位置
lst.remove(15)         # 删除首个匹配值,若不存在抛出 ValueError
lst.clear()            # 清空整个列表: []

# --- 3. 查找与统计 ---
arr = [1, 2, 2, 3]
print(arr.index(2))    # 查找元素首个索引位置 -> 1
print(arr.count(2))    # 统计元素出现次数 -> 2

# --- 4. 排序与翻转 ---
num_list = [3, 1, 4, 1, 5, 9]
num_list.sort()        # 原地升序排列: [1, 1, 3, 4, 5, 9]
num_list.sort(reverse=True) # 原地降序排列
num_list.reverse()     # 原地翻转列表

# 非原地排序函数 sorted()
new_list = sorted(num_list)  # 返回新列表,原列表不变

2. 二维列表 (矩阵) 访问与初始化

# 访问二维列表
matrix = [
    [1, 2, 3],
    [4, 5, 6]
]
print(matrix[1][2])  # 访问第 2 行第 3 列 -> 6

# ⚠️ 踩坑提示:二维列表初始化正确姿势
# 错误做法(会导致所有行指向同一内存地址):
# wrong_matrix = [[0] * 3] * 3  # 修改其中一项会影响整列!

# 正确做法(推导式生成):
right_matrix = [[0 for _ in range(3)] for _ in range(3)]

3.2 元组 (Tuple)

元组是不可变 (Immutable)、有序的元素序列。定义后其元素的引用不可修改。

1. 定义与特例

tup = (1, 2, "hello")

# ⚠️ 踩坑提示:单元素元组必须加逗号!
t1 = (10)   # 类型为 int!
t2 = (10,)  # 类型为 tuple!

2. 元组的不可变性陷阱

元组本身不可变,但如果元组内部包含可变对象(如列表),该可变对象内部的值可以被改变:

tup = (1, 2, [10, 20])
# tup[0] = 100        # 报错!TypeError
tup[2].append(30)     # 成功!tup 变为 (1, 2, [10, 20, 30])

3. 常用 API 与应用场景


3.3 字典 (Dict)

字典是基于键值对 (Key-Value) 存储的可变容器。Python 3.7+ 保留元素的插入顺序。 - Key 的要求:必须是可哈希 (Hashable) / 不可变的数据类型(如 int, str, tuple),不能是 list, dict, set。

1. 常用 API 概览

person = {"name": "张三", "age": 18}

# --- 1. 读取与查询 ---
print(person["name"])           # 键不存在会抛出 KeyError
print(person.get("score", 0))   # 安全获取:键不存在时返回默认值 0

# --- 2. 增加与修改 ---
person["age"] = 19              # 键存在时更新
person["gender"] = "男"         # 键不存在时新增
person.update({"age": 20, "city": "北京"}) # 批量更新

# 安全设置默认值
person.setdefault("hobby", "编程") # 键不存在则设置,存在则不操作

# --- 3. 删除 ---
age = person.pop("age")         # 弹出指定 Key 的 Value
item = person.popitem()         # 弹出最后一个键值对 (Key, Value)
del person["name"]              # 删除指定键值对

# --- 4. 视图遍历 ---
print(person.keys())   # 键视图: dict_keys([...])
print(person.values()) # 值视图: dict_values([...])
print(person.items())  # 键值对视图: dict_items([('key', 'val'), ...])

for k, v in person.items():
    print(f"{k}: {v}")

3.4 集合 (Set) 与 集合运算

集合是无序、元素唯一(自动去重)、可变的容器。元素必须可哈希。

1. 定义与基础 API

# 初始化
s1 = {1, 2, 3, 3}  # 自动去重 -> {1, 2, 3}
empty_set = set()   # ⚠️ 注意:{} 创建的是空字典,空集合必须用 set()

# API 操作
s1.add(4)          # 添加元素
s1.remove(2)       # 删除元素,不存在抛出 KeyError
s1.discard(10)     # 安全删除元素,不存在也不报错
s1.pop()           # 随机弹出并返回一个元素

2. 数学集合运算

A = {1, 2, 3, 4}
B = {3, 4, 5, 6}

print(A & B)  # 交集 (Intersection): {3, 4}
print(A | B)  # 并集 (Union): {1, 2, 3, 4, 5, 6}
print(A - B)  # 差集 (Difference): {1, 2}
print(A ^ B)  # 对称差集 (补集): {1, 2, 5, 6}

3.5 容器推导式全集 (Comprehensions)

推导式是从一个或多个迭代器快速简洁地创建新容器的 Pythonic 方法。

# 1. 列表推导式
# 格式: [表达式 for 变量 in 可迭代对象 if 条件]
squares = [x**2 for x in range(10) if x % 2 == 0]
# 结果: [0, 4, 16, 36, 64]

# 2. 字典推导式
# 格式: {键表达式: 值表达式 for 变量 in 可迭代对象 if 条件}
scores = {"张三": 85, "李四": 59, "王五": 92}
passed_scores = {k: v for k, v in scores.items() if v >= 60}
# 键值对翻转
reversed_scores = {v: k for k, v in scores.items()}

# 3. 集合推导式
# 格式: {表达式 for 变量 in 可迭代对象 if 条件}
unique_lengths = {len(name) for name in ["apple", "banana", "pear", "apple"]}
# 结果: {4, 5, 6}

# 4. 嵌套推导式(展平二维列表)
matrix = [[1, 2], [3, 4]]
flattened = [x for row in matrix for x in row]  # [1, 2, 3, 4]

3.6 变量赋值、浅拷贝与深拷贝

Python 中变量名本质上是对内存对象的引用(地址指针)。

1. 三者对比速查表

操作类型 语法示例 外层容器对象 内部嵌套子对象
直接赋值 b = a 共享同一内存地址 共享同一内存地址
浅拷贝 (Shallow) b = a.copy() 或 copy.copy(a) 创建新对象 共享同一内存地址
深拷贝 (Deep) b = copy.deepcopy(a) 创建新对象 递归创建新对象

2. 代码解析与内存行为展示

import copy

# 初始嵌套列表
origin = [1, [2, 3]]

# 1. 直接赋值
ref = origin

# 2. 浅拷贝 (可以使用 lst.copy() / lst[:] / copy.copy(lst))
shallow = copy.copy(origin)

# 3. 深拷贝
deep = copy.deepcopy(origin)

# --- 修改原对象中的嵌套列表 ---
origin[1].append(4)
origin[0] = 999

print(f"原对象:   {origin}")   # [999, [2, 3, 4]]
print(f"直接赋值: {ref}")      # [999, [2, 3, 4]] (全受影响)
print(f"浅拷贝:   {shallow}")  # [1, [2, 3, 4]]   (外层隔离,内层嵌套受影响)
print(f"深拷贝:   {deep}")     # [1, [2, 3]]      (完全独立,不受任何影响)

四、 字符串与文本处理


4.1 字符串索引、切片与基础拼接

字符串是不可变 (Immutable)、有序的字符序列。任何修改字符串的操作都会返回一个全新的字符串对象。

1. 索引与切片语法

s = "Python3.10"

# 1. 索引访问
print(s[0])     # 正向首元素 -> 'P'
print(s[-1])    # 反向尾元素 -> '0'

# 2. 基础切片
print(s[0:6])   # 截取索引 0~5 -> 'Python'
print(s[:6])    # start 默认为 0 -> 'Python'
print(s[6:])    # stop 默认为结尾 -> '3.10'

# 3. 步长控制 (step)
print(s[::2])   # 隔一个取一个 -> 'Pto31'
print(s[::-1])  # 步长为 -1,字符串高效翻转 -> '01.3nohtyP'

2. 字符串拼接性能避坑

在循环中拼串时,严禁使用 + 运算符(会导致频繁分配内存,性能极差 $O(n^2)$),推荐使用 join()。

# ❌ 低效做法
res = ""
for char in ["a", "b", "c"]:
    res += char

# ✅ 高效做法 (Pythonic)
res = "".join(["a", "b", "c"])  # "abc"

4.2 常用 API (查找 / 替换 / 分割 / 拼接 / 大小写 / 类型判断)

1. 查找与前缀匹配

text = "hello python world"

# find() vs index()
print(text.find("python"))   # 返回首字符索引 -> 6
print(text.find("java"))     # 查找失败返回 -1 (推荐,不报错)
# print(text.index("java"))  # 查找失败抛出 ValueError !

# 前后缀检测 (支持传入元组匹配多个)
print(text.startswith("hello"))            # -> True
print(text.endswith((".png", ".jpg", "world"))) # -> True

# 统计出现次数
print(text.count("o"))       # -> 3

2. 替换与裁剪 (Strip)

s = "  --Python--  "

# 替换 replace(old, new[, count])
print("aabbcc".replace("b", "x", 1))  # 仅替换 1 次 -> "aaxbcc"

# 裁剪空白或指定字符 strip() / lstrip() / rstrip()
print(s.strip())       # 清除两端空格 -> "--Python--"
print(s.strip(" -"))   # 清除两端空格和 '-' 字符 -> "Python"

3. 分割 (Split) 与 拼接 (Join)

# 1. 分割 split(sep=None, maxsplit=-1)
raw_str = "apple,banana,orange"
fruits = raw_str.split(",")  # -> ['apple', 'banana', 'orange']

# 限定分割次数
print("a-b-c-d".split("-", 2)) # -> ['a', 'b', ['c-d']]

# 2. 拼接 join(iterable)
lines = ["line1", "line2", "line3"]
content = "\n".join(lines)   # 用换行符拼接

4. 大小写转换与字符类型检测

# --- 大小写转换 ---
s = "hEllo WORLD"
print(s.upper())      # 全大写 -> "HELLO WORLD"
print(s.lower())      # 全小写 -> "hello world"
print(s.title())      # 每个单词首字母大写 -> "Hello World"
print(s.capitalize()) # 全句首字母大写 -> "Hello world"
print(s.swapcase())   # 大小写翻转 -> "HeLLO world"

# --- 判断方法 (返回 True/False) ---
print("12345".isdigit())   # 是否全为数字 -> True
print("abc".isalpha())     # 是否全为字母 -> True
print("a123".isalnum())    # 是否全为字母或数字 -> True
print("   ".isspace())     # 是否全为空白字符 (\n, \t, 空格) -> True

4.3 字符串格式化 (f-string / format / %)

优先推荐使用 f-string(Python 3.6+ 引入),语法简洁且执行速度最快。

1. f-string 基础语法与表达式计算

name = "张三"
age = 18

# 1. 变量插值
print(f"姓名: {name}, 年龄: {age}")

# 2. 内联表达式计算与函数调用
print(f"明年年龄: {age + 1}")
print(f"大写姓名: {name.upper()}")

2. f-string 进阶格式化技巧 (数字/对齐/调试)

import math

# 1. 保留小数位数 (精度)
pi = 3.1415926
print(f"圆周率: {pi:.2f}")       # -> "3.14"

# 2. 百分比格式化
ratio = 0.756
print(f"完成率: {ratio:.1%}")      # -> "75.6%"

# 3. 千位分隔符
money = 100000000
print(f"余额: {money:,}")          # -> "100,000,000"

# 4. 对齐与填充 ({变量:填充字符 格式 宽度})
# < 左对齐, > 右对齐, ^ 居中
print(f"{'Header':^20}")          # -> "       Header       " (居中, 默认空格填充)
print(f"{'Code':*<10}")           # -> "Code******" (左对齐, * 填充)

# 5. 自报表达式 / 调试助手 (Python 3.8+)
x = 10
y = 20
print(f"{x=}, {y=}, {x+y=}")      # 输出: x=10, y=20, x+y=30

3. 三种格式化方式对比速查

name, score = "李四", 95.5

# 1. f-string (推荐)
print(f"{name} 成绩是 {score:.1f}")

# 2. str.format() 方法
print("{} 成绩是 {:.1f}".format(name, score))

# 3. % 占位符 (老旧传统方式)
print("%s 成绩是 %.1f" % (name, score))

五、 函数与模块


5.1 函数定义、调用与命名规范

函数是组织好的、可重复使用的、用来实现单一或相关联功能的代码块。

1. 基础语法与类型注解 (Type Hints)

def calculate_area(width: float, height: float) -> float:
    """计算矩形面积 (Docstring 提示文档)

    :param width: 矩形宽度
    :param height: 矩形高度
    :return: 面积数值
    """
    return width * height

# 函数调用
area = calculate_area(5.0, 3.0)

2. 命名规范与文档查看


5.2 参数全解 (位置 / 默认 / *args / **kwargs / 组合顺序)

1. 常用参数类型

# 1. 位置参数与关键字参数
def greet(name, msg):
    print(f"{msg}, {name}!")

greet("张三", "你好")          # 位置传参(顺序匹配)
greet(msg="早上好", name="李四") # 关键字传参(按名称匹配,与顺序无关)

# 2. 可变长位置参数 *args (解包为元组 Tuple)
def sum_all(*args):
    return sum(args)  # args 为 (1, 2, 3)

print(sum_all(1, 2, 3)) # -> 6

# 3. 可变长关键字参数 **kwargs (解包为字典 Dict)
def print_info(**kwargs):
    for k, v in kwargs.items():
        print(f"{k}: {v}")

print_info(name="王五", age=20)

2. ⚠️ 经典踩坑:默认参数绝不能为可变对象!

如果在定义函数时将默认参数设置为可变对象(如列表、字典),该默认值在函数定义时被初始化一次,后续所有未传参的调用都会共享同一个内存对象!

# ❌ 错误示范:
def add_item(item, target_list=[]):
    target_list.append(item)
    return target_list

print(add_item(1)) # -> [1]
print(add_item(2)) # -> [1, 2] (并非预期的 [2]!)

# ✅ 正确示范:使用 None 作为占位符
def add_item_safe(item, target_list=None):
    if target_list is None:
        target_list = []
    target_list.append(item)
    return target_list

3. 参数严格排列顺序规范

Python 中多种参数混用时,必须遵循以下固定的定义顺序:

$$ \text{位置参数} \longrightarrow \text{默认参数} \longrightarrow \text{*args} \longrightarrow \text{仅限关键字参数} \longrightarrow \text{**kwargs} $$

# 限定关键字参数 (* 后的参数必须使用关键字传参)
def complex_func(a, b=10, *args, c, **kwargs):
    print(a, b, args, c, kwargs)

complex_func(1, 2, 3, 4, c=100, x=99)
# a=1, b=2, args=(3, 4), c=100, kwargs={'x': 99}

5.3 返回值与多值返回

# 多值返回本质:打包为元组 (Tuple) 返回
def get_user_data():
    name = "张三"
    age = 18
    return name, age  # 相当于返回 (name, age)

# 接收多返回值 (元组解包)
user_name, user_age = get_user_data()

5.4 变量作用域 (LEGB 规则 / global / nonlocal)

1. LEGB 变量查找顺序

Python 查找变量名时按以下 4 个层级从内向外依次搜索: 1. L (Local):函数内部局部作用域。 2. E (Enclosing):嵌套函数中外层非全局作用域(闭包)。 3. G (Global):当前模块文件全局作用域。 4. B (Built-in):Python 内置作用域(如 len, str)。

  Built-in (内置)
    └─ Global (全局)
        └─ Enclosing (嵌套外层)
            └─ Local (局部)  <-- 最先查找

2. global 与 nonlocal 关键字

在内层作用域中修改外层变量时,必须显式使用关键字声明:

count = 0  # 全局变量

def outer():
    num = 10  # 外层嵌套变量

    def inner():
        global count
        nonlocal num

        count += 1  # 修改全局变量 count
        num += 5    # 修改外层非全局变量 num

    inner()
    print("outer num:", num) # -> 15

outer()
print("global count:", count) # -> 1

5.5 高阶函数、闭包 (Closure) 与 Lambda 匿名函数

1. Lambda 匿名函数

add = lambda x, y: x + y
print(add(3, 5))  # -> 8

# 结合 sorted() 实现自定义排序规则
students = [("张三", 88), ("李四", 95), ("王五", 70)]
students.sort(key=lambda item: item[1], reverse=True) # 按成绩降序

2. 常用内置高阶函数 (map / filter / reduce)

from functools import reduce

nums = [1, 2, 3, 4, 5]

# 1. map(func, iterable): 映射处理
squared = list(map(lambda x: x**2, nums))  # [1, 4, 9, 16, 25]

# 2. filter(func, iterable): 过滤筛选
evens = list(filter(lambda x: x % 2 == 0, nums))  # [2, 4]

# 3. reduce(func, iterable): 累积化简
sum_val = reduce(lambda x, y: x + y, nums)  # 1+2+3+4+5 = 15

3. 闭包 (Closure) 概念

闭包条件:必须有嵌套函数,内层函数引用了外层函数的变量,并且外层函数返回内层函数本身。

def make_counter():
    count = 0  # 被自由变量引用的状态

    def counter():
        nonlocal count
        count += 1
        return count

    return counter

# 创建独立计数器实例
counter_a = make_counter()
print(counter_a()) # -> 1
print(counter_a()) # -> 2

5.6 递归函数与常用核心内置函数速查

1. 递归函数要点

# 经典递归:阶乘 n!
def factorial(n: int) -> int:
    if n <= 1:
        return 1  # 终止条件
    return n * factorial(n - 1)  # 递归调用

2. 核心内置函数全集速查表

函数 API 作用说明 示例与返回值
abs(x) 求绝对值 abs(-10) -> 10
all(iterable) 元素全为真才返回 True all([1, True, "a"]) -> True
any(iterable) 只要有一个元素为真即返回 True any([0, False, "a"]) -> True
isinstance(obj, class) 安全检查对象类型(支持继承链) isinstance(10, int) -> True
eval(expression) 执行字符串中的 Python 表达式 eval("1 + 2") -> 3
zip(*iterables) 多序列并行打包为元组迭代器 dict(zip(["a", "b"], [1, 2])) -> {'a': 1, 'b': 2}
dir(obj) 查看对象的所有属性与方法列表 dir([])
id(obj) 获取对象的内存地址指针 id(a)

六、 面向对象编程 (OOP)


6.1 类与对象 (self / __init__)

面向对象通过“类”(Blueprint)来创建“对象”(Instance)。

class Student:
    # 构造方法
    def __init__(self, name: str, age: int):
        # 绑定实例属性
        self.name = name
        self.age = age

    # 实例方法
    def study(self, course: str):
        print(f"{self.name} (年龄: {self.age}) 正在学习 {course}")

# 实例化对象
stu1 = Student("张三", 18)
stu1.study("Python")  # 输出: 张三 (年龄: 18) 正在学习 Python

6.2 属性分类 (实例属性 / 类属性)

属性类型 定义位置 内存形态 访问方式
实例属性 __init__ 或方法内部使用 self.attr 每个对象独立享有一份 self.attr 或 instance.attr
类属性 类体内部,方法体外部 所有实例共享同一份内存空间 ClassName.attr (推荐) 或 self.attr
class ChinesePerson:
    # 类属性 (共享数据)
    country = "中国"

    def __init__(self, name: str):
        # 实例属性 (独享数据)
        self.name = name

p1 = ChinesePerson("李四")
p2 = ChinesePerson("王五")

# 修改类属性 (建议通过类名修改)
ChinesePerson.country = "中华人民共和国"
print(p1.country, p2.country)  # 输出: 中华人民共和国 中华人民共和国

# ⚠️ 踩坑提示:通过实例赋值会隐式创建“实例属性”,遮蔽“类属性”
p1.country = "China"  # 这仅在 p1 实例中创建了同名的实例属性!
print(p1.country)     # -> "China"
print(p2.country)     # -> "中华人民共和国" (类属性不受影响)

6.3 方法分类 (实例方法 / @classmethod / @staticmethod)

class DateFormatter:
    # 类属性
    date_format = "YYYY-MM-DD"

    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    # 1. 实例方法 (第一个参数为 self,访问/修改实例状态和类状态)
    def display(self):
        return f"{self.year}-{self.month:02d}-{self.day:02d}"

    # 2. 类方法 (使用 @classmethod,第一个参数为 cls,常用于做工厂构造函数)
    @classmethod
    def from_string(cls, date_str: str):
        # 传入 "2024-01-15",解析并返回一个新的对象实例
        year, month, day = map(int, date_str.split("-"))
        return cls(year, month, day)  # 相当于 DateFormatter(year, month, day)

    # 3. 静态方法 (使用 @staticmethod,无隐式传递参数,纯逻辑工具函数)
    @staticmethod
    def is_valid_year(year: int) -> bool:
        return 1000 <= year <= 9999

# 调用演示
d = DateFormatter.from_string("2024-05-20") # 使用类方法工厂构造对象
print(d.display())                           # -> "2024-05-20"
print(DateFormatter.is_valid_year(2024))     # -> True

6.4 核心魔法方法 (Magic / Dunder Methods)

魔法方法是 Python 中以双下划线开头和结尾的方法 (__method__),用于重载运算符或响应特定语言行为。

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

    # 1. __str__: print(obj) 或 str(obj) 时调用 (面向用户,可读性好)
    def __str__(self):
        return f"Vector({self.x}, {self.y})"

    # 2. __repr__: 交互式命令行显示或 repr(obj) 时调用 (面向开发者,精确清晰)
    def __repr__(self):
        return f"Vector(x={self.x}, y={self.y})"

    # 3. __add__: 运算符重载 (+)
    def __add__(self, other):
        if isinstance(other, Vector):
            return Vector(self.x + other.x, self.y + other.y)
        raise TypeError("加数必须为 Vector 类型")

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

    # 5. __call__: 使对象实例像函数一样可直接被调用 obj()
    def __call__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

v1 = Vector(1, 2)
v2 = Vector(3, 4)

print(v1)         # 调用 __str__ -> Vector(1, 2)
print(v1 + v2)    # 调用 __add__ -> Vector(4, 6)
print(v1 == v2)   # 调用 __eq__  -> False
v3 = v1(3)        # 调用 __call__ -> Vector(3, 6)

6.5 三大特性:封装、继承、多态与鸭子类型

1. 封装 (Encapsulation) 与 @property 装饰器

Python 没有严格的 private 关键字,采用约定俗成的下划线控制受访级别: - _protected(受保护):单下划线开头,建议仅类及子类内部使用。 - __private(私有属性):双下划线开头,触发名称改写机制 (Name Mangling),外部变为 _ClassName__attr 无法直接访问。

class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner
        self.__balance = balance  # 私有属性,防非法篡改

    # 使用 @property 将方法伪装为“属性”进行安全读取 (Getter)
    @property
    def balance(self):
        return self.__balance

    # 安全写入限制 (Setter)
    @balance.setter
    def balance(self, amount):
        if amount < 0:
            raise ValueError("余额不能为负数!")
        self.__balance = amount

acc = BankAccount("张三", 1000)
print(acc.balance)     # 触发 Getter -> 1000
acc.balance = 1500     # 触发 Setter
# acc.__balance        # 抛出 AttributeError!

2. 继承 (Inheritance) 与 super()

子类可以复用父类的属性和方法,并通过 super() 显式调用父类方法。

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

    def make_sound(self):
        print("发出声音...")

# 子类
class Dog(Animal):
    def __init__(self, name, breed):
        # 使用 super() 调用父类 __init__ 初始化基础属性
        super().__init__(name)
        self.breed = breed

    # 方法重写 (Override)
    def make_sound(self):
        print(f"{self.name} (汪汪汪!)")

dog = Dog("旺财", "金毛")
dog.make_sound()  # -> 旺财 (汪汪汪!)

💡 C3 算法与 MRO (方法解析顺序):多重继承下通过 Dog.__mro__ 或 Dog.mro() 可查看 Python 搜索方法的继承链顺序。

3. 多态 (Polymorphism) 与“鸭子类型” (Duck Typing)

Python 是一种动态语言,关注的是对象的行为(方法和接口),而不是对象的继承结构类型。

"如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子。"

class Duck:
    def fly(self):
        print("鸭子在飞")

class Airplane:
    def fly(self):
        print("飞机在飞")

# 只要传入的对象拥有 fly() 方法,即可直接调用,无需强制继承自某一基类
def make_it_fly(flyable_obj):
    flyable_obj.fly()

make_it_fly(Duck())     # -> 鸭子在飞
make_it_fly(Airplane()) # -> 飞机在飞

6.6 对象间关系 (组合 vs 继承)

# 组合关系代码示例
class CPU:
    def calculate(self):
        print("CPU 高速运算中...")

class Memory:
    def load(self):
        print("内存加载数据中...")

class Computer:
    def __init__(self):
        # 内部持有其它对象实例 (Has-A)
        self.cpu = CPU()
        self.memory = Memory()

    def start(self):
        self.cpu.calculate()
        self.memory.load()
        print("电脑开机完成!")

pc = Computer()
pc.start()

七、 文件操作、序列化与异常处理


7.1 文件读写与打开模式 (文本/二进制)

Python 内置 open() 函数用于打开文件,获得文件句柄。

1. 核心文件打开模式速查表

模式 说明 文件不存在时 指针位置 特点
r 只读 (默认) 抛出 FileNotFoundError 文件开头 只能读取
w 只写 创建新文件 文件开头 覆写! 会清空原有内容
a 追加写入 创建新文件 文件末尾 在旧内容末尾追加
rb / wb 二进制模式 同上 同上 读取/写入 bytes (如图片、音视频)
r+ 读写模式 抛出 FileNotFoundError 文件开头 可读可写

2. 读取文件 API 对比

# 1. read([size]): 读取全部内容 (或指定字符数) -> 字符串
# ⚠️ 踩坑提示:大文件严禁直接 read(),容易导致 OOM 内存溢出!
content = f.read()

# 2. readline(): 逐行读取 -> 字符串
line = f.readline()

# 3. readlines(): 读取所有行 -> 字符串列表 ['line1\n', 'line2\n']
lines = f.readlines()

# ✅ 处理大文件的最佳姿势:利用文件对象迭代器 (内存高效 $O(1)$)
with open("large_file.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line.strip())  # 逐行加载处理,不占用大量内存

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

使用 with 语句打开文件,无论代码执行是否发生异常,都会在退出代码块时自动调用 close() 释放系统资源。

# 基础用法
with open("example.txt", "r", encoding="utf-8") as f:
    content = f.read()

# 同时打开多个文件 (如文件复制)
with open("source.jpg", "rb") as src, open("target.jpg", "wb") as dst:
    dst.write(src.read())

7.3 结构化数据文件处理与路径操作

1. 路径操作 API (os / os.path)

import os

# 1. 路径拼接 (跨平台兼容,自动处理斜杠)
full_path = os.path.join("data", "logs", "app.log")

# 2. 检查路径是否存在
if os.path.exists(full_path):
    print("文件存在")

# 3. 获取当前工作目录与绝对路径
print(os.getcwd())
print(os.path.abspath("example.txt"))

2. JSON 数据读写 (json 模块)

用于跨语言数据交换、配置文件读写。仅支持基本数据类型(列表、字典、字符串、数字、布尔、None)。

import json

data = {"name": "张三", "age": 18, "is_student": True}

# --- 1. 写入 JSON 文件 ---
with open("data.json", "w", encoding="utf-8") as f:
    # ensure_ascii=False 确保中文字符不转义;indent=4 格式化缩进
    json.dump(data, f, ensure_ascii=False, indent=4)

# --- 2. 读取 JSON 文件 ---
with open("data.json", "r", encoding="utf-8") as f:
    loaded_data = json.load(f)

# --- 3. 内存字符串转换 ---
json_str = json.dumps(data, ensure_ascii=False) # 对象 -> JSON 字符串
obj = json.loads(json_str)                      # JSON 字符串 -> 对象

3. CSV 表格文件读写 (csv 模块)

import csv

# --- 1. 写入 CSV 文件 (列表方式 / 字典方式) ---
# ⚠️ 注意:必须指定 newline="",防止 Windows 下出现空行
with open("students.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerow(["姓名", "年龄", "成绩"])      # 写入表头
    writer.writerows([["张三", 18, 95], ["李四", 20, 88]]) # 写入多行数据

# --- 2. 读取 CSV 文件 (字典方式) ---
with open("students.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)  # 将每行自动映射为字典
    for row in reader:
        print(row["姓名"], row["成绩"])

7.4 对象序列化 (pickle vs json)

序列化是指将内存中的对象转换为二进制流或文本以便保存或传输的过程。

特性 pickle (Python 专用) json (跨语言标准)
兼容性 仅限 Python 语言内部 跨所有语言通用
支持数据类型 几乎所有 Python 对象 (类、自定义实例等) 仅基础类型 (Dict, List, Str 等)
文件格式 二进制 (Binary) 文本 (Text)
安全性 ⚠️ 存在安全风险 (反序列化可能执行恶意代码) 安全
import pickle

data = {"a": 1, "b": [1, 2, 3]}

# 序列化保存到二进制文件
with open("data.pkl", "wb") as f:
    pickle.dump(data, f)

# 反序列化读取
with open("data.pkl", "rb") as f:
    obj = pickle.load(f)

7.5 异常处理 (try-except-else-finally / raise / 自定义异常)

1. 完整异常捕捉结构与执行流程

try:
    # 可能会发生异常的代码
    num1 = int(input("输入被除数: "))
    num2 = int(input("输入除数: "))
    result = num1 / num2
except ZeroDivisionError as e:
    # 捕捉具体的除零异常
    print(f"错误: 除数不能为零!({e})")
except ValueError:
    # 捕捉类型转换异常
    print("错误: 请输入有效的整数!")
except Exception as e:
    # 捕捉所有其它未预期的基类异常 (兜底)
    print(f"未知异常: {e}")
else:
    # 没有发生任何异常时执行
    print(f"计算成功,结果: {result}")
finally:
    # 无论是否发生异常,最终都会被执行 (常用于清理资源)
    print("程序执行结束,清理工作完成。")

2. 主动抛出异常 (raise) 与 自定义异常

通过继承 Exception 类可以定义符合业务特性的自定义异常。

# 1. 自定义异常类
class InvalidAgeError(Exception):
    """当输入的年龄不在合法范围内时抛出"""
    def __init__(self, age):
        super().__init__(f"非法年龄: {age},年龄必须在 0 到 150 之间!")

# 2. 校验逻辑与主动抛出 raise
def check_user_age(age: int):
    if age < 0 or age > 150:
        raise InvalidAgeError(age)  # 主动抛出异常
    print(f"年龄校验通过: {age}")

# 3. 捕获使用
try:
    check_user_age(200)
except InvalidAgeError as e:
    print(f"捕获业务异常 -> {e}")

3. 常见内置异常速查列表


八、 正则表达式与网络爬虫基础


8.1 正则表达式元字符与语法速查

正则表达式 (Regular Expression) 用于检索、替换或提取符合特定模式的文本。

1. 单个字符匹配元字符

元字符 匹配范围 / 说明 示例
. 匹配除换行符以外的任意单个字符 a.c 可匹配 abc, a1c
\d / \D \d 匹配数字 [0-9];\D 匹配非数字 \d\d 可匹配 12
\w / \W \w 匹配字母、数字、下划线、汉字;\W 匹配非单词字符 \w+
\s / \S \s 匹配任意空白字符 (\n, \t, 空格);\S 匹配非空白 \s+
[...] 字符集:匹配集中包含的任意单个字符 [a-zA-Z0-9] 匹配英数字
[^...] 否定字符集:匹配不在集中包含的任意字符 [^0-9] 匹配非数字字符

2. 量词 (匹配次数)

量词 说明 示例
* 匹配 0 次或多次 ($\ge 0$) a*
+ 匹配 1 次或多次 ($\ge 1$) a+
? 匹配 0 次或 1 次 ($0$ 或 $1$) a?
{n} / {n,m} {n} 匹配指定 $n$ 次;{n,m} 匹配 $n$ 到 $m$ 次 \d{11} (匹配 11 位手机号)

3. 边界匹配与贪婪/非贪婪模式

4. 分组与捕获


8.2 Python re 模块核心 API

1. 核心匹配 API 对比

import re

text = "Apple 100元, Banana 200元"

# 1. re.match(): 从字符串【开头】开始匹配,开头不匹配则返回 None
m = re.match(r"\w+", text)
print(m.group())  # -> "Apple"

# 2. re.search(): 扫描整个字符串,返回【第一个】匹配成功的 Match 对象
s = re.search(r"\d+", text)
print(s.group())  # -> "100"

# 3. re.findall(): 搜索整个字符串,以【列表 List】形式返回所有匹配子串
items = re.findall(r"(\w+)\s+(\d+)元", text)
print(items)  # -> [('Apple', '100'), ('Banana', '200')]

# 4. re.finditer(): 以【迭代器】形式返回 Match 对象,大文本处理省内存
for match in re.finditer(r"\d+", text):
    print(match.group(), match.span()) # 输出匹配值与起止索引位置

# 5. re.sub(pattern, repl, string): 替换匹配项
clean_text = re.sub(r"\d+元", "赠送", text)
print(clean_text)  # -> "Apple 赠送, Banana 赠送"

# 6. re.split(): 基于正则表达式分割字符串
parts = re.split(r"[,\s]+", text)
# -> ['Apple', '100元', 'Banana', '200元']

2. 常用修饰符标志 (Flags) 与 模式预编译

# 推荐:预编译正则表达式 (多次重用时提升执行效率)
pattern = re.compile(r"<title>(.*?)</title>", re.S | re.I)
html = "<html><TITLE>\nPython 爬虫手册\n</TITLE></html>"
title = pattern.findall(html)  # ['\nPython 爬虫手册\n']

8.3 爬虫基础流程与原生 urllib 请求实战

1. 网络爬虫基本工作流程

  1. 构建请求:设置 URL、请求头 (User-Agent 防封)、请求参数。
  2. 发送请求并获取响应:向服务器发送 HTTP 请求,接收网页响应内容 (HTML/JSON)。
  3. 解析数据:使用正则表达式(或 BeautifulSoup/lxml)提取目标字段。
  4. 数据存储:将提取结果保存至本地文件 (CSV/JSON/数据库)。

2. 原生 urllib 请求与 User-Agent 伪装

import urllib.request
import urllib.parse
import re

# 目标 URL
url = "https://httpbin.org/get"

# 伪装请求头 (User-Agent 反爬突破)
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}

# 1. 构建 Request 请求对象
req = urllib.request.Request(url=url, headers=headers)

try:
    # 2. 发送请求,获取 Response 对象
    with urllib.request.urlopen(req, timeout=5) as response:
        # 3. 读取字节流并解码为字符串
        html_code = response.read().decode("utf-8")
        print("请求成功,状态码:", response.status)

except urllib.error.HTTPError as e:
    print(f"HTTP 错误: {e.code}, 原因: {e.reason}")
except urllib.error.URLError as e:
    print(f"网络连接错误: {e.reason}")

3. 参数编码处理 (urllib.parse)

当 GET 请求 URL 中包含中文或特殊字符时,需要进行 URL 编码转义:

import urllib.parse

# 1. 单个字符串编码与解码
encoded = urllib.parse.quote("Python 爬虫")  # -> 'Python%20%E7%88%AC%E insect...'
decoded = urllib.parse.unquote(encoded)

# 2. 字典批量转为 URL 查询参数字符串
params = {"kw": "三国演义", "page": 1}
query_str = urllib.parse.urlencode(params)  # -> 'kw=%E4%B8%89%E5%9B%BD%E4%BC%A0%E4%B9%89&page=1'
full_url = f"https://example.com/search?{query_str}"

4. 综合实战:简易提取并保存网页标题与链接

import urllib.request
import re
import json

def fetch_and_parse(target_url):
    headers = {"User-Agent": "Mozilla/5.0"}
    req = urllib.request.Request(target_url, headers=headers)

    try:
        with urllib.request.urlopen(req) as resp:
            html = resp.read().decode("utf-8")

        # 使用正则表达式提取超链接中的文本和 URL (非贪婪匹配 + re.S)
        # 匹配格式: <a href="链接">文本</a>
        pattern = re.compile(r'<a\s+href=["\'](?P<url>http[s]?://.*?)["\']\s*>(?P<text>.*?)</a>', re.S)
        matches = pattern.finditer(html)

        results = []
        for m in matches:
            clean_text = re.sub(r"<.*?>|\s+", "", m.group("text")) # 清洗内嵌标签与空白
            if clean_text:
                results.append({"text": clean_text, "url": m.group("url")})

        # 写入 JSON 文件保存
        with open("links.json", "w", encoding="utf-8") as f:
            json.dump(results, f, ensure_ascii=False, indent=4)
        print(f"成功提取并保存 {len(results)} 条链接数据!")

    except Exception as e:
        print(f"爬取失败: {e}")

# 执行提取
# fetch_and_parse("target_url")

九、 数据分析三剑客

9.1 Numpy

Numpy

9.2 Pandas

Pandas

9.3 MatPlotLib

Matplotlib

十、FastAPI

FastAPI