清理Python中的包导入

1 投票
1 回答
3238 浏览
提问于 2025-04-17 19:40

我有一个这样的项目结构:

project
|----app.py
|----package
     |---__init__.py
     |---module.py
     |---module2.py
     |---module3.py
     |---....

我的 __init__.py 文件现在是空的。在 module.py 里,我定义了一个类:

class UsefulClass:
    ...

在其他模块里也有类似的定义。我的 app.py 看起来是这样的:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from package.module import UsefulClass
from package.module2 import UsefulClass2
...

usefulclass = UsefulClass()
usefulclass2 = UsefulClass2()
....

我的问题是:我该如何替换这些 from package.module... import UsefulClass 的语句?现在我只有4个模块,但这些导入看起来开始有点乱了。我能不能在 __init__.py 文件里导入它们,然后在 app.py 里只用 import package?我试过这样做,但出现了错误。

我在寻找一个干净优雅的解决方案。

1 个回答

1

在Python 3中:

package/__init__.py

from .foo import bar

package/foo.py

bar=0

app1.py

import package
print(package.bar)

app2.py:

from package import bar
print(bar)

无论哪种方式,这都会打印出0,正如你想要的那样。

在Python 2中,只需将from .foo import bar改为from foo import bar

(实际上,2.x的代码在Python 3中通常也能运行,但这并不正确,在某些特殊情况下会失败。例如,如果你在应用程序同级目录下有一个bar.py,那么你得到的bar将是那个模块,而不是0。)

在实际使用中,你可能想要为每个包和模块指定一个__all__,这样你就可以使用from foo import …(至少这样可以在交互式解释器中用from foo import *来测试东西)。

听起来你是说你已经尝试过这个,并且遇到了错误。没有确切知道你尝试了什么,错误是什么,以及你使用的是哪个Python版本,我无法判断你可能哪里出错了,但可以推测你肯定是出错了。


.foo表示相对导入。说from .foo import bar的意思是“从和我在同一个包里的foo模块中导入bar”。如果你去掉点号,就是在说“从标准模块路径中的foo模块导入bar”。

关于包内引用的教程部分在这里有简要说明。关于import的参考文档和导入系统的一般信息提供了大部分细节,但最初的提案在PEP 328中更简单地解释了细节和设计背后的原因。

在2.x中需要去掉点号的原因是,2.x没有办法区分相对导入和绝对导入。只有from foo import bar,这意味着“从和我在同一个包里的foo模块中导入bar,或者如果没有这样的模块,就从标准模块路径中导入bar”。

撰写回答