Python 完整指南¶
适用人群:希望用 Python 编写脚本、数据处理程序、Web 服务或 AI 应用的学习者
前置要求:会使用终端,理解文件、目录和程序的基本概念
最后更新:2026-07-21
Python 的优势不在某一个语法特性,而在于它用较低的表达成本连接了自动化、Web、数据科学和人工智能生态。本章不尝试罗列语言的每个角落,而是建立一条可直接工作的主线:先获得可重复的运行环境,再掌握常用数据结构和控制流,随后学习文件、异常、模块、测试与项目组织,最后用速查表完成日常查询。
1. 先理解 Python 程序如何运行¶
Python 源文件通常以 .py 结尾。执行 python app.py 时,解释器读取源码、编译为字节码,再由 Python 虚拟机执行。日常所说的“Python 版本”通常指 CPython 解释器版本。Python 2 已停止维护,新项目只使用仍受支持的 Python 3。
sys.executable 能回答“当前到底使用了哪一个 Python”,比只看命令提示符可靠。macOS 和 Linux 上通常使用 python3,进入虚拟环境后使用 python;Windows 可以使用 python 或 Python Launcher 的 py。
Python 适合快速开发和生态集成,但不是所有场景的默认答案。CPU 密集型底层系统、硬实时任务或极端低延迟组件可能更适合 Rust、C++、Go 等语言;Python 常通过 NumPy、PyTorch 等由底层编译代码实现的库获得计算性能。
安装与验证¶
优先从 Python 官方下载页 或操作系统包管理器安装。不要修改系统组件依赖的 Python,也不要把第三方包直接安装到系统环境。
# macOS
brew install python
# Ubuntu/Debian:发行版仓库版本最稳定
sudo apt update
sudo apt install python3 python3-venv python3-pip
# Windows PowerShell:先查看当前稳定版本对应的包 ID
winget search --id Python.Python
安装后进行最小验证:
需要同时维护多个 Python 版本时再引入 pyenv 或 uv;科学计算环境依赖复杂的本地库时可使用 Conda。初学阶段只掌握“一个项目、一个虚拟环境”即可,过早混用多个环境管理器反而增加路径问题。
2. 虚拟环境和依赖:每个项目都要隔离¶
两个项目可能分别依赖同一库的不同版本。虚拟环境为项目创建独立解释器入口和包目录,使升级 A 项目不会破坏 B 项目。标准流程如下:
mkdir demo-python && cd demo-python
python3 -m venv .venv
# macOS / Linux
source .venv/bin/activate
# Windows PowerShell
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install requests
python -c 'import requests; print(requests.__version__)'
deactivate
始终使用 python -m pip,它明确调用当前解释器对应的 pip,避免 python 与 pip 来自不同环境。.venv/ 是可重建目录,必须加入 .gitignore,不能提交到仓库。
requirements.txt 与 pyproject.toml¶
简单脚本可以使用 requirements.txt:
python -m pip install -r requirements.txt
python -m pip list
python -m pip show requests
python -m pip check
可安装项目、库和长期维护的应用应使用 pyproject.toml 描述项目元数据和直接依赖:
[build-system]
requires = ["setuptools>=75"]
build-backend = "setuptools.build_meta"
[project]
name = "log-summary"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = ["requests>=2.32,<3"]
[project.optional-dependencies]
dev = ["pytest>=8", "ruff>=0.9"]
[project.scripts]
log-summary = "log_summary.cli:main"
-e 表示 editable install,修改本地源码后无需重复安装。应用部署还需要锁定经过测试的间接依赖版本,可以使用组织选定的锁文件工具;不要把 pip freeze 得到的整台机器快照当作库的依赖声明。
3. 变量、对象与基本类型¶
Python 变量保存对象引用,不需要预先声明类型。赋值不会复制对象:
count = 3 # int
ratio = 0.75 # float
enabled = True # bool
name = "python" # str
missing = None # NoneType
items = ["a", "b"]
alias = items
alias.append("c")
print(items) # ['a', 'b', 'c']
判断空值使用 is None,比较值使用 ==:
整数没有固定精度上限;浮点数遵循二进制浮点规则,不能精确表示所有十进制小数。金额等需要十进制精确计算的场景使用 decimal.Decimal:
字符串与格式化¶
字符串是不可变 Unicode 序列。最常用操作包括切片、拆分、清理和拼接:
text = " Alice,admin "
clean = text.strip()
user, role = clean.split(",", maxsplit=1)
print(user.lower())
print(role.upper())
print(f"user={user!r}, role={role!r}")
常见格式:
文本与字节必须明确区分。网络和文件底层传输 bytes,业务文本通常使用 str:
4. 四种核心容器类型¶
选择数据结构时先问是否需要顺序、修改、唯一性和键值查询。
| 类型 | 特征 | 常用场景 |
|---|---|---|
list |
有序、可变、允许重复 | 一组按顺序处理的对象 |
tuple |
有序、不可变 | 固定记录、函数返回多个值 |
set |
无重复、支持集合运算 | 去重、成员测试 |
dict |
键到值的映射 | 配置、索引、结构化记录 |
names = ["alice", "bob", "alice"]
names.append("carol")
first_two = names[:2]
point = (10, 20)
x, y = point
unique_names = set(names)
is_known = "alice" in unique_names
user = {"name": "alice", "role": "admin"}
role = user.get("role", "viewer")
for key, value in user.items():
print(key, value)
复制可变容器时要注意浅复制只复制外层:
from copy import deepcopy
original = {"tags": ["a", "b"]}
shallow = original.copy()
complete = deepcopy(original)
推导式适合简短的映射和过滤,但复杂逻辑应改用普通循环:
squares = [n * n for n in range(10) if n % 2 == 0]
by_name = {item["name"]: item for item in records}
5. 条件、循环与模式匹配¶
Python 使用缩进表达代码块,标准缩进是四个空格。空字符串、空容器、数字零和 None 在条件中视为假。
if status == 200:
result = "ok"
elif 400 <= status < 500:
result = "client error"
else:
result = "other"
遍历时优先使用迭代协议,不要手工维护下标:
for index, name in enumerate(names, start=1):
print(index, name)
for name, score in zip(names, scores, strict=True):
print(name, score)
for attempt in range(3):
if connect():
break
else:
raise RuntimeError("all attempts failed")
break 结束当前循环,continue 跳过本轮,while 适合循环次数取决于运行状态的场景。所有 while 都应有可理解的结束条件。
Python 3.10 以后可用 match 处理结构化分支:
match event:
case {"type": "created", "id": item_id}:
handle_created(item_id)
case {"type": "deleted", "id": item_id}:
handle_deleted(item_id)
case _:
raise ValueError("unsupported event")
6. 函数:明确输入、输出和副作用¶
函数应完成一个清晰动作。参数和返回值使用类型注解,文档说明业务含义和异常,而不是逐行复述代码。
def calculate_total(
prices: list[float],
*,
discount: float = 0.0,
) -> float:
"""Return the discounted total; raise on an invalid discount."""
if not 0 <= discount <= 1:
raise ValueError("discount must be between 0 and 1")
return sum(prices) * (1 - discount)
total = calculate_total([10.0, 20.0], discount=0.1)
* 之后的参数必须按名称传入,能减少布尔值和数字参数位置混淆。默认值应使用不可变对象:
def add_tag(tag: str, tags: list[str] | None = None) -> list[str]:
result = [] if tags is None else list(tags)
result.append(tag)
return result
不要写 tags=[],因为默认列表只创建一次,会在调用之间共享。
*args 收集额外位置参数,**kwargs 收集额外关键字参数。它们适合适配器和装饰器,不应替代明确的业务参数。
7. 模块、包与项目结构¶
每个 .py 文件是模块,包含 __init__.py 的目录通常作为包。推荐使用 src 布局,避免测试时意外导入工作目录中的源码:
log-summary/
├── pyproject.toml
├── README.md
├── src/
│ └── log_summary/
│ ├── __init__.py
│ ├── cli.py
│ └── parser.py
└── tests/
└── test_parser.py
# src/log_summary/cli.py
from log_summary.parser import summarize
def main() -> None:
print(summarize("events.log"))
if __name__ == "__main__":
main()
导入顺序通常是标准库、第三方包、本项目模块。避免 from module import *,它会隐藏名称来源并增加冲突。
循环导入通常说明模块职责互相依赖。可通过抽取共享类型、移动导入到共同底层模块或重新划分边界解决,不要默认用函数内导入掩盖设计问题。
8. 文件、路径、JSON 与 CSV¶
路径操作优先使用 pathlib,文件读写明确编码,并用 with 保证资源关闭:
from pathlib import Path
path = Path("data") / "message.txt"
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("hello\n", encoding="utf-8")
for line in path.read_text(encoding="utf-8").splitlines():
print(line)
大文件不要一次 read_text() 全部加载,应流式迭代:
with path.open(encoding="utf-8") as file:
for line_number, line in enumerate(file, start=1):
process(line_number, line.rstrip("\n"))
JSON 只支持有限类型,日期、自定义对象和集合需要转换:
import json
from pathlib import Path
data = {"name": "alice", "roles": ["admin"]}
Path("user.json").write_text(
json.dumps(data, ensure_ascii=False, indent=2),
encoding="utf-8",
)
loaded = json.loads(Path("user.json").read_text(encoding="utf-8"))
CSV 使用标准库时应指定 newline="":
import csv
with open("users.csv", newline="", encoding="utf-8") as file:
for row in csv.DictReader(file):
print(row["name"])
临时文件使用 tempfile,文件复制使用 shutil,不要用字符串拼接路径或调用 shell 的 cp 完成跨平台文件操作。
9. 异常、日志与资源清理¶
异常表示当前层无法正常完成操作。捕获范围应尽量小,并捕获可以处理的具体异常:
import json
from pathlib import Path
def load_config(path: Path) -> dict[str, object]:
try:
text = path.read_text(encoding="utf-8")
return json.loads(text)
except FileNotFoundError as exc:
raise RuntimeError(f"config not found: {path}") from exc
except json.JSONDecodeError as exc:
raise RuntimeError(
f"invalid JSON at line {exc.lineno}, column {exc.colno}"
) from exc
不要使用空的 except:,也不要捕获后什么都不做。raise ... from exc 保留原始错误链。finally 适合必须执行的清理,但文件、锁和连接更推荐使用上下文管理器。
生产程序使用 logging 而不是散落的 print:
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s %(message)s",
)
logger = logging.getLogger(__name__)
logger.info("processing started", extra={"job_id": "job-42"})
日志应包含时间、级别、组件和用于关联请求的 ID,但不能记录密码、令牌和完整个人敏感信息。
10. 类、dataclass 与类型注解¶
简单数据记录优先使用 dataclass,只有对象确实需要维护状态和行为时才创建复杂类。
from dataclasses import dataclass
@dataclass(frozen=True, slots=True)
class User:
name: str
roles: tuple[str, ...]
def can(self, role: str) -> bool:
return role in self.roles
frozen=True 表达不可变意图,slots=True 限制随意增加属性。继承适合真正的“是一个”关系,复用行为时通常优先组合。
类型注解不会在运行时自动验证输入,但能让编辑器和静态检查器提前发现问题:
from collections.abc import Iterable
def average(values: Iterable[float]) -> float:
items = list(values)
if not items:
raise ValueError("values cannot be empty")
return sum(items) / len(items)
对外部 JSON、表单和环境变量仍需运行时校验。类型注解描述程序内部约定,不能替代边界验证。
11. 迭代器、生成器与上下文管理器¶
可迭代对象能产生迭代器,迭代器逐个返回值。生成器用 yield 按需计算,适合大数据流:
from collections.abc import Iterator
from pathlib import Path
def error_lines(path: Path) -> Iterator[str]:
with path.open(encoding="utf-8") as file:
for line in file:
if "ERROR" in line:
yield line.rstrip("\n")
生成器是一次性数据流,消费后不能自动重放。需要重复遍历时重新创建生成器或显式转为列表。
上下文管理器负责成对的获取与释放。除文件外,数据库事务、锁和临时目录都应采用 with:
from contextlib import contextmanager
from time import perf_counter
@contextmanager
def timer(name: str):
start = perf_counter()
try:
yield
finally:
print(f"{name}: {perf_counter() - start:.3f}s")
12. 并发、并行与 async¶
三种常见需求要分开:等待网络或磁盘属于 I/O 密集;大量 Python 计算属于 CPU 密集;同时服务大量连接适合异步 I/O。
| 需求 | 常用工具 | 说明 |
|---|---|---|
| 少量阻塞 I/O 并发 | ThreadPoolExecutor |
线程共享内存,注意线程安全 |
| CPU 密集并行 | ProcessPoolExecutor |
多进程有序列化和启动成本 |
| 大量异步连接 | asyncio |
依赖库也必须支持异步 |
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=8) as pool:
results = list(pool.map(fetch_url, urls))
import asyncio
async def main() -> None:
results = await asyncio.gather(fetch_a(), fetch_b())
print(results)
asyncio.run(main())
不要在 async def 中直接调用耗时的同步网络或文件函数,它会阻塞事件循环。并发还需要超时、取消、连接池和并发上限,不能只追求同时启动更多任务。
13. 测试、调试和代码质量¶
测试描述程序在给定输入下必须保持的行为。使用 pytest 时,测试文件和函数通常以 test_ 开头:
# src/log_summary/parser.py
def parse_level(line: str) -> str:
if not line.strip():
raise ValueError("empty line")
return line.split(maxsplit=1)[0]
# tests/test_parser.py
import pytest
from log_summary.parser import parse_level
@pytest.mark.parametrize(
("line", "expected"),
[("INFO started", "INFO"), ("ERROR failed", "ERROR")],
)
def test_parse_level(line: str, expected: str) -> None:
assert parse_level(line) == expected
def test_parse_level_rejects_empty_line() -> None:
with pytest.raises(ValueError, match="empty"):
parse_level(" ")
遇到问题先保留完整 traceback。最下方通常是直接异常,上方是调用链。可用 breakpoint() 暂停并检查变量:
日常质量工具可以收敛为 Ruff 与 pytest:
格式化解决排版一致性,lint 检查常见错误,类型检查验证静态约定,测试验证行为;它们不能互相替代。
14. 配置、环境变量与命令行程序¶
配置应与代码分离。环境变量输入始终是字符串,需要显式转换和验证:
import os
def read_port() -> int:
value = int(os.getenv("APP_PORT", "8000"))
if not 1 <= value <= 65535:
raise ValueError("APP_PORT must be between 1 and 65535")
return value
秘密不要写进源码、Dockerfile、命令示例或 Git。.env 只适合本地开发且必须忽略,生产环境使用平台秘密管理服务。
标准库 argparse 足以编写稳定 CLI:
import argparse
def main() -> None:
parser = argparse.ArgumentParser(description="Summarize a log file")
parser.add_argument("path")
parser.add_argument("--level", default="ERROR")
args = parser.parse_args()
print(args.path, args.level)
if __name__ == "__main__":
main()
15. 常见问题的定位顺序¶
python: command not found¶
先确认平台命令名和路径:
Windows 使用 where python 和 py -0p。不要通过随意修改系统软链接解决版本问题。
包已经安装却 ModuleNotFoundError¶
多数情况是安装包和运行程序使用了不同解释器:
python -c 'import sys; print(sys.executable)'
python -m pip --version
python -m pip show PACKAGE_NAME
确认虚拟环境已激活,并检查模块名是否与安装包名不同、当前目录是否存在同名文件遮蔽第三方包。
依赖冲突¶
在全新的虚拟环境中根据依赖文件重建,比在污染环境里反复升级降级更可靠。不要同时让 Conda 和 pip 管理同一个底层二进制依赖,除非理解两者边界。
编码错误¶
文件读写明确写 encoding="utf-8"。无法解码时先确认真实编码,不要用 errors="ignore" 静默丢失数据。
程序很慢或占用内存过大¶
先测量再优化。使用生成器避免一次加载全部数据;减少循环中的重复 I/O;对 CPU 瓶颈使用 profiler;数据计算优先使用向量化库。不要因为 Python 循环慢就盲目增加线程。
16. 高频语法与命令速查¶
环境与依赖¶
| 目的 | 命令 |
|---|---|
| 查看解释器 | python -c 'import sys; print(sys.executable)' |
| 创建环境 | python3 -m venv .venv |
| 激活环境 | source .venv/bin/activate |
| 安装依赖 | python -m pip install PACKAGE |
| 从文件安装 | python -m pip install -r requirements.txt |
| 查看包 | python -m pip show PACKAGE |
| 检查冲突 | python -m pip check |
| 安装当前项目 | python -m pip install -e '.[dev]' |
常用内置函数¶
| 函数 | 用途 |
|---|---|
len(x) |
元素数量 |
type(x) / isinstance(x, T) |
类型检查 |
range() |
整数序列 |
enumerate() |
同时获取索引和值 |
zip() |
并行遍历多个序列 |
sorted() |
返回排序后的新列表 |
sum() / min() / max() |
聚合数值 |
any() / all() |
任一或全部条件判断 |
open() |
打开文件,通常配合 with |
高频标准库¶
| 模块 | 主要用途 |
|---|---|
pathlib |
路径和文件操作 |
json / csv |
数据交换格式 |
datetime / zoneinfo |
日期、时间和时区 |
collections |
Counter、defaultdict、deque |
itertools |
组合迭代器 |
re |
正则表达式 |
subprocess |
受控启动子进程 |
logging |
结构化运行日志 |
argparse |
命令行参数 |
concurrent.futures / asyncio |
并发与异步 |
17. 延伸阅读¶
- Python 官方教程:语言基础与标准语法
- Python 标准库:查询内置模块和 API
- Python Packaging User Guide:
pyproject.toml、构建与发布 - pytest 官方文档:测试组织、fixture 与参数化
- Ruff 官方文档:格式化和 lint
- PEP 8:Python 代码风格指南