程序能直接跑起来,python -m study.main 就能把整个包当作顶级包来执行,导入没崩,改了代码能立刻看到效果。这是整套演示的最终状态。

倒过来讲这事儿的来龙去脉。最先看到的是入口文件 main.py,放在项目根下,它实则只负责一件事:把包跑起来。进入到项目根目录,执行 cd study_manager 然后 python -m study.main,Python 会把当前目录视作顶级包,包内那些相对导入就不会出问题。这种方式的好处也很明显:不用把 study 安装进 site-packages,调试方便,路径更干净。
再往前看包的组织和导入规则。把目录标成包最直观的做法是放一个 __init__.py。Python 3 已经允许目录没有这个文件也能当包,但留着它还是更明确。可以把它当作包的入口处,或者用来控制哪些名字能被 from study import * 带走——用 __all__ 指定一组名字就行。这样一来,外部不会把包里所有内部实现都拉出来,边界更清楚。

包的导入路径上,常见的做法是把模块按功能放好,然后在外面用短路径来引用。列如希望在包外写 import study.ui as ui,而不是去写 import study.ui.ui 那种啰嗦的形式。包内部则一律用相对导入,前面带一个或多个点,确保引用的是同一个包下的模块,而不是碰到名字冲突去导入别处的同名模块。举个具体的:ui.py 里要实例化 DB 类,正确写法一般是 from .db import DB,然后在界面里直接创建 DB 实例。写法简单,路径不会绕来绕去。
项目结构也不是随意摆的,按功能分目录更利于管理。一个最小但真实的 project 一般包含包目录 study,下属几个模块列如 ui.py、db.py,再配一个 main.py 做入口。界面程序那块负责交互和展示,数据库类或者数据层放在 db.py,其他公共工具放单独模块。每个模块的职责分明,改动时影响面小。

另外一个细节是控制导出。包里的 __init__.py 不只用来标记包,还能定义 __all__ 列表,限制 from study import * 的可见名字。这样当别人把你的包当作黑盒用时,不会意外把内部实现都拉出来,维护起来更省心。控制导出不是强制,但对于中大型项目来说,能减少误用。
如果希望在任意位置 import study,还可以把项目做成可安装包。添加一个 pyproject.toml,内容像这样:

[build-system]
requires = [“setuptools”]

build-backend = “setuptools.build_meta”
[project]

name = “study”
version = “0.1.0”
有了这个文件,创建虚拟环境后可以本地安装:python -m venv venv,然后激活 venv(Linux/Mac:source venv/bin/activate,Windows:venvScriptsactivate),接着 pip install -e .。用 -e 可编辑安装,改代码马上生效,不用每次重装包。
细节上别忽视相对导入的规则。包内相互引用,都用 . 或 .. 这种前缀来明确层级。如果在 ui.py 里直接写 import db,容易被解释器当作外部顶级模块去查找,进而导致导入失败或导入到错误的模块。点开头的相对导入是保险做法。
实现这个小项目时,我把包的各个模块职责都写清楚。界面那块负责调用 DB 接口,DB 负责存取逻辑,__init__.py 决定哪些名字对外可见。整个流程从启动到模块相互调用,都是按约定来的:入口启动包,包内模块相互用相对导入,外面用短路径引用。这样一来,调试和部署都比较顺手。
说句个人感受,按这个套路搭个小项目,后续维护轻松不少。把复杂的导入和路径问题在设计阶段处理好,日后改功能只需要关注模块内部,不用天天挠头看导入错误。
让我们保持学习热烈,多做练习。我们下期再见!
快乐男孩
#python#