在Python中导入包
我可能漏掉了一些明显的东西,不过无所谓:
当你在Python中导入一个像 os
这样的包时,你可以直接使用它的任何子模块或子包。例如,这样做是可以的:
>>> import os
>>> os.path.abspath(...)
但是,我有自己的包,结构如下:
FooPackage/
__init__.py
foo.py
而在这里,同样的逻辑却不奏效:
>>> import FooPackage
>>> FooPackage.foo
AttributeError: 'module' object has no attribute 'foo'
我到底哪里做错了呢?
6 个回答
你需要在你的包的 __init__.py
文件中添加 from . import foo
这一行代码。
当你导入 FooPackage
时,Python 会在 PYTHONPATH 指定的目录中查找,直到找到一个叫 FooPackage.py
的文件,或者一个名为 FooPackage
的文件夹,里面有一个叫 __init__.py
的文件。不过,找到这个包的文件夹后,Python 并不会自动扫描这个文件夹里的所有 .py 文件并导入它们。
这样做有两个原因。第一个原因是,导入一个模块会执行 Python 代码,这可能会消耗时间、内存,或者产生一些副作用。所以你可能只想导入 a.b.c.d
,而不想把整个大包 a
都导入进来。包的设计者可以决定是否在 __init__.py
中明确导入它的模块和子包,这样它们就总是可用,或者让使用这个包的程序自己选择要加载哪些内容。
第二个原因稍微复杂一点,也很重要。如果没有明确的导入语句(无论是在 FooPackage/__init__.py
里,还是在使用这个包的程序中),Python 不一定知道应该把 foo.py
导入成什么名字。在不区分大小写的文件系统中(比如 Windows),这可能代表一个叫 foo
、Foo
、FOO
、fOo
、foO
、FoO
、FOo
或 fOO
的模块。这些都是有效且不同的 Python 标识符,所以光凭文件名,Python 没法知道你想要哪个。因此,为了在所有系统上都能保持一致,Python 需要在某个地方有一个明确的导入语句来说明这个名字,即使在那些能够区分大小写的文件系统上也是如此。
你需要导入这个子模块:
import FooPackage.foo
你现在是在寻找 foo
这个东西,它在 FooPackage/__init__.py
这个文件里。你可以通过在 FooPackage/__init__.py
里加上 import FooPackage.foo as foo
(或者 from . import foo
)来解决这个问题,这样 Python 就能在那找到 foo
了。不过我建议你还是用我最开始的建议。