当你导入一个模块时,解释器会创建一个新的命名空间,并使用这个新的命名空间作为本地和全局命名空间来执行该模块的代码。当代码执行完成后,模块名称(或在任何as
子句中给出的名称)将绑定到刚刚在导入命名空间内创建的模块对象上,并记录在其__name__
中,在sys.modules
中。
当导入限定名称(例如package.subpackage.module
)时,第一个名称(package
)被导入到本地命名空间中,然后subpackage
被导入到package
的命名空间中,最后module
被导入到package.subpackage
的命名空间中。使用from ... import ... as ...
的导入执行相同的操作序列,但导入的对象直接绑定到导入模块的命名空间中的名称上。包名称未绑定在本地命名空间中并不意味着它未被导入(如检查sys.modules
所示)。
__init__.py
在包中的作用与模块的.py
文件基本相同。一个包有一个结构, 被写成一个目录,该目录还可以包含模块(常规的.py
文件)和子目录(也包含一个__init__.py
文件)用于任何子包。当导入包时,将创建一个新的命名空间,并使用该命名空间作为本地和全局命名空间来执行包的__init__.py
。因此,为了解决您的问题,我们可以通过省略顶级包来简化您的文件存储,当以程序方式运行test.py
时,解释器永远不会考虑它。那么看起来是这样的:
test.py
subpackage/
__init__.py
hello_world.py
现在,subpackage
不再是子包,因为我们已将其所属的包删除为不相关。关注为什么do_something
名称未定义可能有所帮助。test.py
中没有任何导入,因此不清楚您如何期望do_something
获得含义。您可以通过使用空的subpackage/__init__.py
来使其正常工作,然后您可以编写test.py
:
from subpackage.hello_world import do_something
do_something()
或者您可以使用一个subpackage/__init__.py
文件来读取。
from hello_world import do_something
当导入包时,它会在subpackage
命名空间内建立do_something
函数。然后使用一个test.py
文件从该包中导入该函数,如下所示:
from subpackage import do_something
do_something()
最后一个选择与相同的__init__.py
一起使用一个test.py
,只需导入(子)包,然后使用相对命名来访问所需的函数:
import subpackage
subpackage.do_something()
为了在您的本地命名空间中访问它。
通过空的__init__.py
文件,也可以通过读取test.py
文件来实现这一点。
import subpackage.hello_world
subpackage.hello_world.do_something()
甚至连
from subpackage.hello_world import do_something
do_something()
一个空的
__init__.py
文件意味着顶层包命名空间只包含程序导入的任何子包的名称,这使您能够仅导入所需的子包。这为您控制了顶层包的命名空间。
虽然在
__init__.py
中定义类和函数是完全可能的,但更常见的方法是从子模块导入内容到该命名空间中,以便导入者可以仅通过单级属性引用导入顶层包以访问其内容,甚至使用
from
仅导入您明确想要的名称。
最终,保持清晰的import工作原理和其各种形式对导入命名空间的影响的理解是让您保持正确的最佳工具。
test.py
是在package/test.py
目录下?如果是这样,我认为它不需要在一个包中,因此package/__init__.py
似乎是完全无关紧要的。 - holdenweb