Python 基础教程
Python 基础教程
Python 是一种简单易学、功能强大的编程语言,由 Guido van Rossum 于 1991 年发布。它以清晰的语法和丰富的生态著称,广泛应用于 Web 开发、数据分析、人工智能、自动化脚本等领域。
本教程内容
本教程从 Python 的简介与环境搭建讲起,系统覆盖:基础语法、变量与数据类型、运算符、条件与循环、数字/字符串/列表/元组/字典、函数、模块、文件操作、异常处理、面向对象、正则表达式、网络编程、多线程,以及 JSON、MySQL、GUI 等应用主题。
Python 的特点
- 语法简洁:缩进即代码块,可读性强
- 解释执行:无需编译,即写即跑
- 动态类型:变量无需声明类型
- 丰富的标准库与第三方生态
- 跨平台:Windows / macOS / Linux
- 胶水语言:易与其他语言集成
版本说明
Python 2 已于 2020 年停止维护,新项目请使用 Python 3。本教程内容以 Python 3 为主,同时介绍 2.x 与 3.x 的主要区别。
学习建议
动手实践是学习编程的关键:每章代码亲自运行,配合课后练习。多写多改,理解会更深。
Python 简介
Python 简介
Python 是一门高级、解释型、通用编程语言,以其简洁优雅的语法和"开箱即用"的标准库深受开发者喜爱。
历史
- 1989 年:Guido van Rossum 开始设计 Python
- 1991 年:第一个公开版本发布
- 2000 年:Python 2.0
- 2008 年:Python 3.0(不兼容 2.x 的重大升级)
- 2020 年:Python 2 正式停止维护
能做什么
- Web 开发:Django、Flask、FastAPI
- 数据分析:NumPy、Pandas、Matplotlib
- 人工智能:PyTorch、TensorFlow、scikit-learn
- 自动化:脚本、爬虫、运维工具
- 科学计算:SciPy、SymPy
- 桌面应用:Tkinter、PyQt
Hello World
print("Hello, Python!")
# 输出: Hello, Python!
为什么选择 Python
- 学习曲线平缓,适合入门
- 代码量少,开发效率高
- 社区庞大,问题容易找到答案
- AI 时代的首选语言之一
运行方式
# 方式1: 交互式解释器
python
# 方式2: 运行脚本文件
python hello.py
# 方式3: 直接执行代码字符串
python -c "print('hi')"
Python 环境搭建
Python 环境搭建
开始 Python 编程前,需要安装 Python 解释器并配置开发环境。本节介绍各平台的安装方法。
Windows 安装
# 1. 访问 python.org 下载 Windows 安装包
# 2. 勾选 "Add Python to PATH"(重要!)
# 3. 点击 Install Now
# 验证
python --version
macOS 安装
# 方式1: 官方安装包
# 方式2: Homebrew(推荐)
brew install python
# 验证
python3 --version
Linux 安装
# Debian/Ubuntu
sudo apt update
sudo apt install python3 python3-pip
# CentOS/RHEL
sudo yum install python3
包管理 pip
# 安装包
pip install requests
# 指定版本
pip install numpy==1.26.4
# 查看已安装
pip list
# 卸载
pip uninstall requests
# 国内镜像加速
pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple
虚拟环境(推荐)
# 创建虚拟环境(隔离项目依赖)
python -m venv myenv
# 激活
# Windows
myenv\Scripts\activate
# macOS/Linux
source myenv/bin/activate
# 退出
deactivate
# 或用 conda(科学计算常用)
conda create -n myenv python=3.11
conda activate myenv
开发工具
# 推荐编辑器/IDE:
# - VS Code + Python 扩展(轻量推荐)
# - PyCharm(功能全)
# - Jupyter Notebook(数据分析)
# - IDLE(自带,入门)
# VS Code 插件:
# Python, Pylance, Jupyter
验证环境
python --version
pip --version
# 运行第一个程序
python -c "print('环境就绪!')"
环境就绪后,就可以开始学习 Python 基础语法了。
Python 基础语法
Python 基础语法
Python 语法以简洁著称:缩进定义代码块、无需分号、无需声明类型。本节快速浏览核心语法。
注释
# 单行注释
"""
多行注释(用三引号)
或文档字符串
"""
缩进与代码块
# Python 用缩进(通常 4 空格)表示代码块
if x > 0:
print("正数") # 缩进的代码属于 if
print("继续")
print("无条件执行") # 不缩进,独立
# 不要混用 Tab 与空格(报错!)
变量与赋值
name = "Python" # 字符串
age = 30 # 整数
pi = 3.14 # 浮点
ok = True # 布尔
tags = ["a", "b"] # 列表
# 动态类型:无需声明
# 变量可重新赋不同类型的值
x = 1
x = "现在是字符串"
输入输出
# 输出
print("Hello")
print("值:", 42)
print(f"格式化: {name} 年龄 {age}") # f-string
print("拼接", "多个", "参数")
# 输入
name = input("请输入名字: ")
print(f"你好, {name}")
常用内建函数
len("abc") # 长度 3
type(123) # <class 'int'>
int("42") # 转整数
float("3.14") # 转浮点
str(123) # 转字符串
list("abc") # ['a', 'b', 'c']
range(5) # 0..4
sum([1,2,3]) # 6
max(1,5,3) # 5
abs(-5) # 5
标识符规则
# 命名规则:
# - 字母/数字/下划线组成,不能数字开头
# - 区分大小写(Name 与 name 不同)
# - 关键字不可作变量名(if, for, class 等)
# 命名约定:
# - 变量/函数: snake_case(my_name)
# - 类: PascalCase(MyClass)
# - 常量: ALL_CAPS(MAX_SIZE)
多行与续行
# 长表达式可用括号换行
total = (1 + 2 + 3
+ 4 + 5)
# 或反斜杠续行
total = 1 + 2 + \
3 + 4
Python 语法重在"可读性":缩进即结构。养成 4 空格缩进、snake_case 命名的习惯,代码自然清晰。
Python 变量类型
Python 变量类型
Python 是动态类型语言,变量可以指向任意类型的对象。本节介绍 Python 的内置数据类型。
基本类型
# 数字
x = 10 # int 整数
y = 3.14 # float 浮点
z = 2 + 3j # complex 复数
# 布尔
t = True
f = False
# 字符串
s = "hello"
s2 = 'world'
# 空值
nothing = None
容器类型
# 列表(有序,可变)
lst = [1, 2, 3]
lst.append(4) # [1,2,3,4]
# 元组(有序,不可变)
tup = (1, 2, 3)
# tup[0] = 9 → 报错
# 字典(键值对)
d = {"name": "Python", "age": 30}
d["version"] = "3.11"
# 集合(无序,去重)
s = {1, 2, 2, 3} # {1, 2, 3}
类型检查与转换
type(x) # <class 'int'>
isinstance(x, int) # True
# 转换
int("42") # 字符串 → 整数
float(1) # 整数 → 浮点
str(3.14) # → 字符串
bool(0) # False
list((1,2)) # 元组 → 列表
tuple([1,2]) # 列表 → 元组
可变与不可变
# 不可变(immutable): 修改产生新对象
# 数字、字符串、元组
s = "abc"
s2 = s.upper() # s 不变,产生 "ABC"
# 可变(mutable): 原地修改
# 列表、字典、集合
lst = [1, 2]
lst.append(3) # 原对象被修改
# 注意: 可变对象作为默认参数/共享引用时的坑
变量的内存模型
# 变量是"引用"(指向对象的标签)
a = [1, 2, 3]
b = a # b 和 a 指向同一列表!
b.append(4)
print(a) # [1,2,3,4] ← a 也变了!
# 复制需要显式
c = a.copy() # 浅拷贝
import copy
d = copy.deepcopy(a) # 深拷贝
序列通用操作
s = "hello"
lst = [1, 2, 3]
len(s) # 长度
s[0] # 索引 'h'
s[-1] # 负索引 'o'
lst[1:3] # 切片 [2, 3]
lst[::2] # 步长 [1, 3]
"ell" in s # 成员判断 True
s + "!" # 拼接
[0] * 3 # 重复 [0,0,0]
类型选择指南
# 场景 → 类型
# 有序可变集合 → list
# 有序不可变 → tuple
# 键值映射 → dict
# 去重/集合运算 → set
# 单值 → int/float/str/bool
# 选择原则: 用最合适的类型表达数据
# 让代码更清晰、更不易出错
掌握内置类型与"可变/不可变"、"引用/复制"这两个概念,是写出正确 Python 代码的基础。
Python 运算符
Python 运算符
运算符是表达计算的符号。Python 支持算术、比较、逻辑、赋值、成员、身份等运算符。
算术运算符
a, b = 10, 3
a + b # 13 加
a - b # 7 减
a * b # 30 乘
a / b # 3.333 除(结果为浮点)
a // b # 3 整除(取商)
a % b # 1 取余
a ** b # 1000 幂
# 注意:
7 / 2 # 3.5 (Python3 除法总是浮点)
7 // 2 # 3
比较运算符
1 == 1 # True 等于
1 != 2 # True 不等
2 > 1 # True
1 < 2 # True
1 <= 1 # True
2 >= 3 # False
# 链式比较
1 < x < 10 # x 在 1 和 10 之间
# 注意: == 比较值,is 比较身份
a = [1]
b = [1]
a == b # True(值相同)
a is b # False(不同对象)
逻辑运算符
True and False # False
True or False # True
not True # False
# 短路求值
x = 0 or "默认" # "默认"(or 返回第一个真值)
y = 5 and 10 # 10(and 返回最后一个真值)
# 真值判断
# False、0、空字符串、空容器 为假
if not []: # 空列表为假
print("空列表")
# 推荐写法
if value: # 而非 if value == True
if not items: # 而非 if len(items) == 0
赋值运算符
x = 5
x += 3 # x = 8
x -= 2 # 6
x *= 4 # 24
x /= 3 # 8.0
x //= 2 # 4
x %= 3 # 1
x **= 2 # 1
# 多变量赋值
a = b = c = 0 # 都赋 0
x, y = 1, 2 # 分别赋值
x, y = y, x # 交换(经典!)
成员与身份运算符
# 成员
"a" in "abc" # True
3 in [1, 2, 3] # True
"k" in {"k": 1} # True(字典查键)
5 not in [1, 2] # True
# 身份
a = None
a is None # True(常用!)
a is not None # False
位运算符
# 二进制运算(较少用,了解即可)
5 & 3 # 1 按位与 (101 & 011 = 001)
5 | 3 # 7 按位或 (101 | 011 = 111)
5 ^ 3 # 6 按位异或
~5 # -6 按位取反
5 << 1 # 10 左移(×2)
5 >> 1 # 2 右移(÷2)
运算符优先级
# 从高到低(常用部分):
# ** 幂
# +x, -x, ~x 一元
# *, /, //, %
# +, - 二元
# <<, >> 位移
# & | ^ 位运算
# ==, !=, >, < ... 比较
# not and or 逻辑(从高到低: not > and > or)
# 建议: 复杂表达式加括号,清晰优先
result = (a + b) * c - (d if cond else e)
运算符是计算的"词汇"。重点掌握算术、比较、逻辑与赋值,理解真值判断与短路求值,日常开发足够。
Python 条件语句
Python 条件语句
条件语句让程序根据条件执行不同分支。Python 用 if/elif/else 表达分支逻辑。
if 基本结构
age = 18
if age >= 18:
print("成年")
# 输出: 成年
if / else
score = 55
if score >= 60:
print("及格")
else:
print("不及格")
# 输出: 不及格
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(grade) # B
# elif 可写多个,自上而下匹配第一个真值
嵌套条件
user = "admin"
logged_in = True
if logged_in:
if user == "admin":
print("管理员页面")
else:
print("普通用户页面")
else:
print("请先登录")
# 建议: 嵌套过深时用逻辑合并
if logged_in and user == "admin":
print("管理员页面")
三元表达式
# 简洁的单行条件
x = 10
result = "大" if x > 5 else "小"
print(result) # 大
# 等价写法
if x > 5:
result = "大"
else:
result = "小"
真值判断
# Python 的真值规则:
# 假: False, None, 0, "", [], {}, set()
# 真: 其余一切
# 推荐写法(简洁)
name = ""
if not name: # 等价 if name == ""
name = "匿名"
items = [1, 2]
if items: # 等价 if len(items) > 0
print(f"{len(items)} 项")
match-case(Python 3.10+)
# 模式匹配(类似 switch)
def describe(value):
match value:
case 0:
return "零"
case 1 | 2:
return "小数字"
case [x, y]:
return f"列表: {x},{y}"
case {"name": n}:
return f"名字: {n}"
case _:
return "其他"
print(describe(1)) # 小数字
print(describe([1, 2])) # 列表: 1,2
条件语句最佳实践
# 1. 先处理简单/异常情况(早返回)
def process(data):
if not data:
return "空数据" # 早返回
# 主逻辑...
# 2. 避免深层嵌套,用逻辑合并或提前返回
# 3. 条件表达式保持可读,复杂逻辑提取为函数
# 4. 用真值判断代替显式比较
# 示例: 守卫子句风格
def login(user, pwd):
if not user:
return "用户名为空"
if not pwd:
return "密码为空"
# 验证逻辑...
return "成功"
条件语句是程序逻辑的核心。掌握 if/elif/else、三元表达式与真值判断,配合"早返回"风格,分支逻辑清晰易读。
Python 循环语句
Python 循环语句
循环用于重复执行代码。Python 提供 for 与 while 两种循环,配合 range、break、continue 使用。
for 循环
# 遍历序列
for fruit in ["苹果", "香蕉", "橘子"]:
print(fruit)
# 遍历字符串
for ch in "Python":
print(ch)
# 遍历字典
d = {"a": 1, "b": 2}
for key in d: # 键
print(key)
for key, value in d.items(): # 键值
print(key, value)
range 与 for
# range(开始, 结束, 步长), 不含结束
for i in range(5): # 0,1,2,3,4
print(i)
for i in range(2, 6): # 2,3,4,5
print(i)
for i in range(0, 10, 2): # 0,2,4,6,8
print(i)
for i in range(5, 0, -1): # 5,4,3,2,1
print(i)
# 带索引遍历
names = ["a", "b"]
for idx, name in enumerate(names, start=1):
print(idx, name)
while 循环
# 条件为真时循环
count = 0
while count < 5:
print(count)
count += 1
# 无限循环 + 退出条件
while True:
cmd = input("命令(q 退出): ")
if cmd == "q":
break
print(f"执行: {cmd}")
break / continue / else
# break: 立即退出循环
for i in range(10):
if i == 5:
break
print(i) # 0-4
# continue: 跳过本次循环
for i in range(5):
if i == 2:
continue
print(i) # 0,1,3,4
# for-else: 循环正常结束(未被 break)时执行
for i in range(5):
if i == 3:
break
else:
print("循环完整执行(无 break)") # 不会执行
# else 常用于"查找失败"场景
for item in items:
if item == target:
print("找到了")
break
else:
print("未找到")
循环嵌套
# 九九乘法表
for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}x{i}={i*j}", end="\t")
print() # 换行
# 嵌套注意: 内层 break 只退出内层循环
列表推导式(循环的优雅替代)
# 生成列表
squares = [i ** 2 for i in range(5)] # [0,1,4,9,16]
# 带条件
evens = [x for x in range(10) if x % 2 == 0] # [0,2,4,6,8]
# 双重循环
pairs = [(x, y) for x in range(3) for y in range(2)]
# 字典/集合推导
d = {x: x * 2 for x in range(3)} # {0:0, 1:2, 2:4}
s = {x for x in "abcabc"} # {'a','b','c'}
循环最佳实践
# 1. 优先 for(可读性)而非 while
# 2. 用 enumerate 代替手动索引
# 3. 推导式简洁,但嵌套过深时用普通循环
# 4. 避免死循环: while 条件保证会变假
# 5. 大数据用迭代器(不全部载入内存)
for line in open("big.txt"): # 逐行读
process(line)
循环是程序"重复劳动"的武器。for + range 覆盖 90% 场景,推导式让生成列表更优雅,break/continue 精确控制流程。
Python While 循环语句
Python While 循环语句
while 循环在条件为真时重复执行代码块,适合"不确定次数"的循环场景。
基本语法
count = 0
while count < 5:
print(f"第 {count} 次")
count += 1
# 输出 0-4
典型场景
# 1. 用户输入循环(直到合法)
while True:
age = input("年龄: ")
if age.isdigit():
break
print("请输入数字!")
# 2. 重试机制
attempts = 0
while attempts < 3:
attempts += 1
if login():
print("登录成功")
break
print(f"失败, 剩余 {3 - attempts} 次")
# 3. 消费队列/生成器
while queue:
item = queue.pop()
process(item)
# 4. 条件满足前等待
while not server_ready():
time.sleep(1)
while / else
# 条件变假(未 break)时执行 else
n = 5
while n > 0:
n -= 1
if n == 3:
break
else:
print("循环正常结束") # 被 break 了,不执行
# 典型: 超时检测
timeout = 10
while timeout > 0:
if check():
print("成功")
break
timeout -= 1
else:
print("超时失败")
死循环与退出
# 死循环(配合 break 使用)
while True:
cmd = input("> ")
if cmd == "exit":
break
if cmd == "skip":
continue
print(f"执行 {cmd}")
# 注意:
# - Ctrl+C 中断死循环
# - 确保循环内条件最终变化,避免真死循环
# - 用 break 显式退出比标志位更清晰
# 标志位方式(较少用)
running = True
while running:
...
if done:
running = False
与 for 的选择
# for: 遍历已知集合(次数确定)
for x in items: ...
# while: 条件驱动(次数不确定)
while condition: ...
# 经验法则:
# 能 for 就 for(更清晰)
# 需要条件循环/无限循环用 while
# 例: 猜数字游戏
import random
secret = random.randint(1, 100)
guess = None
while guess != secret:
guess = int(input("猜 1-100: "))
if guess > secret:
print("大了")
elif guess < secret:
print("小了")
print(f"猜对了!答案是 {secret}")
嵌套 while
# 打印 3x3 矩阵位置
i = 0
while i < 3:
j = 0
while j < 3:
print(f"({i},{j})", end=" ")
j += 1
print()
i += 1
# 内层 break 只退出内层
# 需要同时退出时用标志位或函数 return
常见错误
# 1. 忘记更新条件变量 → 死循环
i = 0
while i < 5:
print(i)
# 缺少 i += 1 → 死循环!
# 2. 条件写反
# 3. 浮点比较的精度问题
x = 0.0
while x != 1.0: # 危险!浮点不精确
x += 0.1
# 应改为: while x < 1.0 - 1e-9
while 循环适合"条件驱动"的场景:用户交互、重试、轮询。配合 break/continue/else,控制流完整而清晰。
Python for 循环语句
Python for 循环语句
for 循环是 Python 最常用的循环:遍历任何可迭代对象(列表、元组、字符串、字典、集合、range、生成器)。
遍历各类对象
# 列表
for x in [1, 2, 3]: print(x)
# 元组
for x in (1, 2, 3): print(x)
# 字符串
for ch in "abc": print(ch)
# 字典
for k in d: print(k) # 键
for v in d.values(): print(v) # 值
for k, v in d.items(): print(k, v) # 键值
# 集合
for x in {1, 2, 3}: print(x) # 无序
# 文件(逐行)
for line in open("file.txt"):
print(line, end="")
range 迭代
# 指定次数
for _ in range(5): # _ 表示不需要变量
do_something()
# 带索引
for i in range(len(items)):
print(i, items[i])
# 推荐: enumerate
for i, item in enumerate(items):
print(i, item)
# 反向/步长
for i in range(10, 0, -2): # 10,8,6,4,2
print(i)
并行遍历 zip
names = ["张三", "李四", "王五"]
scores = [90, 85, 95]
# 同时遍历多个序列
for name, score in zip(names, scores):
print(f"{name}: {score}")
# zip 以最短序列为准
# 需要以最长为准: itertools.zip_longest
from itertools import zip_longest
for a, b in zip_longest([1,2,3], [4,5], fillvalue=0):
print(a, b) # (1,4)(2,5)(3,0)
循环控制
for i in range(10):
if i == 3:
continue # 跳过
if i == 8:
break # 退出
print(i) # 0,1,2,4,5,6,7
# for-else: 未 break 时执行
for i in range(5):
if i == 10: # 永不触发
break
else:
print("完整遍历") # 执行
解包遍历
# 列表元素是元组时解包
points = [(1, 2), (3, 4), (5, 6)]
for x, y in points:
print(f"x={x}, y={y}")
# 嵌套解包
data = [(1, "a", True), (2, "b", False)]
for num, char, flag in data:
print(num, char, flag)
# 解包部分(用 _ 忽略)
for _, name, _ in data:
print(name)
迭代器与生成器
# for 本质: 调用 iter() 得到迭代器,反复 next()
# 直到 StopIteration
# 自定义迭代器
class CountDown:
def __init__(self, n):
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.n <= 0:
raise StopIteration
self.n -= 1
return self.n + 1
for x in CountDown(3):
print(x) # 3, 2, 1
# 生成器(推荐)
def countdown(n):
while n > 0:
yield n
n -= 1
for x in countdown(3):
print(x) # 3, 2, 1
性能注意
# 1. 避免在循环内重复计算
# ❌
for x in items:
y = len(items) + x # len 每次算
# ✅
n = len(items)
for x in items:
y = n + x
# 2. 用推导式代替 append 循环(更快)
# 3. 大文件/大数据用生成器(省内存)
# 4. 循环内尽量少做 IO
# 5. 用内置函数替代手写循环
sum(items) # 替代循环求和
max(items) / min(items)
any(x > 5 for x in items) # 是否存在
all(x > 0 for x in items) # 是否全部
for 循环是 Python 的"瑞士军刀":遍历一切可迭代对象,配合 enumerate/zip/推导式,代码既简洁又高效。
Python 循环嵌套
Python 循环嵌套
循环嵌套是一个循环体内包含另一个循环,用于处理多维结构:矩阵、表格、组合、金字塔等。
基本嵌套
# 外层循环每执行一次,内层完整执行一轮
for i in range(3): # 外层
for j in range(2): # 内层
print(f"i={i}, j={j}")
print("---")
# 输出顺序:
# i=0: j=0, j=1
# i=1: j=0, j=1
# i=2: j=0, j=1
矩形与三角形
# 打印 3x5 矩形
for i in range(3):
for j in range(5):
print("*", end="")
print()
# *****
# *****
# *****
# 直角三角形
for i in range(1, 6):
for j in range(i):
print("*", end="")
print()
# *
# **
# ***
# 九九乘法表
for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}x{i}={i*j}", end="\t")
print()
遍历二维列表
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
# 遍历所有元素
for row in matrix:
for value in row:
print(value, end=" ")
print()
# 1 2 3
# 4 5 6
# 7 8 9
# 带索引
for i, row in enumerate(matrix):
for j, value in enumerate(row):
if value == 5:
print(f"5 在 ({i}, {j})")
组合生成
# 生成坐标对
points = []
for x in range(3):
for y in range(3):
points.append((x, y))
# [(0,0),(0,1),(0,2),(1,0),...]
# 等价推导式
points = [(x, y) for x in range(3) for y in range(3)]
# 筛选组合(去重/条件)
pairs = [(a, b) for a in range(1, 5)
for b in range(1, 5) if a < b]
# [(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)]
break 在嵌套中的作用
# 内层 break 只退出内层循环!
for i in range(3):
for j in range(5):
if j == 2:
break # 只退出内层
print(j, end="")
print() # 每次输出 "01"
提前退出所有层
# 方式1: 标志位
found = False
for i in range(10):
for j in range(10):
if i * j == 42:
print(f"找到: {i} x {j}")
found = True
break
if found:
break
# 方式2: 提取为函数(推荐)
def find_pair():
for i in range(10):
for j in range(10):
if i * j == 42:
return i, j
return None
result = find_pair()
# 方式3: 生成器 + next
def pairs():
for i in range(10):
for j in range(10):
if i * j == 42:
yield i, j
first = next(pairs(), None) # 取第一个
while 嵌套
# while 嵌套同样适用
i = 1
while i <= 3:
j = 1
while j <= 3:
print(i * j, end=" ")
j += 1
print()
i += 1
# 1 2 3
# 2 4 6
# 3 6 9
嵌套性能注意
# 嵌套循环复杂度 O(n*m)
# 大输入时注意性能:
# 1. 能提前 break 就提前
# 2. 用集合/字典加速查找
# 3. 考虑是否真的需要两层遍历
# 查找加速示例
# ❌ O(n*m): 两两比较
for a in list_a:
for b in list_b:
if a == b: ...
# ✅ O(n+m): 用集合
set_b = set(list_b)
for a in list_a:
if a in set_b: ...
实用案例
# 打印杨辉三角
rows = 5
triangle = [[1]]
for i in range(1, rows):
row = [1]
for j in range(1, i):
row.append(triangle[i-1][j-1]
+ triangle[i-1][j])
row.append(1)
triangle.append(row)
for row in triangle:
print(row)
# [1]
# [1, 1]
# [1, 2, 1]
# [1, 3, 3, 1]
# [1, 4, 6, 4, 1]
循环嵌套用于处理多维结构。核心:理解"外层一次、内层一轮"的执行顺序;需要提前退出全部时,优先用函数 return。
Python break 语句
Python break 语句
break 用于立即终止当前循环,跳出循环体,继续执行循环后的代码。
基本用法
for i in range(10):
if i == 5:
break
print(i)
# 输出 0,1,2,3,4(到 5 停止)
# while 中同样适用
n = 0
while True:
n += 1
if n > 3:
break
print(n) # 1,2,3
查找场景
# 找到目标立即停止
items = [3, 7, 1, 9, 4]
target = 9
for item in items:
if item == target:
print(f"找到了 {target}")
break
else:
print("未找到") # break 时不执行
# 线性查找函数
def find_index(items, target):
for i, item in enumerate(items):
if item == target:
return i
return -1
idx = find_index(items, 9) # 3
break 与 else 配合
# for-else: 循环"自然结束"(未 break)时执行 else
# 经典: 素数检测
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
break
else:
return True # 无因子,是素数
return False
print(is_prime(17)) # True
print(is_prime(18)) # False
嵌套循环中的 break
# break 只终止"最内层"当前循环
for i in range(3):
for j in range(3):
if j == 1:
break # 只退出内层
print(i, j) # 只输出 j=0 时
print(f"--- 外层 {i} 继续 ---")
# 需要退出所有层:
# 1. 函数 return(推荐)
# 2. 标志位
# 3. 异常(不推荐)
用户输入退出
# 输入循环直到用户退出
while True:
cmd = input("命令(q 退出): ")
if cmd == "q":
print("再见")
break
print(f"执行: {cmd}")
# 菜单示例
while True:
print("\n1. 查询 2. 添加 3. 删除 0. 退出")
choice = input("选择: ")
if choice == "0":
break
elif choice == "1":
print("查询功能")
# ...
break 的常见误区
# 1. break 不能用于 if(只能用于循环)
# 错误: if x > 5: break(在循环外报错)
# 2. break 不退出函数(用 return)
def f():
for i in range(5):
if i == 2:
break # 只退出循环
print("循环已退出") # 会执行
# 3. 死循环中 break 是唯一的出口之一
# 确保 break 条件最终可达
break vs continue vs return
# break: 退出整个循环
# continue: 跳过本次迭代,继续下一次
# return: 退出整个函数(含循环)
for i in range(5):
if i == 1:
continue # 跳过
if i == 3:
break # 退出
print(i) # 0, 2
break 是循环的"紧急出口"。配合 else 判断"是否被中断",配合 return 提前返回,是高效查找与输入校验的关键。
Python continue 语句
Python continue 语句
continue 跳过当前循环迭代的剩余代码,直接进入下一次迭代。
基本用法
for i in range(5):
if i == 2:
continue # 跳过 i=2
print(i)
# 输出 0,1,3,4
# while 中同样适用
n = 0
while n < 5:
n += 1
if n == 3:
continue
print(n) # 1,2,4,5
过滤场景
# 只处理满足条件的
for item in data:
if item is None:
continue # 跳过空值
if len(item) < 3:
continue # 跳过短值
process(item)
# 奇偶分离
evens, odds = [], []
for x in range(10):
if x % 2 == 0:
evens.append(x)
continue # 进入下一次
odds.append(x)
# 或更 Pythonic 的写法(不一定要 continue)
evens = [x for x in range(10) if x % 2 == 0]
嵌套循环中的 continue
# continue 只作用于所在的最内层循环
for i in range(3):
for j in range(3):
if j == 1:
continue # 只跳过内层 j=1
print(i, j) # 输出 j=0 和 j=2
print("外层继续")
while 中使用注意
# 注意: continue 会跳过循环体剩余部分
# 包括更新条件的语句!容易死循环
# 错误示例(死循环!)
n = 0
while n < 5:
if n == 2:
continue # n 不再增加!
print(n)
n += 1
# 正确: 更新语句放在 continue 之前
n = 0
while n < 5:
n += 1 # 先更新
if n == 2:
continue
print(n) # 1,3,4,5
与推导式/过滤的对比
# continue 循环
result = []
for x in items:
if x < 0:
continue
result.append(x * 2)
# 等价推导式(更简洁)
result = [x * 2 for x in items if x >= 0]
# 等价 filter
result = list(map(lambda x: x * 2,
filter(lambda x: x >= 0, items)))
# 选择: 简单过滤用推导式;复杂逻辑用 continue
# 需要副作用(打印/IO)时用循环
实用案例
# 处理用户输入: 跳过无效值
valid = []
while True:
value = input("输入数字(回车结束): ")
if not value:
break
if not value.replace("-", "").isdigit():
print("无效, 跳过")
continue # 跳过非法输入
valid.append(int(value))
print(f"有效数字: {valid}")
# 跳过文件中的空行和注释
for line in open("config.txt"):
line = line.strip()
if not line or line.startswith("#"):
continue # 跳过空行与注释
process(line)
continue vs 条件嵌套
# 两种写法等价,选择更清晰的
# 写法1: continue(扁平化)
for x in items:
if not valid(x):
continue
if not check(x):
continue
do(x)
# 写法2: 条件嵌套(缩进深)
for x in items:
if valid(x):
if check(x):
do(x)
# continue 风格在复杂校验时更易读(扁平)
continue 用于"跳过不需要的迭代"。与 break(退出循环)配合,循环逻辑清晰可控。while 中记得先更新条件变量。
Python pass 语句
Python pass 语句
pass 是空操作语句:什么都不做,用于语法上需要语句但逻辑上不需要的场景。
基本用法
# 占位: 代码块不能为空
if x > 5:
pass # 暂时不写逻辑
else:
print("小")
# 函数占位
def not_implemented():
pass # 先占位,后续实现
# 类占位
class MyModel:
pass # 结构先搭好
# 异常捕获后忽略
try:
risky()
except ValueError:
pass # 暂时忽略该错误
为什么需要 pass
# Python 语法要求代码块不能为空!
# ❌ 语法错误
if x:
# 空
# ✅ 用 pass 占位
if x:
pass
# 其他语言用空花括号 {}
# Python 用 pass
占位设计(常用场景)
# 1. 接口/骨架设计
class BaseHandler:
def handle(self, data):
raise NotImplementedError # 或 pass
# 2. TODO 占位
def process_order(order):
# TODO: 实现订单处理
pass
# 3. 分支骨架
def classify(x):
if x < 0:
pass # TODO: 负数处理
elif x == 0:
return "零"
else:
pass # TODO: 正数处理
pass vs return None
# pass: 不返回值(隐式 None),继续执行后面代码
def f1():
pass
print("后面还会执行")
# return: 立即返回
def f2():
return
print("不会执行") # 不可达
# 函数无 return 时返回 None
result = f1()
print(result) # None
pass 与 ...(Ellipsis)
# Python 中 ... 也可作为占位(简洁)
def placeholder():
...
# 等价于 pass,更紧凑
# 部分代码风格用 ... 表示"待实现"
# 但 pass 更常见、语义更明确
异常处理中的 pass
# 忽略异常(谨慎使用!)
try:
result = int(input("数字: "))
except ValueError:
pass # 忽略错误输入
# 更好的做法: 给出默认值
try:
result = int(input("数字: "))
except ValueError:
result = 0
# 或至少记录
try:
risky()
except Exception as e:
pass
# 或者 logging.warning(f"忽略: {e}")
最佳实践
# 1. 临时占位: 明确 TODO 标注
# 2. 忽略异常: 确保真的应该忽略(否则隐藏问题)
# 3. 空类/空函数骨架: 用 pass 保持结构
# 4. 长期"空实现"考虑 raise NotImplementedError
# 让调用方明确知道未实现
# 代码审查提示:
# 大量 pass 且无 TODO → 功能未完成,需确认
pass 是 Python 的"占位符":满足语法、标注待办。用对了是脚手架,用多了是欠债——记得补上实现。
Python Number(数字)
Python Number(数字)
数字是编程的基础。Python 支持整数、浮点数、复数,并提供丰富的数学函数。
数字类型
# int 整数(任意精度)
x = 42
y = -7
big = 10 ** 30 # 大整数无溢出
# float 浮点数
pi = 3.14159
e = 2.718
sci = 1.5e10 # 科学计数法
# complex 复数
c = 3 + 4j
c.real # 3.0 实部
c.imag # 4.0 虚部
# bool 是 int 的子类
True == 1 # True
False == 0 # True
类型转换
int("42") # 字符串 → 整数
int(3.99) # 浮点 → 整数(截断,不是四舍五入!)
int("0x1A", 16) # 十六进制 → 十进制 26
float("3.14") # → 浮点
complex(1, 2) # → 复数
# 进制
bin(10) # '0b1010'
oct(10) # '0o12'
hex(255) # '0xff'
int("ff", 16) # 255
常用运算
a, b = 10, 3
a + b / a - b / a * b
a // b # 整除 3
a % b # 取余 1
a ** b # 幂 1000
# 内置数学函数
abs(-5) # 5
round(3.14159, 2) # 3.14(四舍五入)
round(2.5) # 2(银行家舍入,注意!)
divmod(10, 3) # (3, 1) 商和余
pow(2, 10) # 1024
max(1, 5, 3) / min(1, 5, 3)
sum([1, 2, 3])
math 模块
import math
math.pi # π
math.e # e
math.sqrt(16) # 4.0 平方根
math.pow(2, 10) # 1024.0
math.floor(3.7) # 3 向下取整
math.ceil(3.2) # 4 向上取整
math.trunc(3.7) # 3 截断
math.fabs(-5) # 5.0
math.factorial(5) # 120
math.gcd(12, 18) # 6
math.log(100, 10) # 2.0
math.log2(8) # 3.0
math.exp(1) # e
math.sin/cos/tan(x)
math.degrees(math.pi) # 180.0
math.radians(180) # π
math.inf # 无穷
math.nan # 非数字
math.isnan(math.nan) # True
math.isfinite(1.0) # True
random 模块
import random
random.random() # [0,1) 浮点
random.randint(1, 10) # [1,10] 整数
random.uniform(1, 5) # [1,5) 浮点
random.choice(["a","b","c"]) # 随机选一个
random.choices(items, k=3) # 选 k 个(可重复)
random.sample(items, 2) # 不重复选 2 个
random.shuffle(items) # 打乱(原地)
random.seed(42) # 固定随机(可复现)
# 示例: 猜数字
secret = random.randint(1, 100)
浮点精度问题
# 二进制浮点不精确!
0.1 + 0.2 # 0.30000000000000004
# 解决:
# 1. 比较用容差
abs(0.1 + 0.2 - 0.3) < 1e-9 # True
# 2. 金额用 Decimal
from decimal import Decimal
Decimal("0.1") + Decimal("0.2") # Decimal('0.3')
# 3. 分数用 Fraction
from fractions import Fraction
Fraction(1, 3) + Fraction(1, 6) # 1/2
数字格式化
# f-string 格式化
price = 1234.5678
f"{price:.2f}" # '1234.57' 两位小数
f"{price:,.2f}" # '1,234.57' 千分位
f"{price:.0f}" # '1235'
f"{price:010.2f}" # '0001234.57' 补零
f"{price:.2e}" # '1.23e+03' 科学计数
# 百分比
rate = 0.856
f"{rate:.1%}" # '85.6%'
# 进制
f"{255:x}" # 'ff'
f"{255:b}" # '11111111'
性能与选择
# 大数计算: int 任意精度(不溢出)
# 金融计算: Decimal(精确)
# 科学计算: float + numpy
# 精确分数: Fraction
# 整数除法与取余:
# // 和 % 满足: a = (a//b)*b + a%b
# 注意负数: -7 // 3 = -3, -7 % 3 = 2
# (与 C 语言等行为不同,注意跨语言迁移)
数字处理是编程基础。掌握类型转换、math/random 模块与格式化,注意浮点精度陷阱,数值操作不再踩坑。
Python 字符串
Python 字符串
字符串是 Python 最常用的数据类型。本节系统介绍字符串的创建、操作、格式化与常用方法。
创建字符串
s1 = "双引号"
s2 = '单引号'
s3 = """三引号
支持多行
字符串"""
s4 = '''也可以用单三引号'''
# 转义
s = "换行\n 制表\t 引号\" 反斜杠\\"
# 原始字符串(不转义)
path = r"C:\Users\name"
regex = r"\d+"
# 字符串不可变(修改产生新字符串)
索引与切片
s = "Hello Python"
s[0] # 'H'
s[-1] # 'n' 负索引从末尾
s[0:5] # 'Hello'
s[6:] # 'Python'
s[:5] # 'Hello'
s[::2] # 'HloPto' 步长
s[::-1] # 反转 'nohtyP olleH'
# 常用
len(s) # 12
s[0] + s[-1] # 'Hn'
字符串方法
s = " Hello World "
# 大小写
s.lower() # ' hello world '
s.upper() # ' HELLO WORLD '
s.title() # ' Hello World '
s.capitalize() # ' hello world '
s.swapcase()
# 去除空白
s.strip() # 'Hello World'
s.lstrip() / s.rstrip()
# 查找
s.find("World") # 7(找不到 -1)
s.index("World") # 7(找不到报错)
s.count("l") # 3
s.startswith(" ") # True
s.endswith("d ") # True
# 判断
s.isalpha() / s.isdigit() / s.isalnum()
s.isspace() / s.isupper() / s.islower()
# 替换与分割
s.replace("World", "Python")
"a,b,c".split(",") # ['a','b','c']
"a,b,c".split(",", 1) # ['a','b,c'] 限制次数
"-".join(["a", "b", "c"]) # 'a-b-c'
" a b ".split() # ['a','b'] 自动处理空白
成员与比较
"World" in s # True
"X" not in s # True
# 比较: 字典序(按字符编码)
"abc" < "abd" # True
"a" < "b" # True
"10" < "9" # True(字符串比较!注意)
# 数值比较要先转 int
字符串格式化
name, age = "Python", 30
# 1. f-string(推荐)
f"我是 {name}, {age} 岁"
f"{name!r}" # repr 形式
f"{3.14159:.2f}" # 3.14
f"{100:>5}" # ' 100' 右对齐
f"{100:<5}" # '100 ' 左对齐
f"{100:^5}" # ' 100 ' 居中
# 2. format 方法
"我是 {}, {} 岁".format(name, age)
"{1} 和 {0}".format("A", "B")
"{name} {age}".format(name=name, age=age)
# 3. 旧式 %(了解)
"我是 %s, %d 岁" % (name, age)
编码与字节
s = "中文"
s.encode("utf-8") # b'\xe4...' 字节
s.encode("gbk") # GBK 编码
b"bytes".decode("utf-8") # 字节 → 字符串
# 字符与编码
ord("A") # 65
chr(65) # 'A'
ord("中") # 20013
# 长度注意
len("中文") # 2(字符数)
len("中文".encode()) # 6(UTF-8 字节数)
多行与拼接
# 拼接
"a" + "b" # 'ab'
"ab" * 3 # 'ababab'
a = "Hello"
b = "World"
full = a + ", " + b + "!"
f"{a}, {b}!" # 更推荐
# 多行字符串
text = (
"第一行 "
"第二行 "
"第三行"
) # 括号内相邻字符串自动拼接
# join 拼接列表(高效)
", ".join(items) # 而非循环 +=
字符串实用案例
# 反转
s[::-1]
# 单词计数
words = text.lower().split()
from collections import Counter
Counter(words).most_common(5)
# 验证密码强度
def password_ok(pwd):
return (len(pwd) >= 8
and any(c.isdigit() for c in pwd)
and any(c.isalpha() for c in pwd))
# 清理文本
import re
clean = re.sub(r"[^\w\s]", "", text) # 去标点
字符串操作是日常高频场景。掌握方法全家桶与 f-string 格式化,配合切片与编码处理,文本处理得心应手。
Python 列表(List)
Python 列表(List)
列表是 Python 最常用的容器:有序、可变、可存放任意类型。本节系统介绍列表操作。
创建列表
lst = [1, 2, 3]
mixed = [1, "a", 3.14, True] # 任意混合
empty = []
nested = [[1, 2], [3, 4]] # 嵌套
list("abc") # ['a','b','c']
list(range(5)) # [0,1,2,3,4]
[0] * 5 # [0,0,0,0,0]
# 推导式
[x * 2 for x in range(5)] # [0,2,4,6,8]
[x for x in range(10) if x % 2 == 0] # 偶数
索引与切片
lst = [10, 20, 30, 40, 50]
lst[0] # 10
lst[-1] # 50
lst[1:3] # [20, 30]
lst[:2] # [10, 20]
lst[::2] # [10, 30, 50]
lst[::-1] # 反转
# 切片修改
lst[1:3] = [99] # [10, 99, 40, 50]
lst[1:3] = [] # 删除切片
增删改
lst = [1, 2]
# 增
lst.append(3) # 末尾 [1,2,3]
lst.insert(0, 0) # 指定位置 [0,1,2,3]
lst.extend([4, 5]) # 批量 [0,1,2,3,4,5]
lst += [6] # 同 extend
# 删
lst.pop() # 末尾弹 [0..5]
lst.pop(0) # 指定索引弹
lst.remove(3) # 删除第一个值3
del lst[0] # 删除索引
lst.clear() # 清空
# 改
lst[0] = "新值" # 索引赋值
查找与统计
lst = [3, 1, 4, 1, 5, 9, 2]
lst.index(4) # 2 首次出现位置
lst.count(1) # 2 出现次数
3 in lst # True
len(lst) # 7
max(lst) / min(lst) / sum(lst)
# 排序
sorted(lst) # 新列表排序(不改变原)
lst.sort() # 原地排序
lst.sort(reverse=True) # 降序
lst.sort(key=len) # 按长度(自定义键)
sorted(lst, key=lambda x: x[1]) # 按第二元素
# 反转
lst.reverse() / lst[::-1]
遍历
for x in lst: print(x)
for i, x in enumerate(lst): print(i, x)
for a, b in zip(list1, list2): ...
for x in reversed(lst): ...
for x in sorted(lst): ...
# 遍历副本(边遍历边改)
for x in lst[:]: # 副本
if x < 0:
lst.remove(x) # 安全删除
复制与深浅拷贝
# 直接赋值是引用!
a = [1, 2, 3]
b = a # 同一列表!
b.append(4)
print(a) # [1,2,3,4] 受影响
# 浅拷贝
c = a.copy() # 或 a[:] / list(a)
c.append(5)
print(a) # 不受影响
# 但嵌套列表共享:
d = [[1], [2]]
e = d.copy()
e[0].append(9)
print(d) # [[1,9],[2]] 受影响!
# 深拷贝
import copy
f = copy.deepcopy(d) # 完全独立
列表推导式进阶
# 基本
[x ** 2 for x in range(5)]
# 带条件
[x for x in range(20) if x % 3 == 0]
# if-else 表达式
[x if x > 0 else 0 for x in nums]
# 嵌套
[(x, y) for x in range(3) for y in range(3)]
# 展平二维
flat = [item for row in matrix for item in row]
# 字符串处理
words = [w.strip() for w in text.split(",")]
# 性能: 推导式比 for+append 快,也更简洁
列表 vs 元组 vs 数组
# list: 可变,通用容器
# tuple: 不可变,更快更安全(常量、函数返回)
# array: 单一类型,省内存(较少用)
# numpy.ndarray: 数值计算(科学计算)
# 选择:
# 会修改 → list
# 不会修改/作字典键 → tuple
# 大量数值计算 → numpy
常用技巧
# 去重(保持顺序)
unique = list(dict.fromkeys(lst))
# 找最大/最小索引
max_idx = lst.index(max(lst))
# 分组
from collections import defaultdict
groups = defaultdict(list)
for item in items:
groups[item["type"]].append(item)
# 滑动窗口
windows = [lst[i:i+3] for i in range(len(lst)-2)]
# 两个列表转字典
d = dict(zip(keys, values))
列表是 Python 的"主力容器"。掌握增删改查、切片、推导式与深浅拷贝,数据处理得心应手。
Python 元组
Python 元组
元组(Tuple)与列表类似,但不可变:创建后不能修改。用于表示"固定结构"的数据。
创建元组
t1 = (1, 2, 3)
t2 = 1, 2, 3 # 省略括号也可
single = (1,) # 单元素必须加逗号!
empty = ()
tuple("abc") # ('a','b','c')
tuple([1, 2]) # 列表 → 元组
# 注意:
(1) # 1(不是元组!)
(1,) # (1,)(是元组)
基本操作
t = (10, 20, 30, 40)
t[0] # 10
t[-1] # 40
t[1:3] # (20, 30)
len(t) # 4
20 in t # True
# 不可变!
# t[0] = 99 → 报错 TypeError
# 拼接(生成新元组)
t + (50,) # (10,20,30,40,50)
t * 2 # 重复
# 方法(少)
t.count(10) # 1
t.index(20) # 1
解包
point = (3, 4)
x, y = point # 解包
print(x, y) # 3 4
# 交换变量(经典)
a, b = b, a
# 多返回值
def min_max(nums):
return min(nums), max(nums)
lo, hi = min_max([3, 1, 4])
# 扩展解包
first, *rest = (1, 2, 3, 4)
# first=1, rest=[2,3,4]
first, *middle, last = (1, 2, 3, 4, 5)
# first=1, middle=[2,3,4], last=5
元组 vs 列表
# 相同: 索引、切片、成员、遍历、拼接
# 不同:
# - 元组不可变(安全,防误改)
# - 元组可作字典键(可哈希)
# - 元组更快、更省内存
# - 列表有更多修改方法
# 选择指南:
# 坐标、常量、固定记录 → 元组
# 动态集合 → 列表
# 转换
list((1, 2)) # [1, 2]
tuple([1, 2]) # (1, 2)
元组作字典键
# 元组可哈希,可作字典键
locations = {
(39.9, 116.4): "北京",
(31.2, 121.5): "上海",
}
print(locations[(39.9, 116.4)]) # 北京
# 列表不可哈希,不能作键!
# {[1,2]: "x"} → 报错
命名元组(namedtuple)
from collections import namedtuple
# 带字段名的元组(可读性好)
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
p.x # 3(按名字访问)
p[0] # 3(按索引也行)
x, y = p # 解包
# 适用: 简单数据结构(替代类)
User = namedtuple("User", "name age email")
u = User("张三", 30, "z@e.com")
print(u.name, u.age)
# 有默认值
Point2 = namedtuple("Point2", "x y z", defaults=[0])
Point2(1, 2) # z 默认为 0
常见场景
# 1. 函数多返回值
def get_user():
return "张三", 30, "北京" # 元组
name, age, city = get_user()
# 2. 记录固定结构数据
# 数据库行、坐标、RGB 颜色
colors = [(255, 0, 0), (0, 255, 0)]
for r, g, b in colors:
print(r, g, b)
# 3. 安全集合(防误改)
DEFAULT_CONFIG = ("prod", 8080, True)
# 保证不会被意外修改
# 4. 字典遍历
for key, value in d.items(): # items 返回元组
陷阱与注意
# 1. 元组内可变元素仍可变!
t = ([1, 2], 3)
t[0].append(9) # 元组本身没变,但元素变了
# t = ([1,2,9], 3)
# 2. 单元素元组记得逗号
# 3. 元组用于"固定结构",列表用于"动态集合"
# 4. 大元组拼接效率低(每次生成新对象)
元组是"不可变的列表":安全、可哈希、适合固定结构。配合解包与 namedtuple,数据表达简洁且语义清晰。
Python 字典(Dictionary)
Python 字典(Dictionary)
字典是键值对的集合:通过键快速查找值。是 Python 最重要的数据结构之一。
创建字典
d1 = {"name": "Python", "age": 30}
d2 = dict(name="Python", age=30) # 关键字方式
d3 = dict([("a", 1), ("b", 2)]) # 键值对列表
d4 = {} # 空
d5 = dict(zip(keys, values)) # 两个列表合并
# 键的要求: 不可变类型(int/str/tuple)
# 值: 任意类型(可嵌套)
访问与修改
d = {"name": "Python", "age": 30}
# 访问
d["name"] # 'Python'
d.get("name") # 'Python'(安全)
d.get("x", "默认") # '默认'(键不存在)
d.get("x") # None
# 区别:
# d["x"] → KeyError(键不存在报错)
# d.get("x") → None(安全)
# 修改/新增
d["version"] = "3.11" # 新增
d["age"] = 31 # 修改
# 删除
del d["age"] # 删除键
d.pop("name") # 删除并返回值
d.pop("x", None) # 不存在返回默认
d.clear() # 清空
# 判断
"name" in d # True(查键)
遍历
d = {"a": 1, "b": 2, "c": 3}
for key in d: # 键
for key in d.keys(): # 键(显式)
for value in d.values(): # 值
for key, value in d.items(): # 键值对(推荐)
# 保持插入顺序(Python 3.7+ 字典有序)
# 遍历时修改(先转列表)
for key in list(d.keys()):
if d[key] < 2:
del d[key]
字典方法
d = {"a": 1, "b": 2}
# 合并
d.update({"c": 3, "a": 10}) # 原地合并
merged = {**d, "d": 4} # 新字典(展开)
# Python 3.9+: d | {"d": 4}
# 默认值
d.setdefault("e", 5) # 键不存在则设置默认
d.setdefault("a", 99) # 存在则不动(a 仍为 1)
# 获取所有键/值
list(d.keys()) / list(d.values()) / list(d.items())
# 复制
d.copy() # 浅拷贝
import copy
copy.deepcopy(d) # 深拷贝
defaultdict(默认值字典)
from collections import defaultdict
# 计数(经典用法)
counts = defaultdict(int)
for word in words:
counts[word] += 1 # 自动初始化为 0
# 分组
groups = defaultdict(list)
for item in items:
groups[item["type"]].append(item)
# 嵌套默认
dd = defaultdict(lambda: defaultdict(int))
dd["a"]["x"] = 1
# 普通 dict 需要先判断
# if key not in d: d[key] = [] → defaultdict 省事
Counter(计数器)
from collections import Counter
text = "hello world hello python"
c = Counter(text.split())
# Counter({'hello': 2, 'world': 1, 'python': 1})
c.most_common(1) # [('hello', 2)] 最高频
c["hello"] # 2
Counter("aabbb") # Counter({'b': 3, 'a': 2})
# 合并
c1 = Counter("abc")
c2 = Counter("bcd")
c1 + c2 # Counter({'b': 2, 'a': 1, 'c': 1, 'd': 1})
OrderedDict 与排序
# 普通 dict 已保持插入顺序(3.7+)
# OrderedDict 提供额外方法(较少用)
# 按键/值排序
d = {"b": 2, "a": 3, "c": 1}
dict(sorted(d.items())) # 按键
dict(sorted(d.items(), key=lambda x: x[1])) # 按值
dict(sorted(d.items(), key=lambda x: x[1],
reverse=True)) # 降序
# top-k
from heapq import nlargest
nlargest(2, d.items(), key=lambda x: x[1]) # 最大2个
字典推导式
# 基本
{x: x ** 2 for x in range(5)} # {0:0,1:1,2:4,3:9,4:16}
# 条件
{x: x for x in range(10) if x % 2 == 0}
# 转换
{word: len(word) for word in words}
# 交换键值
{v: k for k, v in d.items()}
嵌套字典
# 用户 → 订单 → 明细
data = {
"user1": {
"orders": [
{"id": 1, "total": 99.5},
]
}
}
data["user1"]["orders"][0]["total"] # 99.5
# 安全访问嵌套
def safe_get(d, keys, default=None):
for key in keys:
if isinstance(d, dict) and key in d:
d = d[key]
else:
return default
return d
safe_get(data, ["user1", "orders", 0, "total"])
最佳实践
# 1. 访问用 get(避免 KeyError)
# 2. 计数用 defaultdict(int) / Counter
# 3. 分组用 defaultdict(list)
# 4. 嵌套访问封装安全函数
# 5. 遍历修改先转 list
# 6. 合并用 update 或 |
# 场景选择:
# 简单映射 → dict
# 计数 → Counter
# 默认值 → defaultdict
# 有序操作 → 普通 dict(已有序)/OrderedDict
字典是 Python 的"万能映射":快速查找、灵活嵌套。配合 collections 模块,数据统计与分组高效优雅。
Python 日期和时间
Python 日期和时间
Python 通过 datetime 模块处理日期时间:获取当前时间、格式化、计算差值、时区等。
获取当前时间
from datetime import datetime, date, time
now = datetime.now() # 当前日期时间
today = date.today() # 当前日期
# 访问字段
now.year / now.month / now.day
now.hour / now.minute / now.second
now.microsecond
now.weekday() # 0=周一
now.isoweekday() # 1=周一
创建时间
# 指定时间
dt = datetime(2026, 8, 18, 10, 30, 0)
# 日期/时间单独
d = date(2026, 8, 18)
t = time(10, 30, 0)
# 从字符串解析
datetime.strptime("2026-08-18", "%Y-%m-%d")
datetime.fromisoformat("2026-08-18T10:30:00")
# 时间戳
datetime.now().timestamp() # → 时间戳
datetime.fromtimestamp(1750000000) # 时间戳 → 时间
格式化
dt = datetime(2026, 8, 18, 10, 30, 0)
dt.strftime("%Y-%m-%d") # '2026-08-18'
dt.strftime("%Y/%m/%d %H:%M") # '2026/08/18 10:30'
dt.strftime("%H:%M:%S") # '10:30:00'
dt.strftime("%A") # 星期英文
dt.strftime("%Y 年 %m 月 %d 日") # 中文格式
# 常用格式符
# %Y 年(4位) %m 月 %d 日
# %H 时(24) %I 时(12) %M 分 %S 秒
# %p AM/PM %A 星期全名 %a 星期缩写
# %j 年内第几天 %U 年内第几周
# f-string 也支持
f"{dt:%Y-%m-%d %H:%M}"
日期运算
from datetime import timedelta
now = datetime.now()
now + timedelta(days=1) # 明天
now - timedelta(days=7) # 一周前
now + timedelta(hours=2) # 两小时后
now + timedelta(minutes=30)
now + timedelta(weeks=1)
# 差值
d1 = datetime(2026, 8, 1)
d2 = datetime(2026, 8, 18)
diff = d2 - d1 # timedelta(days=17)
diff.days # 17
diff.total_seconds() # 1468800.0
# timedelta 常用字段
td = timedelta(days=1, hours=2, minutes=30)
td.total_seconds() # 95400.0
日期比较
d1 < d2 / d1 == d2 / d1 > d2 # 直接比较
# 判断区间
start = datetime(2026, 8, 1)
end = datetime(2026, 8, 31)
target = datetime(2026, 8, 18)
start <= target <= end # True
time 模块(底层)
import time
# 时间戳
time.time() # 当前时间戳
time.sleep(1) # 暂停 1 秒
# 性能计时
start = time.time()
do_work()
elapsed = time.time() - start
# 更精确: perf_counter(不受系统时间影响)
start = time.perf_counter()
do_work()
elapsed = time.perf_counter() - start
# 结构化时间
time.localtime() # 本地时间元组
time.gmtime() # UTC 时间
时区处理
from datetime import timezone, timedelta
# UTC 时间
utc_now = datetime.now(timezone.utc)
# 指定时区
cst = timezone(timedelta(hours=8)) # 东八区
now_cst = datetime.now(cst)
# 转换
utc_now.astimezone(cst)
# 存储建议: 统一 UTC,展示转本地
# 数据库存 UTC,前端展示时转时区
calendar 模块
import calendar
calendar.month(2026, 8) # 打印月历
calendar.isleap(2024) # True 闰年
calendar.weekday(2026, 8, 18) # 1(周二)
# 某月天数
import calendar
calendar.monthrange(2026, 8) # (5, 31) 首日周几,天数
实用案例
# 1. 计算年龄
def calc_age(birth):
today = date.today()
age = today.year - birth.year
if (today.month, today.day) < (birth.month, birth.day):
age -= 1
return age
# 2. 生成日期序列
dates = [start + timedelta(days=i)
for i in range((end - start).days + 1)]
# 3. 日志时间戳
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"backup_{timestamp}.zip"
# 4. 超时判断
deadline = start + timedelta(seconds=10)
if datetime.now() > deadline:
print("超时")
最佳实践
# 1. 存储用 UTC,展示转本地时区
# 2. 比较统一用 datetime 对象(勿混 str)
# 3. 解析外部日期用 strptime 并指定格式
# 4. 计时用 perf_counter,不用 time.time
# 5. 计算差值用 timedelta,勿手算秒数
# 6. 复杂时区用第三方库 pytz/zoneinfo
# 注意: strptime 解析失败会抛 ValueError
try:
dt = datetime.strptime(s, "%Y-%m-%d")
except ValueError:
print("日期格式错误")
日期时间是程序的"时钟"。掌握 datetime + timedelta + strftime 三件套,配合时区规范,时间处理不再头疼。
Python 函数
Python 函数
函数是组织代码的基本单元:封装逻辑、避免重复、便于测试。本节系统介绍 Python 函数。
定义与调用
def greet(name):
"""问候函数(文档字符串)"""
return f"你好, {name}!"
# 调用
print(greet("Python"))
# 无返回值(返回 None)
def log(msg):
print(f"[LOG] {msg}")
result = log("hi") # None
# 函数是第一类对象
f = greet # 赋值
f("X") # 调用
funcs = [greet, log] # 放容器
参数类型
# 1. 位置参数
def f(a, b, c): ...
# 2. 默认参数(必须放最后)
def f(a, b=10, c="x"): ...
f(1) # b=10, c="x"
f(1, 2) # b=2
# 注意: 默认参数用不可变对象!
# def f(lst=[]): → 陷阱!用 None
# 3. 关键字参数
def f(a, b, c): ...
f(b=2, a=1, c=3) # 顺序随意
# 4. 位置 + 关键字混合
# 位置参数在前,关键字在后
f(1, b=2, c=3)
可变参数
# *args: 任意多个位置参数 → 元组
def sum_all(*args):
return sum(args)
sum_all(1, 2, 3) # 6
# **kwargs: 任意多个关键字参数 → 字典
def show(**kwargs):
for k, v in kwargs.items():
print(f"{k}={v}")
show(name="Py", ver=3)
# 组合(完整形式)
def func(a, b=10, *args, c=20, **kwargs):
print(a, b, args, c, kwargs)
# 强制关键字参数(* 后)
def f(a, *, b):
return a + b
f(1, b=2) # OK
# f(1, 2) # 报错!b 必须关键字
解包传参
# 列表/元组解包
def add(a, b, c):
return a + b + c
nums = [1, 2, 3]
add(*nums) # 6
# 字典解包
d = {"a": 1, "b": 2, "c": 3}
add(**d) # 6
# 应用: 动态调用
config = {"host": "localhost", "port": 8080}
connect(**config)
返回值
# 多返回值(元组)
def stats(nums):
return min(nums), max(nums), sum(nums)
lo, hi, total = stats([1, 5, 3])
# 条件返回
def classify(x):
if x > 0: return "正"
if x < 0: return "负"
return "零"
# 提前返回(守卫子句)
def process(data):
if not data:
return None
if not valid(data):
return "invalid"
return result
作用域
x = 10 # 全局
def f():
y = 20 # 局部
print(x) # 可读全局
# x = 30 # 会创建局部!需 global 声明
def g():
global x # 声明使用全局
x = 99
# 规则: LEGB
# Local(局部) → Enclosing(外层函数)
# → Global(全局) → Built-in(内建)
# 闭包
def counter():
count = 0
def inc():
nonlocal count # 修改外层变量
count += 1
return count
return inc
c = counter()
c() # 1
c() # 2
lambda 匿名函数
# 单行表达式函数
square = lambda x: x ** 2
square(5) # 25
# 与排序/映射配合
pairs = [(1, "b"), (2, "a")]
sorted(pairs, key=lambda p: p[1])
items = [1, 2, 3]
list(map(lambda x: x * 2, items)) # [2,4,6]
list(filter(lambda x: x % 2 == 0, items)) # [2]
# 优先用推导式(更清晰)
[x * 2 for x in items]
[x for x in items if x % 2 == 0]
# lambda 只适合简单表达式,复杂逻辑用 def
装饰器
# 函数增强: 在不动原函数的情况下加功能
def timer(func):
import time
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
print(f"{func.__name__} 耗时 "
f"{time.perf_counter()-start:.4f}s")
return result
return wrapper
@timer # 等价 slow_func = timer(slow_func)
def slow_func():
time.sleep(0.1)
slow_func() # 自动计时
# 带参数的装饰器
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def say():
print("hi")
函数式工具
# map / filter / reduce
from functools import reduce
nums = [1, 2, 3, 4, 5]
list(map(str, nums)) # ['1',...]
list(filter(lambda x: x > 2, nums)) # [3,4,5]
reduce(lambda a, b: a + b, nums) # 15
# 优先推导式(更 Pythonic)
[str(n) for n in nums]
[n for n in nums if n > 2]
# functools 其他
from functools import partial, lru_cache
# 偏函数(固定参数)
add = lambda a, b: a + b
add5 = partial(add, 5)
add5(3) # 8
# 缓存(性能优化)
@lru_cache(maxsize=128)
def fib(n):
if n < 2: return n
return fib(n-1) + fib(n-2)
fib(100) # 秒出
最佳实践
# 1. 函数单一职责: 一个函数做一件事
# 2. 用文档字符串描述功能
# 3. 参数命名清晰,少用魔法数字
# 4. 默认参数用 None 而非可变对象
# 5. 尽早 return(守卫子句)
# 6. 变量作用域最小化
# 7. 复杂逻辑拆分成小函数
# 示例: 好的函数
def calculate_total(prices, tax_rate=0.1):
"""计算含税总价。
prices: 价格列表
tax_rate: 税率(默认 0.1)
"""
if not prices:
return 0.0
subtotal = sum(prices)
return subtotal * (1 + tax_rate)
函数是代码复用的基石。掌握参数类型、可变参数、作用域与装饰器,配合"单一职责"与"守卫子句",代码质量显著提升。
Python 模块
Python 模块
模块是 Python 组织代码的方式:一个 .py 文件就是一个模块,包是模块的集合。模块化让代码可复用、可维护。
导入模块
# 方式1: 导入整个模块
import math
math.sqrt(16) # 4.0
# 方式2: 导入部分
from math import sqrt, pi
sqrt(16) # 直接用
# 方式3: 别名
import numpy as np
import pandas as pd
# 方式4: 通配符(不推荐,污染命名空间)
from math import *
创建自己的模块
# mymodule.py
"""我的模块"""
VERSION = "1.0"
def greet(name):
return f"Hello, {name}"
class Calculator:
def add(self, a, b):
return a + b
# 使用
# main.py
import mymodule
print(mymodule.VERSION)
print(mymodule.greet("World"))
calc = mymodule.Calculator()
__name__ 与主模块
# 每个模块都有 __name__
# - 直接运行时: __name__ == "__main__"
# - 被导入时: __name__ == 模块名
# mymodule.py
def main():
print("程序入口")
if __name__ == "__main__":
main() # 直接运行时执行
# 被导入时不执行 main(避免副作用)
包(Package)
# 目录结构
mypackage/
├── __init__.py # 包标记(可为空)
├── module_a.py
└── sub/
└── module_b.py
# 导入
import mypackage.module_a
from mypackage import module_a
from mypackage.sub import module_b
# __init__.py 可定义包级内容
# __all__ = ["module_a"] # 控制 * 导入范围
常用标准库
import os # 操作系统
import sys # 系统参数
import json # JSON
import re # 正则
import math / random # 数学/随机
import datetime # 日期时间
import collections # 容器工具
import itertools # 迭代工具
import functools # 函数工具
import pathlib # 路径操作
import subprocess # 子进程
import threading # 多线程
import logging # 日志
import unittest # 测试
import urllib # 网络请求
# 常用: os/sys
os.getcwd() # 当前目录
os.listdir(".") # 列出文件
os.path.join("a", "b") # 路径拼接
sys.argv # 命令行参数
sys.path # 模块搜索路径
第三方包
# 安装
pip install requests pandas
# 常用第三方:
# Web: requests / flask / django
# 数据: numpy / pandas / matplotlib
# AI: torch / scikit-learn
# 工具: tqdm(进度条) / rich(美化输出)
# 管理依赖
pip freeze > requirements.txt # 导出
pip install -r requirements.txt # 安装
模块搜索路径
# 导入时按 sys.path 顺序查找
import sys
print(sys.path)
# ['', '/usr/lib/python3.11', ...]
# 当前目录优先 → 标准库 → 第三方
# 添加路径
sys.path.append("/my/libs")
# 或环境变量 PYTHONPATH
# 或 site-packages
# 命名冲突注意: 自定义模块勿与标准库同名
reload 与重新导入
# 交互式开发中修改模块后重载
import importlib
import mymodule
importlib.reload(mymodule)
# 或重启解释器(更可靠)
模块最佳实践
# 1. 每个模块职责单一(一个 .py 一个主题)
# 2. 顶层只写常量/函数/类,副作用放 main
# 3. 用 __all__ 明确公共接口
# 4. 相对导入: from . import sibling
# (包内模块用相对导入)
# 5. 命名: 小写下划线 my_module.py
# 6. 避免循环导入
# 组织建议
# 小项目: 单文件即可
# 中项目: 按功能分包
# 大项目: src 布局 + 包管理工具
模块化让 Python 代码"积木化":标准库开箱即用、第三方包丰富生态、自定义模块复用逻辑。合理组织,项目可维护性大增。
Python 文件I/O
Python 文件I/O
文件读写是程序与外部数据交互的基础。Python 提供简洁的文件操作接口,推荐使用 with 语句自动管理资源。
打开文件
# 语法: open(path, mode, encoding)
f = open("data.txt", "r", encoding="utf-8")
# 读取操作...
f.close() # 记得关闭!
# 模式:
# "r" 只读(默认)
# "w" 写入(覆盖,不存在则创建)
# "a" 追加
# "x" 创建(已存在报错)
# "b" 二进制(如 "rb" "wb")
# "+" 读写("r+" "w+")
# 推荐: with 自动关闭
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read()
# 退出 with 自动 close,无需手动
读取文件
# 全部读取
with open("data.txt", encoding="utf-8") as f:
content = f.read() # 字符串
# 逐行读取(大文件推荐)
with open("data.txt", encoding="utf-8") as f:
for line in f: # 迭代器,省内存
print(line.rstrip())
# 读取所有行(列表)
with open("data.txt", encoding="utf-8") as f:
lines = f.readlines() # ['line1\n', ...]
# 一次读一行
with open("data.txt", encoding="utf-8") as f:
line1 = f.readline()
line2 = f.readline()
# 便捷函数
content = open("data.txt", encoding="utf-8").read()
# 但不推荐(不关闭),了解即可
写入文件
# 覆盖写入
with open("out.txt", "w", encoding="utf-8") as f:
f.write("第一行\n")
f.write("第二行\n")
# 追加
with open("out.txt", "a", encoding="utf-8") as f:
f.write("追加行\n")
# 写多行
lines = ["a", "b", "c"]
with open("out.txt", "w", encoding="utf-8") as f:
f.writelines(line + "\n" for line in lines)
# print 到文件
with open("out.txt", "w", encoding="utf-8") as f:
print("hello", file=f)
二进制文件
# 读取二进制(图片等)
with open("img.png", "rb") as f:
data = f.read() # bytes
# 写入二进制
with open("copy.png", "wb") as f:
f.write(data)
# 复制文件
with open("src.png", "rb") as src, \
open("dst.png", "wb") as dst:
dst.write(src.read())
文件路径操作
import os
from pathlib import Path
# os 方式
os.path.exists("data.txt") # 是否存在
os.path.isfile("data.txt") # 是否文件
os.path.isdir("dir") # 是否目录
os.path.getsize("data.txt") # 大小
os.path.join("dir", "sub", "f.txt") # 拼接路径
os.path.basename("/a/b.txt") # 'b.txt'
os.path.dirname("/a/b.txt") # '/a'
os.path.splitext("a.txt") # ('a', '.txt')
# pathlib(现代推荐)
p = Path("dir/sub/data.txt")
p.exists() / p.is_file() / p.is_dir()
p.name # 'data.txt'
p.stem # 'data'
p.suffix # '.txt'
p.parent # 'dir/sub'
p / "other.txt" # 拼接
Path("dir").mkdir(parents=True, exist_ok=True)
Path("data.txt").read_text(encoding="utf-8")
Path("data.txt").write_text("内容", encoding="utf-8")
目录操作
import os
import shutil
# 列出
os.listdir(".") # 当前目录
for name in os.listdir("."):
if name.endswith(".py"):
print(name)
# glob 模式匹配
import glob
glob.glob("*.py") # 当前目录 py
glob.glob("**/*.py", recursive=True) # 递归
# 创建/删除
os.makedirs("a/b/c", exist_ok=True) # 递归创建
os.rmdir("a") # 删除空目录
shutil.rmtree("a") # 递归删除(慎用!)
# 移动/复制/重命名
shutil.copy("a.txt", "b.txt") # 复制文件
shutil.move("a.txt", "dir/a.txt") # 移动
os.rename("a.txt", "c.txt") # 重命名
# 删除文件
os.remove("c.txt")
文件编码
# 读写时指定编码(处理中文)
with open("data.txt", "r", encoding="utf-8") as f:
...
# 常见问题:
# UnicodeDecodeError: 编码不匹配
# 解决: 确认文件真实编码
# 尝试 gbk / utf-8-sig(带 BOM)
# 读取未知编码文件(尝试)
for enc in ["utf-8", "gbk", "utf-8-sig"]:
try:
with open("f.txt", encoding=enc) as f:
text = f.read()
break
except UnicodeDecodeError:
continue
异常处理
# 文件不存在等错误
try:
with open("missing.txt", encoding="utf-8") as f:
content = f.read()
except FileNotFoundError:
print("文件不存在")
except PermissionError:
print("无权限")
except UnicodeDecodeError:
print("编码错误")
# 常见异常:
# FileNotFoundError / PermissionError
# IsADirectoryError / UnicodeDecodeError
实用案例
# 1. 统计文本词频
from collections import Counter
with open("text.txt", encoding="utf-8") as f:
words = f.read().lower().split()
top = Counter(words).most_common(5)
# 2. 逐行处理大文件
with open("big.log", encoding="utf-8") as f:
for line in f:
if "ERROR" in line:
print(line.rstrip())
# 3. 合并多个文件
with open("merged.txt", "w", encoding="utf-8") as out:
for name in ["a.txt", "b.txt"]:
with open(name, encoding="utf-8") as f:
out.write(f.read())
# 4. 读取 CSV(简单方式)
with open("data.csv", encoding="utf-8") as f:
for line in f:
row = line.strip().split(",")
print(row)
最佳实践
# 1. 永远用 with 打开文件(自动关闭)
# 2. 指定 encoding="utf-8"(跨平台一致)
# 3. 大文件逐行处理,勿整体 read
# 4. 路径操作用 pathlib(更现代)
# 5. 处理可能出现的异常
# 6. 写文件前确保目录存在(mkdir)
# 工具: tempfile 临时文件
import tempfile
with tempfile.NamedTemporaryFile(
suffix=".txt", delete=True) as tmp:
tmp.write(b"temp data")
print(tmp.name) # /tmp/xxx.txt
文件 I/O 是程序的数据出入口。掌握 with 语句、读写模式、编码处理与 pathlib,文件操作安全高效。
Python 异常处理
Python 异常处理
异常是程序运行时的错误。异常处理让程序在出错时优雅降级,而非崩溃。本节系统介绍 try/except/else/finally 与异常体系。
基本结构
try:
result = 10 / 0
except ZeroDivisionError:
print("除数不能为零")
# 捕获异常对象
try:
num = int("abc")
except ValueError as e:
print(f"转换失败: {e}")
# 捕获多种异常
try:
risky()
except (ValueError, TypeError) as e:
print(f"类型错误: {e}")
完整结构
try:
# 可能出错的代码
data = process()
except ValueError:
print("值错误")
except Exception as e: # 兜底
print(f"未知错误: {e}")
else:
print(f"无异常,结果: {data}") # 无异常时执行
finally:
print("无论如何都执行") # 清理资源
# else: try 无异常时执行
# finally: 无论是否异常都执行(关闭资源)
常见异常类型
# 异常层级(部分):
# BaseException
# ├── KeyboardInterrupt (Ctrl+C)
# ├── SystemExit
# └── Exception
# ├── ArithmeticError
# │ ├── ZeroDivisionError
# │ └── OverflowError
# ├── LookupError
# │ ├── IndexError 索引越界
# │ └── KeyError 字典键不存在
# ├── ValueError 值错误
# ├── TypeError 类型错误
# ├── FileNotFoundError 文件不存在
# ├── PermissionError 权限错误
# └── ...(大量具体异常)
# 只捕获 Exception 及其子类
# 不捕获 KeyboardInterrupt/SystemExit
抛出异常
# raise 主动抛出
def divide(a, b):
if b == 0:
raise ValueError("除数不能为零")
return a / b
# 指定类型
raise TypeError("类型不匹配")
raise Exception("通用错误")
# 从异常中抛出异常(链式)
try:
divide(1, 0)
except ValueError as e:
raise RuntimeError("计算失败") from e
# 保留原始异常(排查根因)
# assert(断言,开发期检查)
def set_age(age):
assert 0 <= age <= 150, "年龄不合法"
return age
# 断言失败抛 AssertionError
# 生产环境可禁用(python -O)
自定义异常
# 定义业务异常
class AppError(Exception):
"""应用基础异常"""
pass
class ValidationError(AppError):
"""数据校验失败"""
def __init__(self, field, message):
self.field = field
self.message = message
super().__init__(f"{field}: {message}")
class NotFoundError(AppError):
"""资源不存在"""
pass
# 使用
def get_user(user_id):
if user_id < 0:
raise ValidationError("user_id", "不能为负")
if user_id == 0:
raise NotFoundError("用户不存在")
return {"id": user_id}
try:
get_user(0)
except ValidationError as e:
print(f"校验失败: {e.field} - {e.message}")
except NotFoundError:
print("未找到")
except AppError:
print("其他业务错误")
# 好处: 调用方可精确捕获业务错误
异常链与上下文
# __context__: 异常被处理时自动记录
# __cause__: from 指定原因
# traceback: 完整堆栈
import traceback
try:
divide(1, 0)
except Exception:
traceback.print_exc() # 打印完整堆栈
# 记录异常(日志)
import logging
logging.basicConfig(level=logging.ERROR)
try:
risky()
except Exception as e:
logging.exception("操作失败") # 含堆栈
with 与上下文管理
# with 语句处理资源(文件、锁、连接)
with open("f.txt") as f: # 自动关闭
data = f.read()
# 自定义上下文管理器
class ManagedFile:
def __init__(self, name):
self.name = name
def __enter__(self):
print("打开资源")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("释放资源")
return False # False: 异常继续抛出
with ManagedFile("f.txt") as f:
print("使用中")
# 输出: 打开资源 / 使用中 / 释放资源
# 更简单: contextlib
from contextlib import contextmanager
@contextmanager
def managed():
print("进入")
try:
yield
finally:
print("退出")
with managed():
print("使用")
异常处理最佳实践
# 1. 捕获具体异常,避免裸 except:
# ❌ except: / except Exception: 吞掉所有
# ✅ except ValueError: 精确处理
# 2. 不要用异常控制正常流程
# ❌
try:
value = d["key"]
except KeyError:
value = default
# ✅
value = d.get("key", default)
# 3. 该抛出就抛,别吞
# 捕获后什么都不做 = 隐藏 bug
# 4. 资源用 with 管理
# 5. 关键错误记录日志(含堆栈)
# 6. 自定义异常继承自 Exception(或业务基类)
# 分层处理:
# - 底层: 让异常向上传播
# - 边界(API/UI): 捕获并转换
# - 顶层: 兜底处理,避免崩溃
实用模式
# 1. 重试模式
import time
for attempt in range(3):
try:
result = api_call()
break
except ConnectionError:
if attempt == 2:
raise
time.sleep(2 ** attempt) # 退避
# 2. 默认值模式
try:
value = int(text)
except (ValueError, TypeError):
value = 0
# 3. 部分成功模式
errors = []
for item in items:
try:
process(item)
except Exception as e:
errors.append((item, e))
# 汇总 errors 报告
# 4. 抑制已知异常(contextlib)
from contextlib import suppress
with suppress(FileNotFoundError):
os.remove("maybe_missing.txt")
异常处理是程序的"安全气囊":精确捕获、优雅降级、记录日志、释放资源。处理好异常,程序才健壮可用。
Python 面向对象
Python 面向对象
面向对象编程(OOP)用"类与对象"组织代码:封装数据与行为、复用逻辑。Python 支持完整的 OOP 特性。
类与对象
class Dog:
"""狗类"""
species = "犬科" # 类属性(所有实例共享)
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age
def bark(self):
return f"{self.name}: 汪汪!"
def info(self):
return f"{self.name}, {self.age} 岁"
# 创建对象
d1 = Dog("旺财", 3)
d2 = Dog("小白", 2)
d1.bark() # '旺财: 汪汪!'
d1.info() # '旺财, 3 岁'
Dog.species # '犬科'(类属性)
self 与 __init__
# self: 实例自身的引用(必须为第一个参数)
# __init__: 构造方法(创建对象时初始化)
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def distance(self, other):
return ((self.x - other.x) ** 2
+ (self.y - other.y) ** 2) ** 0.5
p1 = Point(0, 0)
p2 = Point(3, 4)
p1.distance(p2) # 5.0
# 方法只是"绑定到实例的函数"
Point.distance(p1, p2) # 等价调用
属性与封装
# 私有约定: 下划线前缀(约定,非强制)
class Account:
def __init__(self, balance=0):
self._balance = balance # 约定私有
self.__secret = "隐藏" # 名字重整(更私有)
def deposit(self, n):
if n > 0:
self._balance += n
return self._balance
def get_balance(self):
return self._balance
# 属性 property(推荐)
class Account:
def __init__(self, balance=0):
self._balance = balance
@property
def balance(self): # 读取
return self._balance
@balance.setter
def balance(self, value): # 赋值(校验)
if value < 0:
raise ValueError("余额不能为负")
self._balance = value
acc = Account(100)
acc.balance # 100(像属性一样读)
acc.balance = 200 # 走 setter(校验)
继承
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "..."
def info(self):
return f"动物: {self.name}"
class Dog(Animal):
def speak(self): # 重写
return "汪汪"
class Cat(Animal):
def speak(self):
return "喵喵"
def info(self):
return f"猫: {super().info()}" # 调用父类
# 多态
animals = [Dog("旺财"), Cat("咪咪")]
for a in animals:
print(a.speak()) # 汪汪 / 喵喵
# 检查类型
isinstance(d, Dog) # True
issubclass(Dog, Animal) # True
多继承与 MRO
class A:
def method(self): return "A"
class B:
def method(self): return "B"
class C(A, B): # 多继承
pass
c = C()
c.method() # 'A'(按 MRO 顺序)
# MRO: 方法解析顺序
C.__mro__ # (C, A, B, object)
# 多继承慎用!复杂层级易混淆
# 优先组合而非继承
# super() 在多继承中的协作
class D(A, B):
def method(self):
return super().method() + " + D"
魔术方法
class Vector:
def __init__(self, x, y):
self.x, self.y = x, y
def __repr__(self): # 开发者表示
return f"Vector({self.x}, {self.y})"
def __str__(self): # 用户表示(str())
return f"({self.x}, {self.y})"
def __add__(self, other): # +
return Vector(self.x + other.x,
self.y + other.y)
def __eq__(self, other): # ==
return (self.x, self.y) == (other.x, other.y)
def __len__(self): # len()
return int(abs(complex(self.x, self.y)))
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v1 + v2 # Vector(4, 6)
v1 == Vector(1, 2) # True
str(v1) # '(1, 2)'
# 常用魔术方法:
# __init__/__repr__/__str__
# __add__/__sub__/__mul__/__eq__/__lt__
# __len__/__getitem__/__setitem__
# __iter__/__next__
# __call__: 实例可调用
# __enter__/__exit__: with 支持
# __getattr__/__setattr__
类方法与静态方法
class Student:
count = 0
def __init__(self, name):
self.name = name
Student.count += 1
@classmethod
def total(cls): # 类方法: 操作类
return f"学生总数: {cls.count}"
@staticmethod
def validate(name): # 静态方法: 工具函数
return len(name) > 0
@classmethod
def create(cls, name): # 工厂方法
if cls.validate(name):
return cls(name)
return None
s1 = Student("张三")
Student.total() # '学生总数: 1'
Student.validate("") # False
dataclass(数据类)
from dataclasses import dataclass, field
# 自动生成 __init__/__repr__/__eq__ 等
@dataclass
class Product:
name: str
price: float
stock: int = 0 # 默认值
tags: list = field(default_factory=list) # 可变默认!
p1 = Product("键盘", 99.5, 10)
p2 = Product("键盘", 99.5, 10)
print(p1) # Product(name='键盘', price=99.5, stock=10)
p1 == p2 # True(自动实现)
# 对比普通类: 少写大量样板代码
# 适合数据载体(配置、DTO、记录)
OOP 最佳实践
# 1. 组合优于继承(has-a 优于 is-a)
# 2. 单一职责: 一个类做一件事
# 3. 封装: 属性用 property 控制访问
# 4. 少用多继承,保持层级浅
# 5. 数据类用 dataclass
# 6. 魔术方法让类融入 Python 语法
# 7. 不要过度设计(简单场景用函数即可)
# 组合示例
class Engine:
def start(self): ...
class Car:
def __init__(self):
self.engine = Engine() # 组合
def start(self):
self.engine.start()
Python OOP 灵活而优雅:类/继承/多态/魔术方法/dataclass 一应俱全。按需使用,保持简单,是最高原则。
Python 正则表达式
Python 正则表达式
正则表达式(Regex)用于文本的匹配、查找、替换与提取。Python 通过 re 模块提供支持。
基本用法
import re
# match: 从开头匹配
re.match(r"\d+", "123abc") # 匹配对象
re.match(r"abc", "123abc") # None(开头不匹配)
# search: 任意位置匹配
re.search(r"\d+", "abc123def") # 匹配 '123'
# findall: 找全部
re.findall(r"\d+", "a1b22c333") # ['1', '22', '333']
# sub: 替换
re.sub(r"\d+", "#", "a1b22c") # 'a#b#c'
# split: 分割
re.split(r"[,\s]+", "a, b c") # ['a','b','c']
# 匹配对象
m = re.search(r"(\d{4})-(\d{2})", "2026-08")
m.group() # '2026-08' 整个匹配
m.group(1) # '2026'
m.group(2) # '08'
m.span() # (0, 7) 位置
m.start() / m.end()
元字符与语法
# 字符类
. # 任意字符(除换行)
\d # 数字 [0-9]
\D # 非数字
\w # 单词字符 [a-zA-Z0-9_]
\W # 非单词
\s # 空白(空格/制表/换行)
\S # 非空白
# 量词
* # 0次或多次
+ # 1次或多次
? # 0次或1次
{n} # 恰好 n 次
{n,} # 至少 n 次
{n,m} # n 到 m 次
# 锚点
^ # 开头
$ # 结尾
\b # 单词边界
# 分组与或
(abc) # 分组
a|b # 或
[abc] # 字符集: a/b/c 之一
[a-z] # 范围
[^0-9] # 非数字
# 转义: 特殊字符需 \ 转义
# \. \* \+ \? \[ \] \( \) \|
常用模式示例
# 邮箱(简化)
re.fullmatch(r"[\w.+-]+@[\w-]+\.[\w.]+",
"user@example.com")
# 手机号(中国,简化)
re.fullmatch(r"1[3-9]\d{9}", "13812345678")
# 身份证(18位)
re.fullmatch(r"\d{17}[\dX]", "110101199001011234")
# URL
re.fullmatch(r"https?://[\w.-]+(?:/[\w./?&=%-]*)?",
"https://example.com/path?a=1")
# IP 地址(简化)
re.fullmatch(r"\d{1,3}(\.\d{1,3}){3}", "192.168.1.1")
# 日期
re.fullmatch(r"\d{4}-\d{2}-\d{2}", "2026-08-18")
# 中文字符
re.findall(r"[\u4e00-\u9fff]+", "Hello 世界!") # ['世界']
贪婪与懒惰
text = "onetwo"
# 贪婪: 尽可能多匹配
re.findall(r"<.+>", text)
# ['onetwo'] 整个
# 懒惰: 尽可能少匹配(加 ?)
re.findall(r"<.+?>", text)
# ['', '', '', '']
# 需要分组精确提取
re.findall(r"(.*?)", text) # ['one']
编译正则(性能)
# 重复使用同一正则时,先编译
phone_re = re.compile(r"1[3-9]\d{9}")
phone_re.findall(text)
phone_re.search(text)
phone_re.fullmatch(value)
# 编译选项
re.compile(r"pattern", re.IGNORECASE) # 忽略大小写
re.compile(r"pattern", re.MULTILINE) # 多行 ^ $
re.compile(r"pattern", re.DOTALL) # . 匹配换行
re.compile(r"pattern", re.VERBOSE) # 允许注释空白
# 示例(VERBOSE 提高可读性)
pattern = re.compile(r"""
(?P\d{4}) # 年
-
(?P\d{2}) # 月
""", re.VERBOSE)
m = pattern.search("2026-08")
m.group("year") # '2026'(命名分组)
替换与回调
# 简单替换
re.sub(r"\d+", "N", "a1b2") # 'aNbN'
# 引用分组
re.sub(r"(\w+)@(\w+)", r"\2@\1", "user@host")
# 'host@user'
# 函数回调(动态替换)
def repl(m):
num = int(m.group())
return str(num * 2)
re.sub(r"\d+", repl, "a1b2c3") # 'a2b4c6'
正则性能与安全
# 1. 避免灾难性回溯
# 危险: (a+)+ 或 (a|a)+ 在特定输入下极慢
# 应对: 避免嵌套量词,尽量具体化
# 2. 编译复用
# 3. 简单匹配用字符串方法更快
# "abc" in text / text.startswith("a")
# 4. re 模块函数 vs 编译对象
# 少量使用: re.search(...) 方便
# 循环使用: compile 后调用(快 30%+)
# 5. 验证输入边界
# fullmatch 用于完整匹配(防止部分匹配绕过)
实用案例
# 1. 提取所有数字
numbers = [int(x) for x in re.findall(r"\d+", text)]
# 2. 清洗文本(去 HTML 标签)
clean = re.sub(r"<[^>]+>", "", html_text)
# 3. 分割混合分隔符
parts = re.split(r"[;,\s]+", "a;b, c d")
# 4. 敏感信息脱敏
def mask_phone(text):
return re.sub(r"(1[3-9]\d)\d{4}(\d{4})",
r"\1****\2", text)
# 5. 日志解析
pattern = re.compile(
r"(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) "
r"(\w+): (.*)")
for line in log_lines:
m = pattern.match(line)
if m:
date, time, level, msg = m.groups()
正则表达式是文本处理的"瑞士军刀"。掌握元字符、分组、编译与替换,配合常用模式库,文本处理高效可靠。
Python CGI 编程
Python CGI 编程
CGI(Common Gateway Interface)是最早的 Web 动态页面技术:Web 服务器把请求转给 CGI 程序(如 Python 脚本),程序输出 HTML 返回。理解 CGI 有助于掌握 Web 工作原理。
工作原理
浏览器 → HTTP 请求 → Web 服务器
↓
执行 CGI 程序(Python)
↓
程序输出 HTML(标准输出)
↓
Web 服务器 → HTTP 响应 → 浏览器
# CGI 程序通过环境变量与标准输入获取请求信息
# 通过标准输出返回响应
最小 CGI 程序
#!/usr/bin/env python
# hello.py
import cgi
print("Content-Type: text/html\n") # 头部+空行
print("")
print("Hello, Python CGI!
")
print("")
读取请求参数
import cgi
form = cgi.FieldStorage() # 解析表单/参数
# GET: ?name=xx&age=18
# POST: 表单数据
name = form.getvalue("name", "匿名")
age = form.getvalue("age", "未知")
print("Content-Type: text/html; charset=utf-8\n")
print(f"姓名: {name}
")
print(f"年龄: {age}
")
# 多值参数
items = form.getlist("item") # 复选框
# 判断请求方法
import os
method = os.environ.get("REQUEST_METHOD", "GET")
HTML 转义(XSS 防护)
import cgi
import html
# 用户输入必须转义,防止 XSS
user_input = ""
safe = html.escape(user_input)
# '<script>alert('x')</script>'
print(f"{safe}
")
# 旧式接口
# cgi.escape() 已弃用,用 html.escape()
Cookie 与 Session
import http.cookies
# 读取 Cookie
cookie_header = os.environ.get("HTTP_COOKIE", "")
cookies = http.cookies.SimpleCookie(cookie_header)
user_id = cookies.get("user_id")
if user_id:
print(f"用户: {user_id.value}")
# 设置 Cookie(响应头)
cookie = http.cookies.SimpleCookie()
cookie["user_id"] = "12345"
cookie["user_id"]["path"] = "/"
cookie["user_id"]["max-age"] = 3600
print(cookie.output()) # Set-Cookie: ...
print("Content-Type: text/html\n")
文件上传
import cgi
form = cgi.FieldStorage()
if "file" in form:
file_item = form["file"]
if file_item.filename:
# 读取上传内容
data = file_item.file.read()
# 保存(注意路径安全!)
filename = file_item.filename
with open(f"uploads/{filename}", "wb") as f:
f.write(data)
print("上传成功")
else:
print("未选择文件")
重定向与状态码
# 重定向
print("Location: /index.html\n")
# 404
print("Status: 404 Not Found")
print("Content-Type: text/html\n")
print("404
")
# 其他常用头
print("Content-Type: application/json")
print("Content-Type: text/plain; charset=utf-8")
部署配置
# Apache: cgi-bin 目录配置
# ScriptAlias /cgi-bin/ /path/to/cgi-bin/
# 添加执行权限
# chmod +x hello.py
# Nginx + CGI(通过 fastcgi/fcgiwrap)
# 调试 CGI
# 1. 检查日志(服务器错误日志)
# 2. 直接命令行运行(模拟)
# REQUEST_METHOD=GET ./hello.py
# 3. 查看输出格式是否合法(头部+空行)
现代替代方案
# CGI 已过时,现代 Python Web 用 WSGI:
# - Flask / Django / FastAPI(框架)
# - Gunicorn / uWSGI(服务器)
# Flask 示例(替代 CGI)
from flask import Flask, request
app = Flask(__name__)
@app.route("/")
def index():
name = request.args.get("name", "匿名")
return f"你好, {name}
"
if __name__ == "__main__":
app.run()
# 为何用 WSGI:
# - 性能更好(常驻进程 vs 每次启动)
# - 功能完整(路由/模板/会话)
# - 更安全(框架内置防护)
学习价值
# 虽然 CGI 过时,但它清晰展示了:
# 1. HTTP 请求-响应模型
# 2. 服务器与程序的交互方式
# 3. 动态页面生成原理
# 4. 表单处理、Cookie、会话基础
# 理解 CGI = 理解 Web 的"最小骨架"
# 对学习 Flask/Django 帮助巨大
CGI 是 Web 编程的入门课:请求解析、响应生成、转义与 Cookie。现代开发用 Flask/Django,但 CGI 的原理不过时。
Python MySQL
Python MySQL
Python 操作 MySQL 数据库:连接、查询、增删改、事务。常用驱动:pymysql、mysql-connector-python,以及 ORM(SQLAlchemy)。
安装驱动
# pymysql(纯 Python,易装)
pip install pymysql
# 或官方驱动
pip install mysql-connector-python
# ORM(高级)
pip install sqlalchemy
连接数据库
import pymysql
# 建立连接
conn = pymysql.connect(
host="localhost", # 主机
port=3306, # 端口
user="root", # 用户
password="password", # 密码
database="test", # 数据库
charset="utf8mb4", # 编码(中文)
cursorclass=pymysql.cursors.DictCursor, # 字典游标
)
# 创建游标
cursor = conn.cursor()
查询数据
import pymysql
conn = pymysql.connect(...)
cursor = conn.cursor()
# 查询
cursor.execute("SELECT id, name FROM users")
results = cursor.fetchall() # 所有行
row = cursor.fetchone() # 单行
rows = cursor.fetchmany(5) # 5 行
# 带参数(防 SQL 注入!)
cursor.execute(
"SELECT * FROM users WHERE age > %s",
(18,)
)
# 占位符: %s(注意不是 ?)
cursor.execute(
"SELECT * FROM users WHERE name = %s AND age = %s",
("张三", 20)
)
cursor.close()
增删改
conn = pymysql.connect(...)
cursor = conn.cursor()
# 插入
cursor.execute(
"INSERT INTO users(name, age) VALUES(%s, %s)",
("李四", 25)
)
conn.commit() # 必须提交!
print(cursor.lastrowid) # 自增 ID
# 批量插入(高效)
data = [("a", 1), ("b", 2), ("c", 3)]
cursor.executemany(
"INSERT INTO users(name, age) VALUES(%s, %s)",
data
)
conn.commit()
# 更新
cursor.execute(
"UPDATE users SET age = %s WHERE name = %s",
(30, "张三")
)
conn.commit()
print(cursor.rowcount) # 影响行数
# 删除
cursor.execute(
"DELETE FROM users WHERE age < %s",
(18,)
)
conn.commit()
# 回滚(出错时)
try:
cursor.execute("INSERT INTO ...", data)
conn.commit()
except Exception:
conn.rollback() # 撤销
raise
事务处理
# 事务: 一组操作要么全部成功,要么全部回滚
try:
# 转账示例
cursor.execute(
"UPDATE accounts SET balance=balance-100 "
"WHERE id=%s", (1,))
cursor.execute(
"UPDATE accounts SET balance=balance+100 "
"WHERE id=%s", (2,))
conn.commit() # 全部成功才提交
print("转账成功")
except Exception as e:
conn.rollback() # 任一失败全部回滚
print(f"转账失败,已回滚: {e}")
finally:
cursor.close()
conn.close()
# 注意: 表引擎必须是 InnoDB 才支持事务
连接管理(推荐 with)
import pymysql
from contextlib import closing
# 自动关闭游标与连接
with closing(pymysql.connect(
host="localhost", user="root",
password="pwd", database="test",
charset="utf8mb4")) as conn:
with closing(conn.cursor()) as cursor:
cursor.execute("SELECT COUNT(*) FROM users")
print(cursor.fetchone())
SQLAlchemy ORM
from sqlalchemy import create_engine, Column, Integer, String, select
from sqlalchemy.orm import declarative_base, Session
# 连接
engine = create_engine(
"mysql+pymysql://root:password@localhost/test",
echo=True # 打印 SQL(调试)
)
Base = declarative_base()
# 定义模型
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String(50))
age = Column(Integer)
# 创建表
Base.metadata.create_all(engine)
# 增
with Session(engine) as session:
session.add(User(name="王五", age=28))
session.commit()
# 查
with Session(engine) as session:
users = session.scalars(select(User).where(
User.age > 20)).all()
for u in users:
print(u.name, u.age)
# 改/删
with Session(engine) as session:
user = session.get(User, 1)
user.age = 31
session.delete(user)
session.commit()
SQL 注入防护
# 永远用参数化查询(占位符)!
# ❌ 危险: 字符串拼接
name = "' OR '1'='1"
cursor.execute(f"SELECT * FROM users WHERE name='{name}'")
# 注入成功!
# ✅ 安全: 参数化
cursor.execute(
"SELECT * FROM users WHERE name=%s",
(name,)
)
# 规则:
# - 不用 f-string/拼接 构造 SQL
# - 用户输入一律走参数
# - 表名/列名等标识符固定,不来自用户
# (如需动态,白名单校验)
连接池与最佳实践
# 1. 连接用完即关(或 with)
# 2. 高频操作用连接池
from dbutils.pooled_db import PooledDB
pool = PooledDB(
creator=pymysql, maxconnections=10,
host="localhost", user="root",
password="pwd", database="test")
conn = pool.connection() # 从池取
# 3. 密码不硬编码(环境变量)
import os
password = os.environ.get("DB_PASSWORD")
# 4. 处理异常
try:
cursor.execute(sql, params)
except pymysql.MySQLError as e:
print(f"数据库错误: {e}")
# 5. 索引: 常用查询字段建索引
# 6. 批量操作用 executemany
# 7. 大量数据分页(limit/offset)
cursor.execute("SELECT * FROM users LIMIT %s OFFSET %s",
(page_size, offset))
Python + MySQL 是经典组合。掌握 pymysql 增删改查与事务,坚持参数化查询防注入,再进阶 SQLAlchemy ORM。
Python SMTP
Python SMTP
Python 通过 smtplib 发送邮件,配合 email 模块构造邮件内容(文本/HTML/附件)。
发送纯文本邮件
import smtplib
from email.mime.text import MIMEText
from email.header import Header
# 构造邮件
msg = MIMEText("这是一封测试邮件", "plain", "utf-8")
msg["From"] = "sender@example.com" # 发件人
msg["To"] = "receiver@example.com" # 收件人
msg["Subject"] = Header("邮件主题", "utf-8")
# 连接 SMTP 服务器并发送
smtp = smtplib.SMTP("smtp.example.com", 25)
smtp.login("username", "password") # 认证
smtp.send_message(msg)
smtp.quit()
print("邮件已发送")
发送 HTML 邮件
from email.mime.text import MIMEText
html = """
欢迎注册!
点击 这里
验证你的邮箱。
"""
msg = MIMEText(html, "html", "utf-8")
msg["Subject"] = "注册确认"
# 其余同上...
带附件
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
# 混合内容容器
msg = MIMEMultipart()
msg["From"] = "sender@example.com"
msg["To"] = "receiver@example.com"
msg["Subject"] = "月报"
# 正文
msg.attach(MIMEText("请查收附件", "plain", "utf-8"))
# 附件
with open("report.pdf", "rb") as f:
part = MIMEBase("application", "octet-stream")
part.set_payload(f.read())
encoders.encode_base64(part) # 编码
part.add_header(
"Content-Disposition",
"attachment",
filename="report.pdf",
)
msg.attach(part)
# 发送
smtp = smtplib.SMTP_SSL("smtp.example.com", 465)
smtp.login("user", "pass")
smtp.send_message(msg)
smtp.quit()
常见邮箱服务器配置
# QQ 邮箱
SMTP: smtp.qq.com
端口: 465(SSL)或 587(TLS)
认证: QQ 邮箱授权码(非登录密码)
设置: 设置 → 账户 → 开启 SMTP 服务
# 163 邮箱
SMTP: smtp.163.com
端口: 465(SSL)或 25
认证: 授权码
# Gmail
SMTP: smtp.gmail.com
端口: 587(TLS)
认证: 应用专用密码
# 企业邮箱(腾讯企业邮)
SMTP: smtp.exmail.qq.com
端口: 465/587
SSL/TLS 发送
# 方式1: SMTP_SSL(直接 SSL,端口 465)
smtp = smtplib.SMTP_SSL("smtp.qq.com", 465)
# 方式2: SMTP + starttls(端口 587)
smtp = smtplib.SMTP("smtp.qq.com", 587)
smtp.starttls() # 升级为 TLS
# 认证
smtp.login("user@qq.com", "授权码")
# 发送
smtp.send_message(msg)
# 关闭
smtp.quit()
批量发送与抄送
# 多收件人/抄送
msg["To"] = "a@example.com, b@example.com"
msg["Cc"] = "cc@example.com"
# 批量发送(复用连接,逐个 send)
recipients = ["a@x.com", "b@x.com"]
smtp = smtplib.SMTP_SSL(...)
smtp.login(...)
for to in recipients:
msg["To"] = to
smtp.send_message(msg) # 每封单独 To
smtp.quit()
# 群发注意: 大量发送易被判定垃圾邮件
# 建议: 限速、个性化内容、用专门服务
异常处理
import smtplib
try:
smtp = smtplib.SMTP_SSL("smtp.qq.com", 465)
smtp.login("user", "authcode")
smtp.send_message(msg)
print("发送成功")
except smtplib.SMTPAuthenticationError:
print("认证失败: 检查账号/授权码")
except smtplib.SMTPRecipientsRefused:
print("收件人被拒绝")
except smtplib.SMTPException as e:
print(f"发送失败: {e}")
finally:
try:
smtp.quit()
except Exception:
pass
封装邮件发送函数
import smtplib
from email.mime.text import MIMEText
from email.header import Header
import os
SMTP_HOST = os.environ.get("SMTP_HOST", "smtp.qq.com")
SMTP_PORT = int(os.environ.get("SMTP_PORT", "465"))
SMTP_USER = os.environ.get("SMTP_USER")
SMTP_AUTH = os.environ.get("SMTP_AUTH") # 授权码
def send_email(to, subject, content,
content_type="plain"):
"""发送邮件"""
msg = MIMEText(content, content_type, "utf-8")
msg["From"] = SMTP_USER
msg["To"] = to
msg["Subject"] = Header(subject, "utf-8")
with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT) as smtp:
smtp.login(SMTP_USER, SMTP_AUTH)
smtp.send_message(msg)
# 使用
send_email("receiver@example.com",
"通知", "您的订单已发货")
最佳实践
# 1. 凭据用环境变量,不硬编码
# 2. 邮件模板化(HTML 模板 + 数据填充)
# 3. 附件大小控制
# 4. 发送失败重试(带退避)
# 5. 记录发送日志
# 6. 生产环境考虑邮件服务(腾讯云/阿里云 SES)
# 或第三方(如 SendGrid)
# 7. 中文用 utf-8 编码 + Header
# 大文件附件: 放网盘发链接,勿直接附件
# 敏感内容: 确认合规与加密
Python SMTP 让程序自动发邮件:通知、报表、验证码。掌握 smtplib + email 模块,配合邮箱授权码,即可上线邮件功能。
Python 多线程
Python 多线程
多线程让程序同时处理多个任务,适合 I/O 密集场景(网络请求、文件读写)。本节介绍 threading 与相关工具。
创建线程
import threading
import time
def worker(name, delay):
time.sleep(delay)
print(f"{name} 完成")
# 方式1: 直接创建
t = threading.Thread(target=worker,
args=("任务A", 1))
t.start() # 启动线程
t.join() # 等待完成
# 方式2: 继承 Thread
class MyThread(threading.Thread):
def __init__(self, name):
super().__init__()
self.name = name
def run(self): # 重写 run
time.sleep(0.5)
print(f"线程 {self.name} 运行中")
t = MyThread("T1")
t.start()
并发执行多个任务
import threading
import time
def task(name, seconds):
print(f"{name} 开始")
time.sleep(seconds)
print(f"{name} 结束")
return name
# 启动多个线程
threads = []
for i in range(3):
t = threading.Thread(target=task,
args=(f"任务{i}", 1))
t.start()
threads.append(t)
# 等待全部完成
for t in threads:
t.join()
print("全部完成")
# 对比串行: 串行需 3 秒,并行约 1 秒(I/O)
线程安全与锁
import threading
# 共享数据需要锁保护
counter = 0
lock = threading.Lock()
def increment():
global counter
for _ in range(10000):
with lock: # 加锁
counter += 1
threads = [threading.Thread(target=increment)
for _ in range(5)]
for t in threads: t.start()
for t in threads: t.join()
print(counter) # 50000(无锁可能小于此值)
# 其他锁:
# threading.RLock(): 可重入锁(同线程可重复获取)
# threading.Semaphore(n): 信号量(限制并发数)
# threading.Event(): 事件(线程间通知)
线程间通信(Queue)
import threading
import queue
import time
# 线程安全队列
q = queue.Queue()
def producer():
for i in range(5):
q.put(f"消息{i}") # 生产
time.sleep(0.1)
q.put(None) # 结束信号
def consumer():
while True:
item = q.get()
if item is None:
break
print(f"消费: {item}")
# 多个生产者/消费者
threading.Thread(target=producer).start()
for _ in range(2):
threading.Thread(target=consumer).start()
ThreadPoolExecutor(推荐)
from concurrent.futures import ThreadPoolExecutor
import time
def fetch(url):
time.sleep(1) # 模拟请求
return f"{url} 数据"
# 线程池: 控制并发数
with ThreadPoolExecutor(max_workers=4) as pool:
urls = [f"url{i}" for i in range(8)]
# 方式1: map(批量)
results = list(pool.map(fetch, urls))
# 方式2: submit + as_completed(按完成顺序)
futures = [pool.submit(fetch, u) for u in urls]
for fut in futures:
print(fut.result())
# 8 个任务,4 并发: 约 2 秒(串行需 8 秒)
# 与 asyncio 对比:
# ThreadPoolExecutor: 简单,线程开销
# asyncio: 更高效,但需异步代码
线程局部数据
import threading
# 每个线程独立的存储
local = threading.local()
def worker(name):
local.name = name # 线程私有
time.sleep(0.1)
print(f"{local.name} 完成")
threads = [threading.Thread(target=worker,
args=(f"T{i}",))
for i in range(3)]
for t in threads: t.start()
for t in threads: t.join()
# 每个线程访问自己的 local.name
守护线程
import threading
import time
def daemon_worker():
while True:
print("守护线程工作中...")
time.sleep(1)
# daemon=True: 主线程结束则自动结束
d = threading.Thread(target=daemon_worker,
daemon=True)
d.start()
# 主线程做自己的事
time.sleep(3)
print("主线程结束")
# 守护线程随之结束(不阻塞退出)
# 应用: 心跳、监控、日志后台任务
GIL 与多进程
# GIL(全局解释器锁):
# 同一时刻只有一个线程执行 Python 字节码
# → CPU 密集任务多线程无提速!
# I/O 密集: 多线程有效(等待时释放 GIL)
# CPU 密集: 用多进程(每个进程独立 GIL)
# 多进程
from concurrent.futures import ProcessPoolExecutor
def cpu_task(n):
return sum(i * i for i in range(n))
with ProcessPoolExecutor(max_workers=4) as pool:
results = list(pool.map(cpu_task,
[10**6] * 4))
# 多进程注意:
# - 开销大(进程创建)
# - 数据传递需序列化
# - 共享状态复杂(用 Queue/Pipe)
最佳实践
# 1. 优先 ThreadPoolExecutor(简单安全)
# 2. I/O 密集用线程,CPU 密集用进程
# 3. 共享数据一律加锁
# 4. 通信用 Queue,少用共享变量
# 5. 设置 daemon 或确保 join(防僵尸)
# 6. 异常在任务内捕获(线程异常不自动打印)
# 线程内异常处理
def safe_worker():
try:
risky_io()
except Exception as e:
print(f"任务失败: {e}")
# 获取线程结果(用 Future)
with ThreadPoolExecutor() as pool:
fut = pool.submit(fetch, "url")
try:
result = fut.result(timeout=5) # 超时
except TimeoutError:
print("超时")
多线程是 I/O 密集任务的提速器。掌握 ThreadPoolExecutor、锁与 Queue,注意 GIL 限制(CPU 密集用进程),并发编程不再神秘。
Python XML 解析
Python XML 解析
XML 是结构化数据格式。Python 提供多种解析方式:ElementTree(推荐)、DOM、SAX,以及高性能的 lxml。
XML 示例
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="1">
<title>Python 入门</title>
<price>59.0</price>
</book>
<book id="2">
<title>Python 进阶</title>
<price>79.0</price>
</book>
</bookstore>
ElementTree 解析(推荐)
import xml.etree.ElementTree as ET
# 从文件
tree = ET.parse("books.xml")
root = tree.getroot()
# 从字符串
root = ET.fromstring(xml_string)
# 基本访问
root.tag # 'bookstore'
root.attrib # {} 属性字典
root.text # 文本(直接子文本)
# 遍历
for book in root: # 直接子元素
print(book.tag, book.attrib)
for book in root.iter("book"): # 递归找所有 book
print(book.get("id"))
# 查找
root.find("book") # 第一个 book
root.findall("book") # 所有 book
root.find(".//title") # XPath 递归找 title
root.findall(".//price") # 所有 price
book.find("title").text # 子元素文本
读取与修改
import xml.etree.ElementTree as ET
tree = ET.parse("books.xml")
root = tree.getroot()
# 读取元素内容
for book in root.findall("book"):
book_id = book.get("id") # 属性
title = book.find("title").text # 子元素
price = float(book.find("price").text)
print(f"{book_id}: {title} - {price}")
# 修改
book = root.find("book")
book.set("id", "100") # 改属性
book.find("title").text = "新标题" # 改文本
book.find("price").text = "99.0"
# 删除
root.remove(book) # 删除子元素
# 保存
tree.write("books_new.xml", encoding="utf-8",
xml_declaration=True)
创建 XML
import xml.etree.ElementTree as ET
# 创建根元素
root = ET.Element("bookstore")
# 添加子元素
book = ET.SubElement(root, "book")
book.set("id", "3")
title = ET.SubElement(book, "title")
title.text = "Python 高级"
price = ET.SubElement(book, "price")
price.text = "89.0"
# 转成字符串
xml_str = ET.tostring(root, encoding="unicode")
print(xml_str)
# 保存到文件
tree = ET.ElementTree(root)
tree.write("new_books.xml", encoding="utf-8",
xml_declaration=True)
XPath 查询
import xml.etree.ElementTree as ET
root = ET.parse("books.xml").getroot()
# 常用 XPath
root.findall("book") # 直接子 book
root.findall(".//title") # 所有 title
root.findall("book[@id='1']") # 属性过滤
root.findall(".//book[price>60]") # 条件(部分支持)
root.find("./book[2]") # 第 2 个 book
# 遍历命名空间
# <ns:book xmlns:ns="http://x.com">
ns = {"ns": "http://x.com"}
root.findall("ns:book", ns) # 带命名空间查找
DOM 解析(minidom)
from xml.dom import minidom
# 解析
doc = minidom.parse("books.xml")
root = doc.documentElement # bookstore
# 获取元素
books = doc.getElementsByTagName("book")
for book in books:
book_id = book.getAttribute("id")
title = book.getElementsByTagName("title")[0]
title_text = title.firstChild.nodeValue
print(f"{book_id}: {title_text}")
# 与 ElementTree 对比:
# DOM 更接近标准(全树在内存)
# ElementTree 更 Pythonic,推荐日常使用
SAX 解析(流式)
# SAX: 事件驱动,适合超大文件(省内存)
import xml.sax
class BookHandler(xml.sax.ContentHandler):
def __init__(self):
self.current = None
self.books = []
def startElement(self, name, attrs):
if name == "book":
self.current = {"id": attrs.get("id")}
elif name in ("title", "price") and self.current:
self.current[name] = ""
def characters(self, content):
if self.current and self.current.get(
"title") is not None:
if "title" in self.current and \
isinstance(self.current["title"], str) \
and len(self.current["title"]) < 100:
self.current["title"] += content
def endElement(self, name):
if name == "book" and self.current:
self.books.append(self.current)
self.current = None
handler = BookHandler()
xml.sax.parse("books.xml", handler)
print(handler.books)
# 使用场景: 超大 XML(GB 级)流式处理
lxml(高性能推荐)
# pip install lxml
from lxml import etree
# 解析
tree = etree.parse("books.xml")
root = tree.getroot()
# XPath 强大
root.xpath("//book[@id='2']/title/text()")
# ['Python 进阶']
# 遍历
for book in root.iter("book"):
print(book.get("id"),
book.findtext("title"))
# 创建
root = etree.Element("bookstore")
book = etree.SubElement(root, "book")
etree.SubElement(book, "title").text = "lxml 教程"
# 序列化
print(etree.tostring(root, pretty_print=True,
encoding="unicode"))
# lxml 优势: 快、XPath 完整、HTML 解析
# 与 ElementTree API 兼容(大多数场景可直接换)
安全注意
# XXE 攻击(XML 外部实体注入)!
# 恶意 XML 可读取服务器文件
# <!DOCTYPE x [<!ENTITY f SYSTEM "file:///etc/passwd">]>
# ElementTree 默认不处理外部实体(较安全)
# lxml 需禁用:
from lxml import etree
parser = etree.XMLParser(
resolve_entities=False, # 禁用实体解析
no_network=True) # 禁用网络
tree = etree.parse("data.xml", parser)
# 解析不可信 XML 的通用建议:
# - 禁用外部实体
# - 限制解析深度/大小
# - 优先 JSON(简单场景)
最佳实践
# 1. 日常解析用 ElementTree(标准库,够用)
# 2. 复杂 XPath/高性能用 lxml
# 3. 超大文件用 SAX/流式(iterparse)
# 4. 处理不可信 XML 注意 XXE
# 5. 简单数据交换优先 JSON(更轻量)
# 流式处理大文件
import xml.etree.ElementTree as ET
for event, elem in ET.iterparse("big.xml"):
if elem.tag == "book":
process(elem)
elem.clear() # 释放内存
XML 解析是数据处理常客。ElementTree 满足多数需求,lxml 更强更快,SAX 应对超大文件。按场景选择,注意安全。
Python GUI 编程(Tkinter)
Python GUI 编程(Tkinter)
Tkinter 是 Python 标准库自带的 GUI 工具包,无需安装即可创建桌面窗口程序。适合工具类应用与学习 GUI 编程。
第一个窗口
import tkinter as tk
# 创建主窗口
root = tk.Tk()
root.title("我的程序")
root.geometry("400x300") # 宽x高
# 主循环(显示窗口)
root.mainloop()
常用控件
import tkinter as tk
root = tk.Tk()
# 标签
label = tk.Label(root, text="欢迎使用", fg="blue",
font=("Arial", 16))
label.pack(pady=10)
# 按钮
def on_click():
label.config(text="按钮被点击了!")
btn = tk.Button(root, text="点击我",
command=on_click)
btn.pack(pady=5)
# 输入框
entry = tk.Entry(root, width=30)
entry.pack(pady=5)
entry.insert(0, "默认文本")
# 文本区域
text = tk.Text(root, height=5, width=40)
text.pack(pady=5)
# 单选/复选
var = tk.IntVar()
check = tk.Checkbutton(root, text="记住我",
variable=var)
check.pack()
# 下拉框
import tkinter.ttk as ttk
combo = ttk.Combobox(root, values=["A", "B", "C"])
combo.pack()
root.mainloop()
布局管理
import tkinter as tk
root = tk.Tk()
# pack: 顺序排列
tk.Label(root, text="上").pack(side="top")
tk.Label(root, text="左").pack(side="left")
tk.Label(root, text="右").pack(side="right")
tk.Label(root, text="下").pack(side="bottom")
# grid: 网格布局(推荐复杂界面)
root = tk.Tk()
for r in range(3):
for c in range(3):
tk.Button(root, text=f"{r},{c}").grid(
row=r, column=c, padx=5, pady=5)
# place: 绝对定位
tk.Label(root, text="定位").place(x=50, y=100)
# 扩展: sticky/expand/fill
tk.Button(root, text="填充").pack(
fill="x", expand=True) # 水平填充
事件绑定
import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(root, width=300, height=200,
bg="white")
canvas.pack()
# 鼠标事件
def on_click(event):
canvas.create_oval(event.x-3, event.y-3,
event.x+3, event.y+3,
fill="red")
canvas.bind("", on_click) # 左键点击
# 键盘事件
def on_key(event):
print(f"按下: {event.keysym}")
root.bind("", on_key)
# 常用事件:
# 左键 右键
# 双击
# 移动 回车
# 按键 a
完整示例: 待办清单
import tkinter as tk
from tkinter import messagebox
class TodoApp:
def __init__(self):
self.root = tk.Tk()
self.root.title("待办清单")
self.root.geometry("360x400")
# 输入区
self.entry = tk.Entry(self.root, width=30)
self.entry.pack(pady=10)
self.entry.bind("", self.add_todo)
tk.Button(self.root, text="添加",
command=self.add_todo).pack()
# 列表
self.listbox = tk.Listbox(self.root,
width=42, height=15)
self.listbox.pack(pady=10)
# 操作按钮
tk.Button(self.root, text="删除选中",
command=self.delete_todo).pack()
self.root.mainloop()
def add_todo(self, event=None):
text = self.entry.get().strip()
if text:
self.listbox.insert(tk.END, text)
self.entry.delete(0, tk.END)
else:
messagebox.showwarning("提示", "不能为空")
def delete_todo(self):
try:
idx = self.listbox.curselection()[0]
self.listbox.delete(idx)
except IndexError:
messagebox.showinfo("提示", "请先选中")
TodoApp()
对话框
from tkinter import messagebox, filedialog, simpledialog
# 消息框
messagebox.showinfo("信息", "操作成功")
messagebox.showwarning("警告", "磁盘空间不足")
messagebox.showerror("错误", "文件不存在")
result = messagebox.askyesno("确认", "确定删除?")
# 文件对话框
filename = filedialog.askopenfilename(
title="选择文件", filetypes=[("文本", "*.txt")])
save_path = filedialog.asksaveasfilename()
# 输入对话框
name = simpledialog.askstring("输入", "你的名字:")
number = simpledialog.askinteger("输入", "数字:")
定时任务与动画
import tkinter as tk
import time
root = tk.Tk()
label = tk.Label(root, text="", font=("Arial", 24))
label.pack()
# 定时更新
def update_time():
label.config(text=time.strftime("%H:%M:%S"))
root.after(1000, update_time) # 1秒后再调用
update_time()
# 简单动画
x = 0
ball = tk.Label(root, text="●", font=("Arial", 20))
ball.pack()
def move():
global x
x = (x + 5) % 300
ball.place(x=x, y=100)
root.after(50, move) # 50ms 移动一次
move()
root.mainloop()
最佳实践
# 1. 长任务放线程(否则界面卡死)
import threading
def long_task():
# 耗时操作...
pass
tk.Button(root, text="开始",
command=lambda: threading.Thread(
target=long_task, daemon=True).start())
# 2. 界面更新放主线程(用队列通信)
# 3. 组件用 grid/pack 合理布局
# 4. 样式统一(颜色/字体常量)
# 5. 数据与界面分离(简单 MVC)
# 其他 GUI 框架:
# - PyQt/PySide: 强大专业
# - wxPython: 原生外观
# - Kivy: 移动端
# - 简单工具: Tkinter 够用
# 打包发布
# pip install pyinstaller
# pyinstaller --onefile --windowed app.py
Tkinter 让 Python 轻松拥有图形界面。掌握控件、布局与事件,配合线程处理耗时任务,即可开发实用桌面工具。
Python2.x 与 3.x 版本区别
Python2.x 与 3.x 版本区别
Python 3 是 Python 2 的重大升级,不向后兼容。理解两者的区别,有助于阅读旧代码与正确迁移。Python 2 已于 2020 年停止维护。
核心差异总览
# 1. print 语句 vs 函数
# Python 2
print "hello"
# Python 3
print("hello")
# 2. 整数除法
# Python 2: 3 / 2 = 1(整数除)
# Python 3: 3 / 2 = 1.5(真除法)
# 3 // 2 = 1(整除)
# 3. 字符串与 Unicode
# Python 2: str(字节) + unicode(文本)
# Python 3: str(文本) + bytes(字节)
# 默认源码编码: ASCII → UTF-8
语法差异
# 1. 异常语法
# Python 2
try:
pass
except Exception, e: # 逗号语法
print e
# Python 3
try:
pass
except Exception as e: # as 语法
print(e)
# 2. 输入
# Python 2: raw_input() 返回 str, input() 会 eval!
# Python 3: input() 统一返回 str(安全)
# 3. range vs xrange
# Python 2: range() 返回列表, xrange() 惰性
# Python 3: range() 惰性(等价 xrange),无 xrange
# 4. 比较
# Python 2: 不同类型可比较(如 1 < "a")
# Python 3: 不同类型比较报错(更安全)
数据类型差异
# 1. 长整数
# Python 2: int + long(大数自动转 long)
# Python 3: 统一 int(任意精度,无 long)
# 2. 字典
# Python 2: 无序
# Python 3.7+: 保持插入顺序
# 3. 迭代器
# Python 2: dict.keys() 返回列表
# Python 3: dict.keys() 返回视图(省内存)
# 遍历中修改需 list(dict.keys())
# 4. 字节 vs 文本
# Python 2: "abc" 是字节; u"abc" 是文本
# Python 3: "abc" 是文本; b"abc" 是字节
模块与库变化
# 1. 模块重命名
# Python 2 → Python 3
# ConfigParser → configparser
# Queue → queue
# StringIO → io
# urllib2 → urllib.request
# Tkinter → tkinter
# __builtin__ → builtins
# 2. 函数移动
# map/filter/zip 返回迭代器(2 返回列表)
# reduce 移入 functools
# 3. 标准库删除
# 部分模块移除或改版(需替换方案)
其他变化
# 1. 元类语法
# Python 2: __metaclass__ = Meta
# Python 3: class C(metaclass=Meta)
# 2. 超级调用
# Python 2: super(Class, self).method()
# Python 3: super().method()
# 3. 非本地变量
# Python 2 无 nonlocal; 3 引入
def outer():
x = 0
def inner():
nonlocal x # 3 才有
x += 1
# 4. 解包扩展
# Python 3: a, *b, c = [1,2,3,4]
# 5. f-string / dataclass / walrus
# Python 3.6+: f"{x}"
# Python 3.8+: := 海象运算符
# Python 3.10+: match-case
# Python 3.12+: 类型语法增强
迁移建议
# 1. 新项目直接用 Python 3(无理由用 2)
# 2. 旧项目迁移工具: 2to3
python -m lib2to3 -w old_script.py
# 3. 兼容写法(2/3 通用)
from __future__ import (
print_function, division,
unicode_literals)
# 4. 用 six/future 库处理兼容
import six
six.moves.range(5)
# 5. 检查依赖: 确认第三方库支持 3
# 6. 字符串/字节处理是迁移最大难点
# - 明确 str 与 bytes 的边界
# - 文件读写显式指定编码
# 迁移优先级:
# 1. print/除法/异常语法(自动工具可改)
# 2. 字符串编码(人工检查重点)
# 3. 第三方库依赖(确认版本)
# 4. 测试充分(行为差异)
实践检查清单
# 从 2 迁到 3 时的常见问题:
# [ ] print 是否都是函数形式
# [ ] 整数除法是否符合预期(用 // 或 float)
# [ ] 字符串 vs 字节是否混淆
# [ ] range 是否有索引操作(需 list)
# [ ] dict.keys() 是否有修改遍历
# [ ] 异常语法是否用 as
# [ ] 模块导入名是否更新
# [ ] 编码声明与文件读写
# [ ] 第三方依赖兼容性
# [ ] 正则字节模式匹配
# 验证工具:
# python -W error::DeprecationWarning script.py
# 可发现 2 的兼容警告
Python 3 是唯一被积极维护的版本。理解 2→3 的差异,迁移旧代码时有章可循;新代码永远选择 Python 3。
Python IDE
Python IDE
好的开发环境显著提升效率。本节介绍主流 Python IDE/编辑器,以及开发环境的配置技巧。
IDE 对比
# PyCharm(专业 IDE)
# - 功能全: 调试/重构/数据库/远程
# - 社区版免费(够用),专业版付费
# - 适合: 大型项目、专业开发
# VS Code(轻量编辑器)
# - 免费开源,插件丰富
# - Python + Pylance 体验极佳
# - 适合: 全栈、轻量开发、多数场景
# Jupyter Notebook
# - 交互式: 代码/文本/图表混合
# - 适合: 数据分析、教学、探索
# 其他:
# - Sublime/Atom(轻量)
# - Spyder(科学计算)
# - IDLE(自带,入门)
# - Thonny(教学,断点可视化)
VS Code 配置
# 1. 安装扩展
# - Python(Microsoft)
# - Pylance(类型检查/补全)
# - Jupyter(Notebook 支持)
# - Python Debugger
# 2. 选择解释器
# Ctrl+Shift+P → Python: Select Interpreter
# 选择虚拟环境
# 3. 设置(settings.json 片段)
{
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.formatting.provider": "black",
"editor.formatOnSave": true,
"python.analysis.typeCheckingMode": "basic"
}
# 4. 调试
# 添加 launch.json
# 断点 → F5 调试
PyCharm 配置
# 1. 创建项目时选择虚拟环境
# 2. 解释器: Settings → Project → Python Interpreter
# 3. 常用快捷键
# Ctrl+Alt+L 格式化代码
# Ctrl+Shift+F10 运行
# Ctrl+Shift+F9 调试
# Ctrl+Alt+Shift+↑ 重构
# Shift+Enter 新行
# 4. 代码检查
# Alt+Enter 快速修复
# 自动提示潜在问题
# 5. 调试器
# 断点、表达式求值、变量查看
# 条件断点、异常断点
工具链配置
# 代码格式化: black
pip install black
black my_script.py # 自动格式化
# 代码检查: ruff(快速)
pip install ruff
ruff check . # 检查
ruff check --fix . # 自动修复
# 类型检查: mypy
pip install mypy
mypy my_script.py
# 一键配置(推荐组合)
# .pre-commit-config.yaml
# - black 格式化
# - ruff 检查
# - mypy 类型
Jupyter 使用
# 安装
pip install jupyter
# 启动
jupyter notebook # 传统界面
jupyter lab # 现代界面
# 快捷键
Shift+Enter 运行并前进
Esc → A/B 上方/下方插入
Esc → M/Y 单元格转 Markdown/代码
Tab 补全
# 常用魔法命令
%time 计时
%timeit 多次计时
%matplotlib inline 内嵌图表
%%writefile 写文件
%run script.py 运行脚本
调试技巧
# 1. 断点调试(IDE)
# 2. print 调试(简单场景)
# 3. logging 调试(生产环境)
# 4. pdb 命令行调试
import pdb
pdb.set_trace() # 设置断点
# 运行到此处进入交互调试
# n 下一步 / s 进入函数 / c 继续 / q 退出
# p 变量名 打印变量
# 5. 异常追踪
# 捕获时打印完整堆栈
import traceback
try:
risky()
except Exception:
traceback.print_exc()
# 6. ipdb(更好的 pdb)
# pip install ipdb
# 有补全与高亮
虚拟环境与依赖管理
# venv
python -m venv .venv
source .venv/bin/activate # Linux/macOS
.venv\Scripts\activate # Windows
pip install -r requirements.txt
# poetry(现代依赖管理)
pip install poetry
poetry new myproject
poetry add requests
poetry run python main.py
# uv(超快速)
pip install uv
uv venv
uv pip install -r requirements.txt
uv add requests
# conda(科学计算)
conda create -n env python=3.11
conda activate env
最佳实践
# 1. 项目级虚拟环境(隔离依赖)
# 2. 格式化/检查/类型 一站式配置
# 3. 用调试器而非 print(高效定位)
# 4. 快捷键熟练(提升操作效率)
# 5. 代码片段与模板(常用模式)
# 6. 版本控制集成(Git 面板)
# 7. 主题与字体(护眼舒适)
# 推荐新手路线:
# IDLE/Jupyter 入门 → VS Code 或 PyCharm 深入
# 数据分析 → Jupyter + VS Code
工具是效率放大器。选一个主力 IDE 并配置到位(格式化+检查+调试),配合虚拟环境,开发体验大幅提升。
Python JSON
Python JSON
JSON 是现代数据交换的标准格式。Python 通过 json 模块实现 JSON 的解析与生成,与字典/列表无缝转换。
基本转换
import json
# 字典 → JSON 字符串
data = {"name": "Python", "age": 30,
"tags": ["web", "ai"]}
json_str = json.dumps(data)
print(json_str)
# '{"name": "Python", "age": 30, "tags": ["web", "ai"]}'
# JSON 字符串 → Python 对象
text = '{"name": "Python", "age": 30}'
data = json.loads(text)
print(data["name"]) # 'Python'
print(type(data)) # <class 'dict'>
文件读写
import json
# 写入文件
data = {"users": [{"name": "张三", "age": 25}]}
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False,
indent=2) # 美化缩进
# 读取文件
with open("data.json", "r", encoding="utf-8") as f:
data = json.load(f)
# 关键参数:
# ensure_ascii=False: 中文原样保存(不转 \uXXXX)
# indent=2: 格式化缩进(可读)
# sort_keys=True: 键排序(一致输出)
类型映射
# Python → JSON
dict → object
list/tuple → array
str → string
int/float → number
True/False → true/false
None → null
# JSON → Python(反向)
# 注意: tuple 转 JSON 变 array,读回是 list
import json
d = json.dumps({"t": (1, 2, 3)})
# '{"t": [1, 2, 3]}'
json.loads(d)["t"] # [1, 2, 3](list!)
处理中文
import json
data = {"name": "中国"}
# 默认: 中文转义为 \u 序列
json.dumps(data)
# '{"name": "\u4e2d\u56fd"}'
# 保持可读
json.dumps(data, ensure_ascii=False)
# '{"name": "中国"}'
# 读取时自动解码(无需特殊处理)
text = '{"name": "\u4e2d\u56fd"}'
json.loads(text)["name"] # '中国'
复杂对象序列化
import json
from datetime import datetime
# 自定义类型需要转换
class User:
def __init__(self, name, age):
self.name = name
self.age = age
# 方式1: 自定义函数
def user_to_dict(user):
return {"name": user.name, "age": user.age}
u = User("张三", 25)
json.dumps(u, default=user_to_dict)
# '{"name": "张三", "age": 25}'
# 方式2: 默认处理 datetime
def default_handler(obj):
if isinstance(obj, datetime):
return obj.isoformat()
if hasattr(obj, "__dict__"):
return obj.__dict__
return str(obj)
data = {"time": datetime.now()}
json.dumps(data, default=default_handler)
# 方式3: 对象自带 to_json
class User:
def to_json(self):
return {"name": self.name, "age": self.age}
json.dumps(u, default=lambda o: o.to_json())
错误处理
import json
# 解析失败
try:
data = json.loads('{"invalid": }')
except json.JSONDecodeError as e:
print(f"JSON 解析错误: {e}")
print(f"位置: 行 {e.lineno}, 列 {e.colno}")
# 常见错误:
# - 尾逗号: {"a": 1,}(不允许!)
# - 单引号: {'a': 1}(必须双引号!)
# - 注释: 不支持
# - 尾随内容: {"a":1} extra
# 宽松解析技巧(不推荐,先修数据)
# 用 ast.literal_eval 处理 Python 风格字面量
import ast
data = ast.literal_eval("{'a': 1}") # 仅安全字面量
JSON Lines(逐行 JSON)
# 大数据: 每行一个 JSON 对象
# data.jsonl
# {"id": 1, "name": "a"}
# {"id": 2, "name": "b"}
import json
# 写入
with open("data.jsonl", "w", encoding="utf-8") as f:
for item in items:
f.write(json.dumps(item,
ensure_ascii=False) + "\n")
# 读取
with open("data.jsonl", "r", encoding="utf-8") as f:
for line in f:
if line.strip():
item = json.loads(line)
print(item["name"])
# 适用: 日志、流式处理、百万级数据
网络 API 中的 JSON
import json
import urllib.request
# 请求 API 并解析 JSON
url = "https://api.example.com/data"
with urllib.request.urlopen(url) as resp:
data = json.loads(resp.read().decode("utf-8"))
# 用 requests(更常用)
import requests
resp = requests.get(url, timeout=5)
data = resp.json() # 自动解析 JSON
print(data)
# 发送 JSON
resp = requests.post(url,
json={"name": "张三"}, # 自动转 JSON
headers={"Authorization": "Bearer xxx"})
最佳实践
# 1. 读写文件指定 encoding="utf-8"
# 2. 中文 ensure_ascii=False 保持可读
# 3. 数据结构化校验(schema)
# - jsonschema 库
# - 或 pydantic(现代推荐)
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
user = User.model_validate_json(
'{"name": "张三", "age": 25}')
# 4. 解析不可信 JSON 限制大小/深度
# 5. 性能: 大量解析用 orjson(更快)
# import orjson
# orjson.loads / orjson.dumps
实用案例
# 1. 配置管理
with open("config.json", encoding="utf-8") as f:
config = json.load(f)
host = config.get("host", "localhost")
# 2. 数据导出/导入
# 数据库记录 → JSON(方便交换)
# 3. 日志结构化
import logging
log_entry = {
"time": datetime.now().isoformat(),
"level": "ERROR",
"message": "请求失败",
"request_id": "abc123",
}
print(json.dumps(log_entry, ensure_ascii=False))
# 便于日志系统(ELK)采集分析
JSON 是 Python 与世界交互的"通用语言"。掌握 dump/load 与参数细节,配合文件读写与 API 使用,数据交换畅通无阻。
Python 100例
Python 100例
实践出真知。本节精选 20 个经典编程练习(涵盖基础、算法、数据处理),每个都配有解法与思路。建议先自己动手,再看答案。
1-5: 基础练习
# 1. 判断奇偶
def is_odd(n):
return n % 2 == 1
# 2. 交换两个变量
a, b = 5, 10
a, b = b, a
# 3. 判断闰年
def is_leap(year):
return (year % 4 == 0 and year % 100 != 0) \
or year % 400 == 0
# 4. 计算阶乘
def factorial(n):
result = 1
for i in range(1, n + 1):
result *= i
return result
# 或: from math import factorial
# 5. 斐波那契数列
def fib(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
# fib(10) → 55
6-10: 字符串与列表
# 6. 判断回文
def is_palindrome(s):
s = s.lower().replace(" ", "")
return s == s[::-1]
# 7. 字符串反转
s[::-1]
# 8. 统计字符出现次数
from collections import Counter
Counter("hello").most_common(1)
# 9. 列表去重
list(set([1, 2, 2, 3]))
# 保持顺序
list(dict.fromkeys([1, 2, 2, 3]))
# 10. 找出最大/次大
nums = [3, 1, 4, 1, 5, 9, 2, 6]
sorted(set(nums))[-2:] # 最大两个
# 或遍历找次大
def second_max(nums):
first = second = float("-inf")
for n in nums:
if n > first:
second = first
first = n
elif n > second:
second = n
return second
11-15: 数学与算法
# 11. 判断素数
def is_prime(n):
if n < 2: return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0: return False
return True
# 12. 最大公约数/最小公倍数
import math
math.gcd(12, 18) # 6
math.lcm(12, 18) # 36
# 13. 冒泡排序
def bubble_sort(arr):
n = len(arr)
for i in range(n - 1):
for j in range(n - 1 - i):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr
# 14. 二分查找
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
# 15. 两数之和(找下标)
def two_sum(nums, target):
seen = {}
for i, n in enumerate(nums):
if target - n in seen:
return [seen[target - n], i]
seen[n] = i
return []
# two_sum([2,7,11,15], 9) → [0, 1]
16-20: 数据处理与实用
# 16. 词频统计
from collections import Counter
text = "the quick brown fox the lazy dog"
words = text.split()
top = Counter(words).most_common(3)
# 17. 字典按键/值排序
d = {"b": 2, "a": 3, "c": 1}
sorted(d.items()) # 按键
sorted(d.items(), key=lambda x: x[1]) # 按值
# 18. 扁平化嵌套列表
def flatten(lst):
result = []
for item in lst:
if isinstance(item, list):
result.extend(flatten(item))
else:
result.append(item)
return result
flatten([1, [2, [3, 4], 5], 6]) # [1,2,3,4,5,6]
# 19. 生成器: 无限序列
def even_numbers():
n = 0
while True:
yield n
n += 2
gen = even_numbers()
next(gen) # 0
next(gen) # 2
# 20. 日期工具
from datetime import datetime, timedelta
days_ago = datetime.now() - timedelta(days=7)
# 格式化
datetime.now().strftime("%Y-%m-%d %H:%M")
21-25: 进阶算法
# 21. 快速排序
def quicksort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
mid = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quicksort(left) + mid + quicksort(right)
# 22. 二分/快慢指针找中间
# 链表找中点(快慢指针)
def middle(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow
# 23. 最长公共前缀
def longest_common_prefix(strs):
if not strs: return ""
prefix = strs[0]
for s in strs[1:]:
while not s.startswith(prefix):
prefix = prefix[:-1]
if not prefix: return ""
return prefix
# 24. 斐波那契(DP 记忆化)
from functools import lru_cache
@lru_cache(maxsize=None)
def fib_dp(n):
return n if n < 2 else fib_dp(n-1) + fib_dp(n-2)
# 25. 滑动窗口最大和
def max_subarray_sum(nums, k):
window = sum(nums[:k])
result = window
for i in range(k, len(nums)):
window += nums[i] - nums[i - k]
result = max(result, window)
return result
# max_subarray_sum([2,1,5,1,3,2], 3) → 9
26-30: 文件与系统
# 26. 读取 CSV 汇总
import csv
with open("data.csv", encoding="utf-8") as f:
reader = csv.DictReader(f)
total = sum(float(row["price"])
for row in reader)
# 27. 目录遍历
from pathlib import Path
for p in Path(".").glob("**/*.py"):
print(p)
# 28. 文件去重
seen = set()
with open("out.txt", "w", encoding="utf-8") as out:
for line in open("in.txt", encoding="utf-8"):
if line not in seen:
seen.add(line)
out.write(line)
# 29. 并发下载(简单)
from concurrent.futures import ThreadPoolExecutor
import urllib.request
def download(url):
with urllib.request.urlopen(url) as r:
return len(r.read())
urls = ["https://example.com"] * 5
with ThreadPoolExecutor(max_workers=5) as pool:
sizes = list(pool.map(download, urls))
# 30. 定时任务
import time
while True:
do_job()
time.sleep(3600) # 每小时一次
练习建议
# 1. 先手写,再看答案(记忆更深)
# 2. 每个例子尝试多种解法(对比优劣)
# 3. 改写参数/边界条件(测试理解)
# 4. 用测试验证
import unittest
class TestPrime(unittest.TestCase):
def test_is_prime(self):
self.assertTrue(is_prime(17))
self.assertFalse(is_prime(18))
# 5. 进阶题库:
# - LeetCode(算法)
# - 菜鸟教程 Python 100 例(全量)
# - 牛客网(面试题)
# - Project Euler(数学编程)
练习是学习的加速器。把每道题"讲给别人听"(费曼技巧),或写成博客,理解会更深。编程是练出来的,不是看出来的。
Python2.x 教程
Python2.x 教程(总结)
本教程围绕 Python 语言的核心知识展开,虽以 Python 3 为主,但绝大多数概念同样适用于 Python 2.x(注意差异章节)。本节做整体回顾,并给出进一步学习路线。
核心知识回顾
# 基础
- 语法: 缩进、注释、变量、类型
- 数据类型: int/float/str/bool
- 容器: list/tuple/dict/set
- 运算: 算术/比较/逻辑/位
# 流程
- 条件: if/elif/else, 三元表达式
- 循环: for/while, break/continue/else
- 推导式: 列表/字典/集合
# 函数与模块
- 函数: 参数/返回值/作用域/lambda
- 装饰器/生成器/闭包
- 模块/包/标准库
# 数据处理
- 字符串/列表/字典操作
- 文件 I/O/pathlib
- JSON/XML/正则
# 进阶
- 面向对象: 类/继承/多态/魔术方法
- 异常处理: try/except/finally
- 多线程/多进程
- 网络: SMTP/CGI/HTTP
# 应用
- 数据库: pymysql/SQLAlchemy
- GUI: Tkinter
- IDE 与调试工具
实战能力清单
# 学完本教程,你应该能:
# 1. 写脚本处理文件与数据
# 2. 写爬虫抓取网页信息
# 3. 操作数据库(增删改查)
# 4. 写自动化脚本(批处理/定时)
# 5. 开发简单 GUI 工具
# 6. 用 JSON/XML 做数据交换
# 7. 处理并发任务(线程池)
# 8. 面向对象设计程序结构
# 9. 异常处理保证健壮性
# 10. 用正则处理文本
# 自测项目:
# - 命令行待办工具(文件存储)
# - 网页爬虫(requests + 解析)
# - 数据分析脚本(pandas 可选)
# - 桌面小工具(Tkinter)
# - 邮件自动发送脚本
学习路线进阶
# 方向1: Web 开发
# Flask → FastAPI → Django
# HTML/CSS/JS 基础
# 方向2: 数据分析
# NumPy → Pandas → Matplotlib
# 统计学基础
# 方向3: 人工智能
# 数学基础(线性代数/微积分)
# scikit-learn → PyTorch/TensorFlow
# 机器学习/深度学习
# 方向4: 自动化与运维
# 脚本/爬虫/自动化测试
# 服务器/容器(Docker)
# 方向5: 面试准备
# 算法(LeetCode)
# 数据结构
# 项目实战(简历)
资源推荐
# 官方文档(第一手资料)
# https://docs.python.org
# 中文教程
# 菜鸟教程(runoob.com)
# 廖雪峰 Python 教程
# 进阶
# Python Cookbook(进阶技巧)
# Fluent Python(流畅的 Python)
# 实践平台
# LeetCode / 牛客网
# GitHub(阅读优秀源码)
# PyPI(探索第三方库)
学习建议
# 1. 动手>阅读: 每章代码自己敲
# 2. 项目驱动: 边做项目边学
# 3. 坚持练习: 每天写点代码
# 4. 善用搜索: 错误信息/问题定位
# 5. 阅读源码: 学习优秀代码风格
# 6. 参与社区: Stack Overflow/GitHub
# 7. 记录总结: 博客/笔记沉淀知识
# 编程学习曲线:
# 入门(语法) → 熟练(套路) → 精通(设计)
# 每个阶段都需要大量实践支撑
Python 是通往"自动化与 AI"的钥匙。本教程为你打下了坚实基础,接下来选择一个方向深耕,在实践中不断成长。祝你编码愉快!