Python 是一门语法简洁、生态丰富、应用范围广泛的编程语言。它既适合初学者学习编程,也被大量应用于 Web 开发、数据分析、人工智能、自动化运维、网络爬虫、测试开发和科学计算等领域。
本文以现代 Python 3 为基础,从运行环境、核心语法、函数、面向对象、异常处理、文件操作,一直讲到虚拟环境、测试、并发和项目结构,帮助你建立一套完整的 Python 知识体系。
1. Python 是什么
Python 是一种通用型高级编程语言,强调代码的可读性和开发效率。
所谓"通用型",是指 Python 并不局限于某一种开发场景。它可以用来编写网站后端、自动化脚本、数据分析程序、机器学习模型、桌面工具和测试程序。
需要区分两个概念:
- Python:编程语言及其语法规范。
- CPython:最常用的 Python 解释器实现,主要使用 C 语言编写。
我们平时从 Python 官网下载安装的版本,通常就是 CPython。
Python 程序运行时,源代码通常会先被编译成字节码,再由 Python 虚拟机执行。因此,把 Python 简单理解成"解释型语言"没有问题,但它的实际运行过程并不是逐字符直接解释。
一个最简单的 Python 程序如下:
python
print("Hello, Python!")
与很多编程语言相比,Python 不需要编写复杂的入口类和类型声明,非常适合快速实现想法。
2. Python 的特点
2.1 语法简洁
Python 使用缩进表示代码块,不需要使用大括号。
python
age = 20
if age >= 18:
print("已成年")
else:
print("未成年")
2.2 可读性较高
Python 代码通常接近自然语言:
python
users = ["Alice", "Bob", "Charlie"]
for user in users:
print(user)
2.3 动态类型
定义变量时不需要显式声明类型:
python
value = 100
value = "Python"
变量本身没有固定类型,它只是引用某个对象。
不过,Python 仍然属于强类型语言。不同类型之间不会总是自动转换:
python
age = 18
# TypeError:字符串不能直接和整数相加
message = "年龄:" + age
应该显式转换:
python
message = "年龄:" + str(age)
或者使用格式化字符串:
python
message = f"年龄:{age}"
2.4 跨平台
大多数 Python 程序可以运行在 Windows、Linux 和 macOS 上。
但涉及以下内容时,仍然需要处理平台差异:
- 文件路径
- Shell 命令
- 文件权限
- 系统服务
- 操作系统专有接口
推荐使用 pathlib 处理文件路径,减少平台差异。
2.5 标准库丰富
Python 自带大量标准库,可以处理:
- 文件与目录
- 日期和时间
- JSON、CSV
- 正则表达式
- 数据压缩
- 网络请求基础能力
- 并发编程
- 日志记录
- 单元测试
- SQLite 数据库
这也是 Python 常被称为"自带电池"的原因。
2.6 第三方生态丰富
Python Package Index,也就是 PyPI,提供了大量第三方包,例如:
requests:HTTP 请求fastapi:Web APIdjango:Web 应用开发numpy:数值计算pandas:数据处理matplotlib:数据可视化scikit-learn:机器学习pytorch:深度学习pytest:自动化测试
2.7 Python 的不足
Python 也不是所有场景下的最佳选择。
主要不足包括:
- 在纯计算密集型任务中,普通 Python 代码的运行速度通常不如 C、C++、Rust 等编译型语言。
- 动态类型虽然提高了开发效率,但部分错误只能在运行时暴露。
- 不同项目之间容易出现依赖版本冲突,因此必须重视虚拟环境。
- Python 不是浏览器前端和原生移动端开发的主流语言。
- 将 Python 应用打包成完全独立的桌面程序时,体积和兼容性处理可能比较复杂。
在真实项目中,选择语言需要结合业务场景、团队能力、性能要求和部署环境,而不是只看语法是否简单。
3. Python 的应用领域
3.1 Web 开发
Python 可以用于开发网站后端和 API 服务。
常见框架包括:
- Django
- Flask
- FastAPI
适合开发:
- 内容管理系统
- 企业管理后台
- REST API
- 微服务
- 数据服务
- 人工智能接口服务
3.2 数据分析
Python 可以读取、清洗、转换和分析大量数据。
常用工具包括:
- NumPy
- Pandas
- Matplotlib
- Jupyter
- Polars
3.3 人工智能与机器学习
Python 是人工智能领域最常见的编程语言之一。
常见工具包括:
- Scikit-learn
- PyTorch
- TensorFlow
- Transformers
- OpenCV
3.4 自动化脚本
Python 很适合编写自动化程序,例如:
- 批量重命名文件
- 处理 Excel 和 CSV
- 定时生成报表
- 调用外部 API
- 自动发送通知
- 批量转换图片
- 检查服务器状态
3.5 网络爬虫
常用工具包括:
- Requests
- Beautiful Soup
- Scrapy
- Playwright
编写爬虫时,需要遵守目标网站的服务条款、访问频率限制、版权规则以及当地法律法规。
3.6 自动化测试
Python 可以用于:
- 接口测试
- Web UI 测试
- 单元测试
- 集成测试
- 性能测试脚本
- 测试数据构造
3.7 运维与云计算
Python 经常用于:
- 日志分析
- 服务巡检
- 配置管理
- 云资源管理
- CI/CD 脚本
- 容器和 Kubernetes 工具开发
4. 安装 Python 与运行第一个程序
4.1 下载 Python
可以从 Python 官网下载安装程序:
在 Windows 上安装时,建议勾选:
text
Add Python to PATH
4.2 检查安装结果
Windows PowerShell:
powershell
py --version
macOS 或 Linux:
bash
python3 --version
如果输出类似下面的内容,说明 Python 已经可以使用:
text
Python 3.x.x
4.3 进入交互式解释器
Windows:
powershell
py
macOS 或 Linux:
bash
python3
进入后可以直接执行 Python 代码:
python
>>> 1 + 2
3
>>> print("Hello")
Hello
退出解释器:
python
exit()
4.4 编写第一个 Python 文件
创建 hello.py:
python
name = input("请输入你的名字:")
print(f"你好,{name}!欢迎学习 Python。")
运行程序:
Windows:
powershell
py hello.py
macOS 或 Linux:
bash
python3 hello.py
4.5 Python 程序的入口
一个常见的 Python 文件结构如下:
python
def main():
print("程序开始运行")
if __name__ == "__main__":
main()
当文件被直接运行时,__name__ 的值是 "__main__",因此会调用 main()。
当这个文件被其他模块导入时,入口代码不会自动执行。
5. Python 的基本语法
5.1 使用缩进划分代码块
Python 通常使用四个空格缩进:
python
score = 90
if score >= 60:
print("考试通过")
print("可以进入下一阶段")
下面的写法会产生缩进错误:
python
if score >= 60:
print("考试通过")
同一个代码块中不要混用 Tab 和空格。
5.2 注释
单行注释使用 #:
python
# 计算商品总价
total = price * quantity
函数、类和模块说明通常使用文档字符串:
python
def add(a, b):
"""返回两个数的和。"""
return a + b
可以读取文档字符串:
python
print(add.__doc__)
5.3 一行只写一条语句
Python 虽然允许使用分号:
python
a = 1; b = 2
但通常不推荐这样写。
推荐写成:
python
a = 1
b = 2
5.4 命名规则
变量名可以包含:
- 字母
- 数字
- 下划线
但不能以数字开头。
python
user_name = "Alice"
user2 = "Bob"
不合法的变量名:
python
# 不能以数字开头
2user = "Alice"
常见命名习惯:
| 类型 | 命名方式 | 示例 |
|---|---|---|
| 变量 | 小写下划线 | user_name |
| 函数 | 小写下划线 | get_user() |
| 类 | 大驼峰 | UserService |
| 常量 | 大写下划线 | MAX_RETRY_COUNT |
| 内部属性 | 单下划线开头 | _cache |
6. 变量与数据类型
6.1 变量
Python 变量不需要提前声明:
python
name = "Python"
age = 30
price = 99.9
enabled = True
查看变量类型:
python
print(type(name))
print(type(age))
print(type(price))
print(type(enabled))
6.2 整数
python
count = 100
temperature = -5
binary_value = 0b1010
hex_value = 0xFF
Python 整数可以表示很大的数:
python
large_number = 10 ** 100
print(large_number)
6.3 浮点数
python
price = 19.99
ratio = 0.85
浮点数采用二进制表示,因此部分十进制小数无法被精确表示:
python
print(0.1 + 0.2)
结果可能是:
text
0.30000000000000004
涉及金额精确计算时,应考虑使用 Decimal:
python
from decimal import Decimal
result = Decimal("0.1") + Decimal("0.2")
print(result)
输出:
text
0.3
注意:构造 Decimal 时推荐传入字符串,而不是浮点数。
6.4 布尔值
python
is_admin = True
is_deleted = False
以下值通常会被视为假:
FalseNone00.0""[]{}set()
示例:
python
users = []
if not users:
print("用户列表为空")
6.5 字符串
python
name = "Python"
message = 'Hello'
description = """这是一个
可以换行的字符串"""
常见操作:
python
text = " Hello Python "
print(text.strip())
print(text.lower())
print(text.upper())
print(text.replace("Python", "World"))
print(text.startswith(" Hello"))
print("Python" in text)
字符串切片:
python
text = "Python"
print(text[0])
print(text[-1])
print(text[0:3])
print(text[::-1])
输出:
text
P
n
Pyt
nohtyP
格式化字符串:
python
name = "Alice"
age = 20
message = f"姓名:{name},年龄:{age}"
print(message)
格式化数字:
python
price = 1234.5678
print(f"{price:.2f}")
print(f"{price:,.2f}")
输出:
text
1234.57
1,234.57
6.6 空值 None
None 表示"没有值"或"值不存在"。
python
result = None
if result is None:
print("暂时没有结果")
判断 None 时推荐使用:
python
value is None
value is not None
不要写成:
python
value == None
6.7 类型转换
python
age_text = "18"
age = int(age_text)
price = float("19.99")
message = str(100)
numbers = list((1, 2, 3))
转换可能失败:
python
value = int("abc")
这会抛出 ValueError。
6.8 可变对象与不可变对象
常见不可变对象:
intfloatboolstrtuplefrozensetNone
常见可变对象:
listdictset
示例:
python
numbers = [1, 2, 3]
numbers.append(4)
print(numbers)
列表对象本身被修改了。
字符串不能原地修改:
python
text = "Python"
text = text + " 3"
这里创建了新的字符串对象,然后让 text 指向它。
7. 运算符
7.1 算术运算符
python
a = 10
b = 3
print(a + b)
print(a - b)
print(a * b)
print(a / b)
print(a // b)
print(a % b)
print(a ** b)
其中:
/:普通除法//:向下取整除法%:取余**:幂运算
7.2 比较运算符
python
print(10 > 5)
print(10 >= 10)
print(10 == 10)
print(10 != 5)
Python 支持连续比较:
python
age = 20
if 18 <= age <= 60:
print("年龄在指定范围内")
7.3 逻辑运算符
python
age = 20
has_permission = True
if age >= 18 and has_permission:
print("允许访问")
逻辑运算符包括:
andornot
7.4 成员运算符
python
roles = ["admin", "editor"]
print("admin" in roles)
print("guest" not in roles)
7.5 身份运算符
is 判断两个变量是否引用同一个对象:
python
a = []
b = a
c = []
print(a is b)
print(a is c)
print(a == c)
输出:
text
True
False
True
区别如下:
==:比较值是否相等。is:比较是否为同一个对象。
除 None、True、False 等单例判断外,普通值比较通常使用 ==。
7.6 赋值表达式
现代 Python 支持海象运算符 :=:
python
if (length := len("Python")) > 5:
print(f"字符串长度为 {length}")
它可以在表达式中完成赋值,但不应为了减少一行代码而过度使用。
8. 条件判断与循环
8.1 if 条件判断
python
score = 85
if score >= 90:
level = "优秀"
elif score >= 80:
level = "良好"
elif score >= 60:
level = "及格"
else:
level = "不及格"
print(level)
8.2 三元表达式
python
age = 20
status = "成年" if age >= 18 else "未成年"
print(status)
8.3 match 结构匹配
较新的 Python 3 版本支持 match:
python
command = "start"
match command:
case "start":
print("启动服务")
case "stop":
print("停止服务")
case "restart":
print("重启服务")
case _:
print("未知命令")
match 不只是简单的 switch,还支持结构解构:
python
point = (10, 20)
match point:
case (0, 0):
print("原点")
case (x, 0):
print(f"位于 X 轴:x={x}")
case (0, y):
print(f"位于 Y 轴:y={y}")
case (x, y):
print(f"普通坐标:x={x}, y={y}")
8.4 for 循环
python
names = ["Alice", "Bob", "Charlie"]
for name in names:
print(name)
配合 range():
python
for number in range(1, 6):
print(number)
输出范围是 1 到 5,不包含结束值 6。
8.5 enumerate
需要索引时,不要手动维护计数器:
python
names = ["Alice", "Bob", "Charlie"]
for index, name in enumerate(names, start=1):
print(index, name)
8.6 zip
同时遍历多个序列:
python
names = ["Alice", "Bob"]
scores = [90, 85]
for name, score in zip(names, scores):
print(f"{name}: {score}")
默认情况下,zip() 会在最短的序列结束时停止。
8.7 while 循环
python
count = 1
while count <= 5:
print(count)
count += 1
8.8 break、continue 与 pass
python
for number in range(1, 10):
if number == 3:
continue
if number == 8:
break
print(number)
continue:跳过本次循环剩余代码。break:结束整个循环。pass:什么也不做,作为语法占位符。
python
def future_feature():
pass
8.9 循环中的 else
当循环正常结束、没有被 break 中断时,会执行 else:
python
numbers = [1, 3, 5, 7]
target = 4
for number in numbers:
if number == target:
print("找到了")
break
else:
print("没有找到")
9. Python 常用数据结构
9.1 列表 list
列表有序、可变,可以保存重复元素:
python
users = ["Alice", "Bob", "Alice"]
常见操作:
python
users = ["Alice", "Bob"]
users.append("Charlie")
users.insert(1, "David")
users.remove("Bob")
last_user = users.pop()
print(users)
print(last_user)
切片:
python
numbers = [0, 1, 2, 3, 4, 5]
print(numbers[1:4])
print(numbers[:3])
print(numbers[::2])
print(numbers[::-1])
排序:
python
numbers = [5, 2, 9, 1]
numbers.sort()
print(numbers)
numbers.sort(reverse=True)
print(numbers)
sorted() 会返回新列表:
python
numbers = [5, 2, 9, 1]
new_numbers = sorted(numbers)
print(numbers)
print(new_numbers)
按字段排序:
python
users = [
{"name": "Alice", "age": 20},
{"name": "Bob", "age": 18},
]
users.sort(key=lambda user: user["age"])
print(users)
9.2 元组 tuple
元组有序,但不能修改:
python
point = (10, 20)
元组解包:
python
x, y = point
print(x)
print(y)
交换变量:
python
a = 10
b = 20
a, b = b, a
只有一个元素的元组必须带逗号:
python
value = (1,)
9.3 集合 set
集合无重复元素,适合去重和集合运算:
python
numbers = {1, 2, 2, 3}
print(numbers)
输出:
text
{1, 2, 3}
常见操作:
python
a = {1, 2, 3}
b = {3, 4, 5}
print(a | b)
print(a & b)
print(a - b)
print(a ^ b)
分别表示:
- 并集
- 交集
- 差集
- 对称差集
集合元素必须是可哈希对象,因此不能直接放入列表:
python
# TypeError
values = {[1, 2], [3, 4]}
9.4 字典 dict
字典以键值对保存数据:
python
user = {
"id": 1,
"name": "Alice",
"age": 20,
}
访问数据:
python
print(user["name"])
print(user.get("email"))
print(user.get("email", "未填写"))
区别如下:
user["email"]:键不存在时抛出KeyError。user.get("email"):键不存在时返回None或指定默认值。
遍历字典:
python
for key, value in user.items():
print(key, value)
修改和删除:
python
user["age"] = 21
user["email"] = "alice@example.com"
removed_age = user.pop("age")
合并字典:
python
base_config = {
"host": "localhost",
"port": 8000,
}
custom_config = {
"port": 9000,
"debug": True,
}
config = base_config | custom_config
print(config)
后面的字典会覆盖相同键。
9.5 如何选择数据结构
| 数据结构 | 是否有序 | 是否可变 | 是否允许重复 | 典型场景 |
|---|---|---|---|---|
list |
是 | 是 | 是 | 有序数据集合 |
tuple |
是 | 否 | 是 | 固定结构的数据 |
set |
不依赖位置 | 是 | 否 | 去重、集合运算 |
dict |
保留插入顺序 | 是 | 键不重复 | 键值映射 |
10. 函数
10.1 定义函数
python
def add(a, b):
return a + b
result = add(10, 20)
print(result)
10.2 默认参数
python
def greet(name, message="你好"):
return f"{message},{name}"
print(greet("Alice"))
print(greet("Bob", "早上好"))
10.3 关键字参数
python
def create_user(name, age, enabled=True):
return {
"name": name,
"age": age,
"enabled": enabled,
}
user = create_user(age=20, name="Alice")
关键字参数可以提高调用代码的可读性。
10.4 可变位置参数
python
def total(*numbers):
return sum(numbers)
print(total(1, 2, 3, 4))
numbers 在函数内部是一个元组。
10.5 可变关键字参数
python
def build_profile(**attributes):
return attributes
profile = build_profile(name="Alice", age=20, city="Shanghai")
print(profile)
attributes 在函数内部是一个字典。
10.6 参数解包
python
def add(a, b):
return a + b
numbers = [10, 20]
print(add(*numbers))
字典解包:
python
def create_user(name, age):
return {"name": name, "age": age}
data = {
"name": "Alice",
"age": 20,
}
user = create_user(**data)
10.7 仅限关键字参数
python
def connect(host, *, timeout=10, retry=3):
print(host, timeout, retry)
connect("localhost", timeout=5, retry=2)
* 后面的参数必须通过关键字传递。
10.8 函数也是对象
函数可以赋值给变量:
python
def greet(name):
return f"你好,{name}"
handler = greet
print(handler("Alice"))
也可以作为参数传递:
python
def execute(operation, a, b):
return operation(a, b)
def multiply(a, b):
return a * b
print(execute(multiply, 3, 4))
10.9 lambda 表达式
python
multiply = lambda a, b: a * b
print(multiply(3, 4))
lambda 适合表达简单的单行函数。逻辑复杂时应使用普通 def。
10.10 变量作用域
python
name = "全局变量"
def show_name():
name = "局部变量"
print(name)
show_name()
print(name)
Python 查找变量时大致遵循 LEGB 规则:
- Local:局部作用域
- Enclosing:外层函数作用域
- Global:模块全局作用域
- Built-in:内置作用域
10.11 不要使用可变对象作为默认参数
错误示例:
python
def add_item(item, items=[]):
items.append(item)
return items
默认参数在函数定义时创建一次,多次调用会共享同一个列表。
正确写法:
python
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
11. 模块与包
11.1 模块
每个 .py 文件都可以作为一个模块。
创建 calculator.py:
python
def add(a, b):
return a + b
def subtract(a, b):
return a - b
在另一个文件中使用:
python
import calculator
print(calculator.add(10, 20))
也可以只导入某个函数:
python
from calculator import add
print(add(10, 20))
还可以设置别名:
python
import calculator as calc
print(calc.add(10, 20))
不要使用通配符导入:
python
from calculator import *
因为它会让代码中名称的来源变得不清晰。
11.2 包
包可以理解为用于组织多个模块的目录。
text
my_project/
├── main.py
└── app/
├── __init__.py
├── services.py
└── utils.py
导入包中的模块:
python
from app.services import create_user
虽然现代 Python 支持命名空间包,但初学阶段保留 __init__.py 更直观。
11.3 __name__ 的作用
假设 calculator.py 内容如下:
python
def add(a, b):
return a + b
if __name__ == "__main__":
print(add(10, 20))
直接运行时:
bash
python calculator.py
测试代码会执行。
被其他文件导入时:
python
from calculator import add
测试代码不会执行。
12. 面向对象编程
12.1 类和对象
python
class User:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
return f"我叫 {self.name},今年 {self.age} 岁"
user = User("Alice", 20)
print(user.name)
print(user.introduce())
其中:
User是类。user是对象。__init__用于初始化对象。self表示当前对象。
12.2 实例属性与类属性
python
class User:
species = "Human"
def __init__(self, name):
self.name = name
alice = User("Alice")
bob = User("Bob")
print(alice.species)
print(bob.species)
species是类属性。name是实例属性。
12.3 实例方法、类方法和静态方法
python
class User:
count = 0
def __init__(self, name):
self.name = name
User.count += 1
def introduce(self):
return f"我是 {self.name}"
@classmethod
def get_count(cls):
return cls.count
@staticmethod
def validate_name(name):
return bool(name and name.strip())
调用:
python
user = User("Alice")
print(user.introduce())
print(User.get_count())
print(User.validate_name("Bob"))
12.4 封装与属性控制
Python 没有和部分语言完全相同的强制私有机制。
单下划线表示内部使用约定:
python
class Account:
def __init__(self, balance):
self._balance = balance
可以使用 property 控制属性访问:
python
class Account:
def __init__(self, balance):
self._balance = balance
@property
def balance(self):
return self._balance
@balance.setter
def balance(self, value):
if value < 0:
raise ValueError("余额不能小于 0")
self._balance = value
使用方式:
python
account = Account(100)
account.balance = 200
print(account.balance)
12.5 继承
python
class Animal:
def speak(self):
raise NotImplementedError
class Dog(Animal):
def speak(self):
return "汪"
class Cat(Animal):
def speak(self):
return "喵"
多态调用:
python
animals = [Dog(), Cat()]
for animal in animals:
print(animal.speak())
12.6 组合优于过度继承
如果一个对象只是"使用"另一个对象,而不是"属于"另一个对象,通常更适合使用组合。
python
class EmailSender:
def send(self, message):
print(f"发送邮件:{message}")
class UserService:
def __init__(self, email_sender):
self.email_sender = email_sender
def register(self, name):
print(f"注册用户:{name}")
self.email_sender.send("注册成功")
组合可以降低类之间的耦合,使测试和替换实现更加容易。
12.7 魔术方法
Python 中以双下划线开头和结尾的方法通常称为特殊方法或魔术方法。
python
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __str__(self):
return f"{self.name}:{self.price:.2f} 元"
def __eq__(self, other):
if not isinstance(other, Product):
return NotImplemented
return self.name == other.name and self.price == other.price
使用:
python
product = Product("键盘", 299)
print(product)
13. 异常处理
13.1 捕获异常
python
try:
number = int(input("请输入一个整数:"))
result = 100 / number
print(result)
except ValueError:
print("输入内容不是有效整数")
except ZeroDivisionError:
print("除数不能为 0")
13.2 获取异常信息
python
try:
value = int("abc")
except ValueError as error:
print(f"转换失败:{error}")
13.3 else 与 finally
python
try:
number = int("10")
except ValueError:
print("转换失败")
else:
print(f"转换成功:{number}")
finally:
print("无论是否出现异常都会执行")
else:没有异常时执行。finally:无论是否有异常都会执行。
13.4 主动抛出异常
python
def withdraw(balance, amount):
if amount <= 0:
raise ValueError("提现金额必须大于 0")
if amount > balance:
raise ValueError("余额不足")
return balance - amount
13.5 自定义异常
python
class InsufficientBalanceError(Exception):
"""余额不足异常。"""
def withdraw(balance, amount):
if amount > balance:
raise InsufficientBalanceError(
f"余额不足:余额={balance},提现金额={amount}"
)
return balance - amount
13.6 异常处理原则
- 只捕获能够处理的异常。
- 尽量捕获具体异常类型。
- 不要使用空的
except隐藏错误。 - 记录足够的上下文信息。
- 不要把正常业务分支全部设计成异常。
- 在系统边界统一转换或记录未处理异常。
不推荐:
python
try:
run_task()
except:
pass
这种写法会隐藏真实错误,包括程序中断信号和系统级异常。
14. 文件与数据读写
14.1 使用 with 打开文件
python
with open("example.txt", "w", encoding="utf-8") as file:
file.write("Hello, Python!\n")
读取文件:
python
with open("example.txt", "r", encoding="utf-8") as file:
content = file.read()
print(content)
with 结束后会自动关闭文件,即使执行过程中发生异常。
14.2 逐行读取
python
with open("example.txt", "r", encoding="utf-8") as file:
for line in file:
print(line.rstrip())
处理大文件时,逐行读取通常比一次性调用 read() 更节省内存。
14.3 使用 pathlib
python
from pathlib import Path
file_path = Path("data") / "users.txt"
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_text("Alice\nBob\n", encoding="utf-8")
content = file_path.read_text(encoding="utf-8")
print(content)
常见操作:
python
from pathlib import Path
path = Path("data/users.txt")
print(path.exists())
print(path.name)
print(path.stem)
print(path.suffix)
print(path.parent)
print(path.resolve())
遍历目录:
python
from pathlib import Path
for file_path in Path(".").glob("*.py"):
print(file_path)
递归遍历:
python
for file_path in Path(".").rglob("*.py"):
print(file_path)
14.4 JSON 数据
写入 JSON:
python
import json
from pathlib import Path
user = {
"name": "Alice",
"age": 20,
"skills": ["Python", "SQL"],
}
Path("user.json").write_text(
json.dumps(user, ensure_ascii=False, indent=2),
encoding="utf-8",
)
读取 JSON:
python
import json
from pathlib import Path
content = Path("user.json").read_text(encoding="utf-8")
user = json.loads(content)
print(user["name"])
14.5 CSV 数据
写入 CSV:
python
import csv
users = [
{"name": "Alice", "age": 20},
{"name": "Bob", "age": 22},
]
with open("users.csv", "w", newline="", encoding="utf-8-sig") as file:
writer = csv.DictWriter(file, fieldnames=["name", "age"])
writer.writeheader()
writer.writerows(users)
读取 CSV:
python
import csv
with open("users.csv", "r", newline="", encoding="utf-8-sig") as file:
reader = csv.DictReader(file)
for row in reader:
print(row)
utf-8-sig 在需要使用部分 Windows 表格软件直接打开 CSV 时可能更方便;普通文本文件通常使用 utf-8 即可。
15. 推导式、迭代器与生成器
15.1 列表推导式
普通写法:
python
squares = []
for number in range(1, 6):
squares.append(number ** 2)
列表推导式:
python
squares = [number ** 2 for number in range(1, 6)]
带条件:
python
even_squares = [
number ** 2
for number in range(1, 11)
if number % 2 == 0
]
推导式适合简单的数据转换。如果嵌套层级太多,应改为普通循环。
15.2 字典推导式
python
names = ["Alice", "Bob", "Charlie"]
name_lengths = {
name: len(name)
for name in names
}
15.3 集合推导式
python
values = [1, 2, 2, 3, 3, 4]
squares = {value ** 2 for value in values}
15.4 可迭代对象与迭代器
列表是可迭代对象:
python
numbers = [1, 2, 3]
iterator = iter(numbers)
print(next(iterator))
print(next(iterator))
print(next(iterator))
继续调用 next() 会抛出 StopIteration。
for 循环会在内部自动完成迭代器创建和异常处理。
15.5 生成器
生成器通过 yield 按需产生数据:
python
def count_up_to(limit):
current = 1
while current <= limit:
yield current
current += 1
for number in count_up_to(5):
print(number)
生成器不会一次性把所有结果放入内存,适合处理:
- 大文件
- 大量数据
- 数据流
- 分批查询结果
- 无限序列
生成器表达式:
python
squares = (number ** 2 for number in range(1, 1000000))
print(next(squares))
print(next(squares))
注意:生成器通常只能被完整消费一次。
16. 装饰器
装饰器用于在不直接修改原函数主体的情况下,为函数添加额外行为。
16.1 基本装饰器
python
from functools import wraps
def log_call(function):
@wraps(function)
def wrapper(*args, **kwargs):
print(f"开始调用:{function.__name__}")
result = function(*args, **kwargs)
print(f"调用结束:{function.__name__}")
return result
return wrapper
@log_call
def add(a, b):
return a + b
print(add(10, 20))
@wraps(function) 可以保留原函数的名称、文档字符串等元数据。
16.2 带参数的装饰器
python
from functools import wraps
def retry(max_attempts):
def decorator(function):
@wraps(function)
def wrapper(*args, **kwargs):
last_error = None
for attempt in range(1, max_attempts + 1):
try:
return function(*args, **kwargs)
except RuntimeError as error:
last_error = error
print(f"第 {attempt} 次执行失败:{error}")
raise last_error
return wrapper
return decorator
使用:
python
@retry(max_attempts=3)
def unstable_task():
raise RuntimeError("服务暂时不可用")
实际项目中的重试还应考虑:
- 只重试可恢复异常
- 指数退避
- 最大等待时间
- 幂等性
- 超时控制
- 日志与监控
17. 类型标注与数据类
17.1 类型标注
python
def add(a: int, b: int) -> int:
return a + b
集合类型:
python
def average(values: list[float]) -> float:
if not values:
raise ValueError("数据不能为空")
return sum(values) / len(values)
可为空类型:
python
def find_user(user_id: int) -> dict[str, object] | None:
if user_id == 1:
return {
"id": 1,
"name": "Alice",
}
return None
X | None 语法适用于较新的 Python 3 版本;维护旧版本项目时,可以使用 Optional[X]。
需要特别注意:类型标注通常不会在运行时自动阻止错误类型传入。它主要供 IDE、静态类型检查器、代码审查和文档工具使用。Python 官方 typing 文档
17.2 类型别名
python
UserId = int
UserData = dict[str, object]
def find_user(user_id: UserId) -> UserData | None:
return None
17.3 dataclass
如果一个类主要用于保存数据,可以使用 dataclass:
python
from dataclasses import dataclass, field
@dataclass
class User:
id: int
name: str
skills: list[str] = field(default_factory=list)
user = User(
id=1,
name="Alice",
skills=["Python", "SQL"],
)
print(user)
不要直接把可变列表作为默认值。应使用:
python
field(default_factory=list)
数据类会自动生成常用方法,例如:
__init____repr____eq__
18. 虚拟环境与依赖管理
18.1 为什么需要虚拟环境
假设项目 A 依赖某个库的 1.x 版本,项目 B 依赖同一个库的 2.x 版本。如果把所有依赖都安装到全局 Python 环境中,就容易产生版本冲突。
虚拟环境可以让每个项目拥有独立的:
- Python 执行环境
- 第三方依赖
- 命令行工具
虚拟环境通常命名为 .venv,不应该提交到 Git,并且应当能够根据依赖清单重新创建。Python venv 官方文档
18.2 Windows 创建虚拟环境
powershell
py -m venv .venv
PowerShell 激活:
powershell
.\.venv\Scripts\Activate.ps1
如果由于 PowerShell 执行策略不能运行激活脚本,也可以直接使用虚拟环境中的解释器:
powershell
.\.venv\Scripts\python.exe main.py
退出虚拟环境:
powershell
deactivate
18.3 macOS 或 Linux 创建虚拟环境
bash
python3 -m venv .venv
source .venv/bin/activate
退出:
bash
deactivate
18.4 安装第三方包
激活虚拟环境后:
bash
python -m pip install requests
推荐使用:
bash
python -m pip
而不是直接使用:
bash
pip
这样更容易确保 pip 对应的就是当前使用的 Python 解释器。
查看已安装依赖:
bash
python -m pip list
查看包信息:
bash
python -m pip show requests
卸载:
bash
python -m pip uninstall requests
18.5 requirements.txt
导出当前环境中的依赖:
bash
python -m pip freeze > requirements.txt
根据依赖文件安装:
bash
python -m pip install -r requirements.txt
对于应用项目,应根据团队规范锁定可复现的依赖版本。对于准备发布给其他项目使用的库,则不宜盲目把所有间接依赖都固定成当前环境版本。
18.6 pyproject.toml
现代 Python 项目通常使用 pyproject.toml 保存项目元数据和构建配置。
一个简化示例:
toml
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"
[project]
name = "example-project"
version = "0.1.0"
description = "一个 Python 示例项目"
requires-python = ">=3.10"
dependencies = [
"requests>=2,<3"
]
安装当前项目:
bash
python -m pip install .
开发阶段可以使用可编辑安装:
bash
python -m pip install -e .
关于包安装、虚拟环境和依赖文件的完整说明,可以参考 Python Packaging User Guide。
19. 常用标准库
19.1 datetime
python
from datetime import datetime, timedelta
now = datetime.now()
tomorrow = now + timedelta(days=1)
print(now)
print(tomorrow)
print(now.strftime("%Y-%m-%d %H:%M:%S"))
解析时间:
python
text = "2026-08-21 12:30:00"
value = datetime.strptime(text, "%Y-%m-%d %H:%M:%S")
涉及跨时区系统时,应明确时区,不要依赖服务器默认时区。
19.2 collections
统计次数:
python
from collections import Counter
words = ["Python", "Java", "Python", "Go"]
counter = Counter(words)
print(counter)
print(counter.most_common(2))
提供默认值的字典:
python
from collections import defaultdict
groups = defaultdict(list)
groups["backend"].append("Alice")
groups["backend"].append("Bob")
19.3 itertools
python
from itertools import chain
first = [1, 2]
second = [3, 4]
for value in chain(first, second):
print(value)
19.4 functools
缓存函数结果:
python
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(number):
if number < 2:
return number
return fibonacci(number - 1) + fibonacci(number - 2)
print(fibonacci(30))
缓存适用于相同输入必然得到相同输出的函数。不要随意缓存依赖实时外部状态的结果。
19.5 re
python
import re
text = "联系电话:13812345678"
match = re.search(r"1\d{10}", text)
if match:
print(match.group())
复杂文本解析不应全部依赖正则表达式。处理 HTML、JSON、XML 等结构化内容时,应优先使用专用解析器。
19.6 os 与环境变量
python
import os
database_url = os.getenv("DATABASE_URL")
if database_url is None:
raise RuntimeError("缺少 DATABASE_URL 环境变量")
密码、密钥和令牌不应直接写入源代码或提交到 Git。
19.7 argparse
python
import argparse
parser = argparse.ArgumentParser(description="用户问候程序")
parser.add_argument("name", help="用户姓名")
parser.add_argument("--age", type=int, help="用户年龄")
args = parser.parse_args()
print(f"你好,{args.name}")
运行:
bash
python main.py Alice --age 20
20. 测试、日志与调试
20.1 使用 assert
python
def add(a, b):
return a + b
assert add(1, 2) == 3
assert 适合开发阶段验证内部假设,但不应代替正式的输入校验和业务异常,因为优化模式下断言可能被关闭。
20.2 unittest
业务代码 calculator.py:
python
def divide(a, b):
if b == 0:
raise ValueError("除数不能为 0")
return a / b
测试代码 test_calculator.py:
python
import unittest
from calculator import divide
class CalculatorTest(unittest.TestCase):
def test_divide(self):
self.assertEqual(5, divide(10, 2))
def test_divide_by_zero(self):
with self.assertRaises(ValueError):
divide(10, 0)
if __name__ == "__main__":
unittest.main()
运行:
bash
python -m unittest
20.3 pytest
pytest 是常用的第三方测试框架。
安装:
bash
python -m pip install pytest
示例:
python
import pytest
from calculator import divide
def test_divide():
assert divide(10, 2) == 5
def test_divide_by_zero():
with pytest.raises(ValueError):
divide(10, 0)
运行:
bash
python -m pytest
20.4 logging
不要在生产项目中全部依赖 print() 输出日志。
python
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s %(message)s",
)
logger = logging.getLogger(__name__)
def create_user(name):
logger.info("开始创建用户,name=%s", name)
try:
if not name:
raise ValueError("用户名不能为空")
logger.info("用户创建成功,name=%s", name)
except ValueError:
logger.exception("用户创建失败")
raise
日志中应避免记录:
- 密码
- 完整令牌
- 银行卡信息
- 身份证完整号码
- 未脱敏的个人隐私数据
20.5 调试
最简单的断点方式:
python
breakpoint()
程序执行到这里时会进入调试器。
常用命令包括:
text
n 执行下一行
s 进入函数
c 继续运行
p name 查看变量
q 退出调试
实际开发中还可以使用 IDE 图形化调试器。
21. Python 并发编程
Python 常见并发方式包括:
| 方式 | 常见适用场景 |
|---|---|
threading |
阻塞式 I/O、已有同步库 |
multiprocessing |
CPU 密集型计算、进程隔离 |
asyncio |
大量并发网络 I/O |
| 任务队列 | 跨进程、跨机器的后台任务 |
这只是常见工程判断,不是绝对规则。最终方案还要结合第三方库是否释放解释器锁、任务规模、数据传输成本和部署方式。
21.1 多线程
python
from concurrent.futures import ThreadPoolExecutor
from time import sleep
def download(task_id):
sleep(1)
return f"任务 {task_id} 完成"
with ThreadPoolExecutor(max_workers=4) as executor:
results = executor.map(download, range(1, 6))
for result in results:
print(result)
21.2 多进程
python
from concurrent.futures import ProcessPoolExecutor
def calculate(number):
return sum(value * value for value in range(number))
if __name__ == "__main__":
with ProcessPoolExecutor() as executor:
results = executor.map(
calculate,
[1000000, 1200000, 1400000],
)
print(list(results))
Windows 使用多进程时,应特别注意:
python
if __name__ == "__main__":
21.3 asyncio
python
import asyncio
async def fetch(task_id):
print(f"开始任务:{task_id}")
await asyncio.sleep(1)
print(f"完成任务:{task_id}")
return task_id
async def main():
results = await asyncio.gather(
fetch(1),
fetch(2),
fetch(3),
)
print(results)
if __name__ == "__main__":
asyncio.run(main())
需要注意:
async不会自动让所有代码变快。- 异步函数中执行长时间阻塞操作,会阻塞事件循环。
- 使用异步框架时,应选择异步数据库和异步 HTTP 客户端。
- CPU 密集型计算通常不应直接运行在事件循环中。
22. Python 项目结构
一个中小型项目可以采用以下结构:
text
example_project/
├── pyproject.toml
├── README.md
├── .gitignore
├── src/
│ └── example_project/
│ ├── __init__.py
│ ├── main.py
│ ├── models.py
│ ├── services.py
│ └── repositories.py
└── tests/
├── __init__.py
└── test_services.py
各目录职责:
src/:业务源代码。tests/:测试代码。pyproject.toml:项目和构建配置。README.md:项目说明。.gitignore:不需要提交的文件。
常见 .gitignore:
gitignore
__pycache__/
*.py[cod]
.venv/
.pytest_cache/
.mypy_cache/
.ruff_cache/
.coverage
htmlcov/
build/
dist/
*.egg-info/
.env
不要提交:
- 虚拟环境
- 缓存文件
- 本地密钥
- 数据库密码
- API Token
- IDE 临时文件
- 构建产物
22.1 分层建议
对于业务项目,可以按照职责拆分:
text
接口层
↓
服务层
↓
数据访问层
↓
数据库或外部服务
例如:
python
class UserRepository:
def find_by_id(self, user_id):
return {
"id": user_id,
"name": "Alice",
}
class UserService:
def __init__(self, repository):
self.repository = repository
def get_user(self, user_id):
if user_id <= 0:
raise ValueError("用户 ID 必须大于 0")
return self.repository.find_by_id(user_id)
清晰的职责边界通常比"文件越多越专业"更重要。小项目不需要过早设计复杂架构。
23. 综合实战:命令行待办事项程序
下面使用标准库实现一个简单的待办事项程序,支持:
- 添加任务
- 查看任务
- 完成任务
- 删除任务
- 使用 JSON 保存数据
创建 todo.py:
python
import argparse
import json
from pathlib import Path
DATA_FILE = Path("tasks.json")
def load_tasks():
if not DATA_FILE.exists():
return []
try:
content = DATA_FILE.read_text(encoding="utf-8")
data = json.loads(content)
except json.JSONDecodeError as error:
raise RuntimeError(
f"任务文件格式错误:{DATA_FILE}"
) from error
if not isinstance(data, list):
raise RuntimeError("任务文件的顶层数据必须是列表")
return data
def save_tasks(tasks):
content = json.dumps(
tasks,
ensure_ascii=False,
indent=2,
)
DATA_FILE.write_text(content, encoding="utf-8")
def add_task(title):
title = title.strip()
if not title:
raise ValueError("任务标题不能为空")
tasks = load_tasks()
next_id = max(
(task["id"] for task in tasks),
default=0,
) + 1
task = {
"id": next_id,
"title": title,
"completed": False,
}
tasks.append(task)
save_tasks(tasks)
print(f"任务添加成功:[{next_id}] {title}")
def list_tasks():
tasks = load_tasks()
if not tasks:
print("暂无任务")
return
for task in tasks:
status = "√" if task["completed"] else " "
print(f"[{status}] {task['id']}: {task['title']}")
def complete_task(task_id):
tasks = load_tasks()
for task in tasks:
if task["id"] == task_id:
task["completed"] = True
save_tasks(tasks)
print(f"任务已完成:{task_id}")
return
raise ValueError(f"任务不存在:{task_id}")
def delete_task(task_id):
tasks = load_tasks()
remaining_tasks = [
task
for task in tasks
if task["id"] != task_id
]
if len(remaining_tasks) == len(tasks):
raise ValueError(f"任务不存在:{task_id}")
save_tasks(remaining_tasks)
print(f"任务已删除:{task_id}")
def create_parser():
parser = argparse.ArgumentParser(
description="命令行待办事项程序"
)
subparsers = parser.add_subparsers(
dest="command",
required=True,
)
add_parser = subparsers.add_parser(
"add",
help="添加任务",
)
add_parser.add_argument("title", help="任务标题")
subparsers.add_parser(
"list",
help="查看任务",
)
complete_parser = subparsers.add_parser(
"complete",
help="完成任务",
)
complete_parser.add_argument(
"task_id",
type=int,
help="任务 ID",
)
delete_parser = subparsers.add_parser(
"delete",
help="删除任务",
)
delete_parser.add_argument(
"task_id",
type=int,
help="任务 ID",
)
return parser
def main():
parser = create_parser()
args = parser.parse_args()
try:
if args.command == "add":
add_task(args.title)
elif args.command == "list":
list_tasks()
elif args.command == "complete":
complete_task(args.task_id)
elif args.command == "delete":
delete_task(args.task_id)
except (ValueError, RuntimeError) as error:
parser.error(str(error))
if __name__ == "__main__":
main()
添加任务:
bash
python todo.py add "学习 Python"
python todo.py add "编写一个命令行程序"
查看任务:
bash
python todo.py list
完成任务:
bash
python todo.py complete 1
删除任务:
bash
python todo.py delete 2
这个程序虽然简单,但已经包含了不少实际开发知识:
- 函数拆分
- 命令行参数
- JSON 序列化
- 文件读写
- 输入校验
- 异常处理
- 列表推导式
- 程序入口
后续可以继续扩展:
- 增加任务创建时间。
- 增加任务优先级。
- 增加任务截止日期。
- 使用 SQLite 保存数据。
- 为每个函数编写测试。
- 把程序打包成可安装的命令行工具。
- 使用 FastAPI 提供 Web API。
- 增加 Web 或桌面图形界面。
24. 常见问题与易错点
24.1 is 和 == 混用
错误:
python
if value is 100:
print("等于 100")
正确:
python
if value == 100:
print("等于 100")
判断 None 时使用:
python
if value is None:
print("没有值")
24.2 修改正在遍历的列表
不推荐:
python
numbers = [1, 2, 3, 4]
for number in numbers:
if number % 2 == 0:
numbers.remove(number)
推荐创建新列表:
python
numbers = [
number
for number in numbers
if number % 2 != 0
]
24.3 列表引用共享
python
a = [1, 2, 3]
b = a
b.append(4)
print(a)
输出:
text
[1, 2, 3, 4]
因为 a 和 b 引用了同一个列表。
创建浅拷贝:
python
b = a.copy()
嵌套对象需要根据实际情况考虑深拷贝:
python
from copy import deepcopy
b = deepcopy(a)
深拷贝不是默认最佳方案。很多时候,重新设计数据流或使用不可变对象更清晰。
24.4 二维列表初始化错误
错误:
python
matrix = [[0] * 3] * 3
matrix[0][0] = 1
print(matrix)
三行引用了同一个内部列表。
正确:
python
matrix = [
[0] * 3
for _ in range(3)
]
24.5 浮点数不能直接用于精确金额判断
不推荐:
python
total = 0.1 + 0.2
if total == 0.3:
print("相等")
可以使用误差比较:
python
import math
print(math.isclose(0.1 + 0.2, 0.3))
金额计算可根据业务精度要求使用 Decimal。
24.6 捕获过于宽泛的异常
不推荐:
python
try:
process()
except Exception:
print("执行失败")
如果确实需要在程序最外层统一捕获,应记录完整异常堆栈:
python
import logging
logger = logging.getLogger(__name__)
try:
process()
except Exception:
logger.exception("程序执行失败")
raise
24.7 在全局环境安装所有依赖
不推荐直接把不同项目依赖全部安装到系统 Python。
每个项目应该创建独立虚拟环境:
bash
python -m venv .venv
24.8 使用字符串拼接文件路径
不推荐:
python
file_path = directory + "/" + file_name
推荐:
python
from pathlib import Path
file_path = Path(directory) / file_name
24.9 把密钥写在代码中
错误:
python
API_KEY = "真实密钥"
更合理的方式是从环境变量读取:
python
import os
api_key = os.getenv("API_KEY")
if not api_key:
raise RuntimeError("缺少 API_KEY")
24.10 过早优化
优化代码前应先确认真正的性能瓶颈。
可以使用:
bash
python -m cProfile main.py
基本原则:
- 先保证代码正确。
- 再编写测试。
- 使用数据定位瓶颈。
- 优化最耗时的部分。
- 优化后重新验证正确性和性能。
25. Python 学习路线
25.1 第一阶段:语言基础
学习内容:
- 变量和数据类型
- 字符串
- 列表、元组、集合、字典
- 条件判断
- 循环
- 函数
- 文件读写
- 异常处理
练习项目:
- 猜数字游戏
- 通讯录
- 文本词频统计
- 文件批量重命名
- 命令行记账程序
25.2 第二阶段:编程能力
学习内容:
- 模块和包
- 面向对象
- 迭代器和生成器
- 装饰器
- 类型标注
- 标准库
- 单元测试
- 日志
- Git
练习项目:
- 待办事项程序
- 日志分析器
- CSV 数据处理器
- API 数据同步工具
- 简单爬虫
25.3 第三阶段:工程化
学习内容:
- 虚拟环境
- 依赖管理
pyproject.toml- 项目分层
- 配置管理
- 测试覆盖
- 静态检查
- 自动格式化
- CI/CD
- Docker
常见工程工具:
pytestruffmypyblackpre-commit
工具不是越多越好。应先建立代码规范、测试策略和明确的交付要求,再选择合适的工具。
25.4 第四阶段:选择方向
Web 开发
建议学习:
- HTTP
- FastAPI、Flask 或 Django
- SQL
- PostgreSQL 或 MySQL
- Redis
- 身份认证
- Docker
- API 设计
数据分析
建议学习:
- NumPy
- Pandas 或 Polars
- Matplotlib
- Jupyter
- SQL
- 统计学基础
人工智能
建议学习:
- NumPy
- Pandas
- 线性代数
- 概率统计
- Scikit-learn
- PyTorch
- 模型评估
- 数据处理
自动化测试
建议学习:
- Pytest
- Requests
- Playwright
- 接口测试
- Mock
- 测试报告
- CI/CD
运维与自动化
建议学习:
- Linux
- Shell
- 网络基础
- 日志处理
- Docker
- Kubernetes
- 云平台 SDK
- 监控与告警
26. 总结
Python 的核心优势是语法简洁、开发效率高、标准库丰富、第三方生态完善。它既可以作为学习编程的第一门语言,也能够承担真实的生产项目。
学习 Python 时,不应只停留在记忆语法。更有效的学习方式是:
- 理解变量、对象和引用关系。
- 熟练使用列表、字典、集合和元组。
- 学会通过函数拆分复杂逻辑。
- 理解异常、文件和模块边界。
- 为每个项目创建独立虚拟环境。
- 使用测试验证关键逻辑。
- 使用日志记录运行过程。
- 从小型项目开始积累工程经验。
- 根据实际方向学习 Web、数据、AI 或自动化生态。
- 保持代码简单、明确、可验证。
Python 入门并不困难,真正需要长期积累的是程序设计、问题拆解、测试意识和工程实践。掌握基础语法后,应尽快完成几个能够独立运行的小项目,在不断编写、调试和改进代码的过程中形成自己的知识体系。