我正在学习Python,而我无法弄清楚__init__.py
中的导入是如何工作的。
我从the Python tutorial了解到__init__.py
文件初始化了一个包,并且我可以在这里导入子包。
以下是我尝试做的简单示例。
这是我的文件结构:
package
__init__.py
test.py
subpackage
__init__.py
hello_world.py
hello_world.py
的内容:
def do_something():
print "Hello, world!"
subpackage/__init__.py
为空。
package/__init__.py
包含:
import test.submodule.do_something
最后,test.py
包含:
do_something()
这是我尝试使用OSX终端和Python 3运行hello_world.py的方式:
python test.py
然后,Python会抛出以下错误:
NameError: name 'do_something' is not defined
答案 0 :(得分:17)
您可能已经明白,当您导入模块时,解释器会创建一个新的命名空间,并使用新的命名空间作为本地命名空间和全局命名空间来执行该模块的代码。当代码完成执行时,模块名称(或任何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
在导入包时在do_something
命名空间内建立subpackage
函数。然后使用从包中导入函数的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()
最终,让您保持领先的最佳工具是清楚地了解导入的工作原理以及其各种形式对导入命名空间的影响。
答案 1 :(得分:1)
首先,您必须了解import
单独工作的方式:
import test.submodule.do_something
尝试从do_something
加载的submodule
加载test
。
你想从subpackage
加载一些东西,所以从那开始:
import subpackage
很好,subpackage/__init__.py
已加载。
现在,您需要文件中的do_something()
函数("模块")hello_world.py
。易:
from subpackage.hello_world import do_something
你完成了!只需大声读取此行,它就会完全按照其说明:从do_something
包中的模块hello_world
导入subpackage
。
在test.py
from subpackage.hello_world import do_something
do_something()
它应该可以正常工作。
现在,第二个问题:
由于您未使用__init__.py
作为套餐,因此package/
无法调用{p> package/
。如果您导入__init__.py
或其中的任何内容,将使用package/
,例如:
from package import test
否则,它根本不会被加载。
但是,如果您要在导入子包时加载do_something()
,请将from submodule.hello_word import do_something
放入subpackage/__init__.py
,然后在test.py
中,执行{{1} }}
答案 2 :(得分:1)
在Python中,这是一个绝对的硬性规则,必须始终在您正在使用它的模块中定义或导入名称。在这里,你永远不会在test.py中导入任何内容 - 因此,如错误所示,do_something
未定义。
即使您的package/__init__.py
文件已被执行(正如其他人所指出的那样,但事实并非如此),您的代码仍然无法正常工作,因为导入do_something
已经如果要在该文件中引用它,可以在test.py中完成。