Python导入模块:文件和目录有什么区别?

2 投票
4 回答
1104 浏览
提问于 2025-04-17 12:44

我在项目的根目录下有以下文件和文件夹

main.py
bar.py
foo \
    __init__.py
    alice.py
    bob.py

文件夹foo里的文件都是空的,而bar.py的内容是

alice = None
bob = None

还有main.py的内容是

import foo
import bar
print 'foo:', dir(foo)
print 'bar:', dir(bar)

当我执行python main.py时,输出结果是

foo: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
bar: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'alice', 'bob']

为什么在foo里没有alicebob呢?如果我想使用模块foo里的alicebob,除了

from foo import alice, bob

以外,我该怎么做呢?因为那个文件夹里可能有很多文件。

编辑

我的问题不是关于内置函数dir给出的奇怪结果。如果我在main.py里这样做

import foo
foo.alice

就会出现一个异常:AttributeError: 'module' object has no attribute 'alice'

看起来在foo里没有alice?我觉得我在理解如何将一个文件夹作为模块导入时遇到了一些问题。

4 个回答

0
# in foo/__init__.py:
__all__ = ['alice', 'bob']

这段话的意思是,你可以这样做:

# in main.py
from foo import *

并且只导入在all中明确提到的那些模块。

3

你在 dir(bar) 看到的 alicebob 是来自 bar.py 文件里的变量。

dir(foo) doesn't mean directory.

dir : If called without an argument, return the names in the current scope.
Else, return an alphabetized list of names comprising (some of) the attributes
of the given object, and of attributes reachable from it.
If the object supplies a method named __dir__, it will be used; otherwise
the default dir() logic is used and returns
. for a module object: the module's attributes.
. for a class object:  its attributes, and recursively the attributes
    of its bases.
. for any other object: its attributes, its class's attributes, and
    recursively the attributes of its class's base classes.

在 main.py 文件里写:

import foo.alice
import foo.bob

这样你就能得到 alice 和 bob 这两个变量了。

2

这主要是模块和包之间的区别。根据官方文档的解释:

包是一种通过使用“点状模块名称”来组织Python模块命名空间的方式。比如,模块名A.B表示在名为A的包中有一个子模块B。就像使用模块可以让不同模块的作者不必担心彼此的全局变量名一样,使用点状模块名称可以让像NumPy或Python图像库这样的多模块包的作者不必担心彼此的模块名称。

在一个目录中,__init__.py文件的作用是将其变成一个包。这个文件提供了一个地方来指定包的公共接口。你可以通过两种方式将alicebob引入到foo中:

1. 使用 __all__

在你的__init__.py文件中,你可以明确声明你想要暴露的模块,使用__all__。下面的代码将暴露alicebob

`__all__` = ['alice', bob']

2. 直接导入 alicebob

另外,在__init__.py文件中直接导入这些模块也会暴露它们。

这样做还会在初始化时导入这些模块,所以每当你在foo中导入任何东西时,它们也会被导入。

撰写回答