当前位置:首页>python>Python 模块与包:代码超过 500 行就该看这篇了

Python 模块与包:代码超过 500 行就该看这篇了

  • 2026-10-11 07:47:44
Python 模块与包:代码超过 500 行就该看这篇了

你有没有经历过这种痛苦——打开一个 Python 文件,往下一拉,好家伙,3000 行,找个函数翻半天?

这就是今天要聊的话题:怎么把代码拆得明明白白。

一个 .py 文件就是一个模块

这个概念其实特别简单。你写了一个 utils.py,那 utils 就是一个模块。想在别的文件里用它?导入就行:

import utils
utils.some_function()

导入有三种写法,我直接说结论:**默认用 import xxx**。为什么?因为看到 math.sqrt() 你就知道 sqrt 来自 math 模块,一清二楚。要是写成 from math import sqrt,调用时只写 sqrt(),别人读代码还得猜这函数哪来的。

当然,from math import pi 这种导入一两个常量的情况也完全没问题。但 from math import * 这种"全倒入"的写法,千万别用——你不知道它会往你的代码里塞多少名字,万一跟你自己的变量撞了,debug 到哭。

还有一个特别实用的技巧:给模块起别名。比如 import numpy as np,这已经是整个 Python 社区的默契了,大家一看就懂。

Python 去哪找你的模块?

当你写下 import utils,Python 会按顺序在几个地方找这个文件:

  1. 你当前脚本所在的目录(优先级最高)
  2. 环境变量 PYTHONPATH 里的目录
  3. Python 安装目录下的标准库
  4. 第三方库的安装目录 site-packages

这里面有个大坑:千万别给你的文件取跟标准库一样的名字。你要是写了个 json.py,同目录下 import json 导入的就是你自己的文件,而不是标准库的 json。这种 bug 找起来能让人怀疑人生。

那个经典的 if __name__ == "__main__"

这段代码你肯定见过:

if __name__ == "__main__":
    main()

原理一句话就说清:文件被直接运行时,__name__ 等于 "__main__";被导入时,__name__ 等于模块名。所以这行代码的作用就是——直接运行才执行,被导入不执行。

养个好习惯,每个脚本底部都加上它。这样你的文件既能当脚本直接跑,又能当模块被别人导入,互不干扰。

目录也能当模块用——包(Package)

把几个 .py 文件放进一个目录,再加一个 __init__.py 文件(哪怕是空的),这个目录就变成了"包":

myapp/
├── __init__.py
├── models.py      # myapp.models
├── views.py       # myapp.views
└── utils.py       # myapp.utils

__init__.py 不只是个占位符。你可以在里面导入子模块的核心功能,让用户写 from myapp import User 就够了,不用写 from myapp.models import User。这就是一种"便捷接口"的设计。

包还能嵌套——包里面再放包,形成子包。但记住一条:包层级别超过 3 层。太深的嵌套只会让导入路径变得又长又难读。

绝对导入 vs 相对导入

包内部的模块互相导入时,有两种写法:

# 绝对导入:从项目根包写完整路径
from myproject.models.user import User

# 相对导入:用 . 表示当前包,.. 表示上级包
from ..models.user import User

PEP 8 官方推荐绝对导入,理由很直白:一眼就能看出 User 在哪。相对导入还得在心里算一算 .. 是第几层,容易搞晕。

不过相对导入也有它的价值——当你可能改包名的时候,相对导入不需要改任何代码。很多大型项目内部用相对导入,对外接口用绝对导入,这个思路可以借鉴。

你可能不知道的标准库宝藏

Python 最大的优势之一就是"自带电池"——装完 Python 就有好几百个现成模块可以用。挑几个最实用的说说:

pathlib——路径操作首选。用 / 拼接路径,比 os.path.join 优雅太多:

from pathlib import Path
p = Path("src") / "main.py"
print(p.read_text())  # 直接读取文件内容

collections——高级容器。Counter 数数、defaultdict 省去判断 key 是否存在、deque 做双端队列,都是一行搞定的事。

json / csv——数据处理标配。json.dumps() 和 json.loads() 一对搭档走天下,CSV 读写也是几行代码的事。

secrets——生成安全随机数。别再用 random 模块生成密码了,secrets.token_hex(16) 才是正解。

dataclasses——用装饰器自动生成 __init__、__repr__、__eq__,省掉一大坨样板代码:

from dataclasses import dataclass

@dataclass
classUser:
    name: str
    age: int
    email: str = ""

contextlib——@contextmanager 装饰器让你用生成器写上下文管理器,不用写类那么麻烦:

from contextlib import contextmanager

@contextmanager
deftimer(label="操作"):
    start = time.time()
yield
    print(f"{label}耗时 {time.time() - start:.2f} 秒")

with timer("数据处理"):
# 你的代码
pass

总结

模块和包是 Python 项目组织的基本功:.py 文件是模块,带 __init__.py 的目录是包,import 把它们串起来。标准库里有大量现成工具,遇到问题先想想"Python 是不是已经帮我造好了这个轮子"。

别想着一次把标准库全记住,那是查文档的事。你只需要建立一个索引——知道有什么,用的时候去查就行。Python 官方文档(docs.python.org/3/library/)写得很详细,是最好的参考。

把代码拆好了,你未来的自己会感谢现在的你。

最新文章

随机文章