Python 基础 · Python 3.13 / 3.14

"人生苦短,我用 Python。"这不是一句口号,是无数程序员血泪换来的结论。这一页把 Python 从"装环境"讲到"写出能交付的命令行小工具"——语法、数据结构、函数、面向对象、装饰器、异常、模块包、文件 IO、并发异步、测试,外加一个待办事项小项目。版本基线:Python 3.13(2024 年 10 月发布,当前稳定主力)与 Python 3.14(2025 年 10 月发布,最新)。Python 2 已于 2020 年正式停更,别再回头。

最新版本与兼容性(以 python.org 官网最新稳定版为准)
版本状态要点
Python 3.14最新稳定2025 年 10 月发布,当前最新稳定版;自由线程(no-GIL)与 JIT(copy-and-patch)按官方节奏推进,具体新特性以官网发布说明为准。
Python 3.13当前主力2024 年 10 月发布,生态最稳、第三方库适配最全;自由线程(no-GIL)为实验性,需用 --disable-gil 开关启用;copy-and-patch JIT 同为实验性。
Python 3.12广泛使用上一代稳定版,大量生产环境仍在跑;错误提示更友好,性能小幅提升。新项目建议直接上 3.13 / 3.14。
Python 2.x已停更2020 年 1 月 1 日 EOL(End Of Life),官方不再发安全补丁。网上老教程里 print "hi"(无括号)全是 Python 2 写法,别照抄。

包管理与虚拟环境速查

类别工具说明
包管理pip 25.x标准包管理器,pip install xxx,所有项目都绕不开。
uvAstral 出品的超快包管理器(Rust 写的),比 pip 快 10-100 倍,兼容 pip 接口,新项目强烈推荐。
poetry 1.8.x带依赖锁定和虚拟环境管理,pyproject.toml 一站式,适合正式开源库。
conda科学计算专用,连 Python 解释器一起管,处理 NumPy/PyTorch 等 C 扩展库时省心。
虚拟环境venv标准库自带,python -m venv .venv,轻量够用。
virtualenvvenv 的加强版,Python 3.3 之前的老方案,现在基本被 venv 取代。
conda envconda 自带的环境隔离,和 conda 配套用。
no-GIL 与 JIT:别急着当主力

Python 3.13 的自由线程(no-GIL)和 copy-and-patch JIT 都还是实验性:自由线程要编译/下载专门版本并用 --disable-gil 启动,很多 C 扩展库(NumPy、Pillow 等)还没完全适配;JIT 更早期,效果因场景而异。生产环境先用标准 3.13 / 3.14,等 3.14 之后官方宣布正式化再迁移。别为了"消灭 GIL"把自己坑进兼容性地狱。

测

小结 & 自测题

Summary & Quiz

到这里,你已经从"装 Python"走到了"写一个命令行工具"。Python 的精髓不是记住所有语法,而是知道有什么、需要时能查。下面 5 道题,遮住答案自己答一遍。

自测 · Python 基础

1.(概念题)Python 里 list 和 tuple 最本质的区别是什么?什么时候你会特意用 tuple?

查看答案

答案:list 可变,tuple 不可变。当数据不该被改(坐标、函数多返回值、当字典键)时用 tuple。解析:不可变是一种"约束"——它告诉读代码的人"这东西别乱动",同时 tuple 能当字典的键,list 不行。

2.(代码题)下面代码输出什么?为什么?

def f(x=[]): x.append("hi") return x print(f()) print(f())
查看答案

答案:第一次 ['hi'],第二次 ['hi', 'hi']。解析:这就是著名的"可变默认参数坑"——默认列表在函数定义时只创建一次,两次调用共用同一个列表。修法:def f(x=None): if x is None: x = []。

3.(概念题)为什么 Python 的多线程不适合加速"CPU 密集型"任务?该用什么?

查看答案

答案:因为 GIL(全局解释器锁)——同一时刻一个进程里只有一个线程跑 Python 字节码,多线程在 CPU 密集任务上等于排队。CPU 密集型应该用 multiprocessing 多进程(绕开 GIL)。IO 密集型才用线程或 asyncio。

4.(代码题)用列表推导式,把 [1,2,3,4,5,6] 变成每个偶数的平方,结果是?

查看答案

答案:[x*x for x in [1,2,3,4,5,6] if x % 2 == 0] → [4, 16, 36]。解析:前半段 x*x 是加工,if x%2==0 是筛选。推导式一行顶三行循环。

5.(思考题)你写了一个爬取 1000 个网页的脚本,串行要 10 分钟,想提速。你会选多线程还是多进程?为什么?

查看答案

答案:选多线程(或 asyncio)。解析:爬虫的时间几乎全花在"等网络返回"上,是 IO 密集型。GIL 在等网络时会释放,多线程能真正并行等。用多进程纯属浪费——创建进程贵,而且 CPU 根本没在算东西。最佳是 asyncio + aiohttp,几千个请求同时飞。

综合练习题(5 道,覆盖全章)

综合练习 · 动手写

1.(代码题)写一个带参数的装饰器 @log_calls(prefix="[API]"),打印每次调用的函数名、参数和前缀。要求用 functools.wraps。

查看答案

答案:三层结构——外层接参数 prefix,中层接函数,内层接调用。wrapper(*a, **kw) 里先 print 前缀+函数名+参数,再调原函数。别忘 @wraps(func)。这是带参装饰器的固定套路。

2.(代码题)用生成器写一个"读超大日志文件,逐行 yield 错误行"的函数,要求内存恒定(不能 read() 整个文件)。

查看答案

答案:def iter_error_lines(path): 里 with open(path) as f: for line in f: if "ERROR" in line: yield line.rstrip()。解析:文件对象本身就是迭代器,for line in f 逐行缓冲不读全文件;yield 出去调用方处理完才拉下一行——几个 G 的日志也只占一行内存。

3.(代码题)用 ThreadPoolExecutor 并发下载 5 个 URL 的状态码,要求"谁先下完先打印谁",并统计总耗时。

查看答案

答案:pool.submit 每个任务一次,存进 {fut: url} 字典;as_completed(futs) 按完成先后迭代,fut.result() 拿结果。解析:as_completed 适合流式打印,max_workers 5-20 足够,开太多反而被限流。

4.(代码题)写一个异步协程 fetch_all(urls),用 aiohttp 并发抓取,Semaphore 限制同时最多 10 个,返回 {url: status_code}。

查看答案

答案:建 sem = asyncio.Semaphore(10),内部 one(u) 在 async with sem 里 async with s.get(u) as r: return u, r.status;外层 dict(await asyncio.gather(*[one(u) for u in urls]))。解析:Semaphore 限流防封 IP,gather 汇总成 (url, status) 配对,dict() 反转成映射。

5.(思考题)你有一个 100 万行的 CSV,要统计其中"价格 > 100 的行数"。用 sum(1 for row ...) 和 len([...]) 哪个好?为什么?

查看答案

答案:用生成器表达式 sum(1 for row in reader if price>100)。len([...]) 会先建 100 万元素的列表占内存再数长度;生成器边读边数,内存恒定。这就是"能用生成器就别用列表"的典型场景。

下
下一步去哪

① 动手:把 todo 项目加个"优先级"和"按日期筛选"功能。

② 写点真脚本:拿你每周重复的一件事,写成 Python。

③ 进 AI 方向:Python 基础打底之后,下一页就是 Python AI 数据科学——NumPy、Pandas、PyTorch。