使用 __init__.py 导入 Python 子模块

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24302754/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 04:24:48  来源:igfitidea点击:

Python submodule imports using __init__.py

python

提问by Benjamin

I'm learning Python, and I can't figure out how imports in __init__.pywork.

我正在学习 Python,但我无法弄清楚导入是如何__init__.py工作的。

I understand from the Python tutorialthat the __init__.pyfile initializes a package, and that I can import subpackages here.

我从Python 教程中了解到该__init__.py文件会初始化一个包,并且我可以在此处导入子包。

I'm doing something wrong, though. Could you explain for me (and for future Python-learners) what I'm doing wrong?

不过,我做错了什么。您能否为我(以及未来的 Python 学习者)解释一下我做错了什么?

Here's a simplified example of what I'm trying to do.

这是我正在尝试做的一个简化示例。

This is my file structure:

这是我的文件结构:

package
    __init__.py
    test.py
    subpackage
        __init__.py
        hello_world.py

The contents of hello_world.py:

内容hello_world.py

def do_something():
    print "Hello, world!"

subpackage/__init__.pyis empty.

subpackage/__init__.py是空的。

package/__init__.pycontains:

package/__init__.py包含:

import test.submodule.do_something

And finally, test.pycontains:

最后,test.py包含:

do_something()

This is how I attempt to run hello_world.py using OSX terminal and Python 3:

这就是我尝试使用 OSX 终端和 Python 3 运行 hello_world.py 的方式:

python test.py

Python then throws the following error:

Python然后抛出以下错误:

NameError: name 'do_something' is not defined

采纳答案by holdenweb

You probably already understand that when you import a module, the interpreter creates a new namespace and executes the code of that module with the new namespace as both the local and global namespace. When the code completes execution, the module name (or the name given in any asclause) is bound to the module object just created within the importing namespace and recorded against its __name__in sys.modules.

您可能已经了解,当您导入一个模块时,解释器会创建一个新的命名空间,并使用新的命名空间作为本地和全局命名空间来执行该模块的代码。当代码完成执行时,模块名称(或任何子as句中给出的名称)绑定到刚刚在导入命名空间中创建的模块对象,并记录在其__name__in 中sys.modules

When a qualified name such as package.subpackage.moduleis imported the first name (package) is imported into the local namespace, then subpackageis imported into package's namespace and finally moduleis imported into package.subpackage's namespace. Imports using from ... import ... as ...perform the same sequence of operations, but the imported objects are bound directly to names in the importing module's namespace. The fact that the package name isn't bound in your local namespace does not mean it hasn't been imported (as inspection of sys.moduleswill show).

当一个限定名称如package.subpackage.module被导入时,名字(package)被导入到本地命名空间,然后subpackage被导入到package的命名空间,最后module被导入到package.subpackage的命名空间。导入使用from ... import ... as ...执行相同的操作序列,但导入的对象直接绑定到导入模块命名空间中的名称。包名称未绑定在您的本地命名空间中的事实并不意味着它没有被导入(如检查sys.modules将显示)。

The __init__.pyin a package serves much the same function as a module's .pyfile. A package, having structure, is written as a directory which can also contain modules (regular .pyfiles) and subdirectories (also containing an __init__.pyfile) for any sub_packages. When the package is imported a new namespace is created and the package's __init__.pyis executed with that namespace as the local and global namespaces. So to answer your problem we can strip your filestore down by omitting the top-level package, which will never be considered by the interpreter when test.pyis run as a program. It would then look like this:

__init__.py包中的很多功能相同的模块的.py文件。具有结构的被写成一个目录,该目录还可以包含任何 sub_packages 的模块(常规.py文件)和子目录(也包含一个__init__.py文件)。当包被导入时,会创建一个新的命名空间,并__init__.py使用该命名空间作为本地和全局命名空间来执行包。所以为了回答你的问题,我们可以通过省略顶级包来剥离你的文件存储,当test.py作为程序运行时,解释器永远不会考虑它。然后它看起来像这样:

test.py
subpackage/
    __init__.py
    hello_world.py

Now, subpackageis no longer a sub-package, as we have removed the containing package as irrelevant. Focusing on why the do_somethingname is undefined might help. test.pydoes not contain any import, and so it's unclear how you are expecting do_somethingto acquire meaning. You could make it work by using an empty subpackage/__init__.pyand then test.pycould read

现在,subpackage不再是子包,因为我们已经删除了包含不相关的包。关注do_something名称未定义的原因可能会有所帮助。test.py不包含任何导入,因此不清楚您希望do_something如何获得意义。您可以通过使用空来使其工作subpackage/__init__.py,然后test.py可以读取

from subpackage.hello_world import do_something
do_something()

Alternatively you could us a subpackage/__init__.pythat reads

或者你可以给我们subpackage/__init__.py

from hello_world import do_something

which establishes the do_somethingfunction inside the subpackagenamespace when the package is imported. Then use a test.pythat imports the function from the package, like this:

它在导入包时在命名空间do_something内建立函数subpackage。然后使用test.py从包中导入函数的a ,如下所示:

from subpackage import do_something
do_something()

A final alternative with the same __init__.pyis to use a test.pythat simply imports the (sub)package and then use relative naming to access the required function:

最后一种替代方法__init__.py是使用 atest.py简单地导入(子)包,然后使用相对命名来访问所需的功能:

import subpackage
subpackage.do_something()

to gain access to it in your local namespace

在您的本地命名空间中访问它

With the empty __init__.pythis could also be achieved with a test.pyreading

有了空,__init__.py这也可以通过test.py阅读来实现

import subpackage.hello_world
subpackage.hello_world.do_something()

or even

甚至

from subpackage.hello_world import do_something
do_something()

Ultimately the best tool to keep you straight is a clear understanding of how import works and what effect its various forms have on the importing namespace.

最终,让您保持正直的最佳工具是清楚地了解导入的工作原理以及其各种形式对导入命名空间的影响。

回答by evuez

First, you have to understand how importalone work:

首先,您必须了解import单独工作的方式:

import test.submodule.do_something

Would try to load do_somethingfrom submoduleitself loaded from test.

会尝试do_somethingsubmodule自身加载从test.

You want to load something from subpackage, so start with that:

你想从 加载一些东西subpackage,所以从它开始:

import subpackage

Fine, subpackage/__init__.pyis loaded.

很好,subpackage/__init__.py已加载。

Now, you want the do_something()function which is in the file (a "module") hello_world.py. Easy:

现在,您需要do_something()文件(“模块”)中的函数hello_world.py。简单:

from subpackage.hello_world import do_something

And you are done! Just read this line loud, it does exactly what it says: import do_somethingfrom the module hello_worldwhich is in the subpackagepackage.

你已经完成了!刚读到这响亮,它不正是它说:进口do_something从模块hello_world这是在subpackage包中。

Try that in test.py

试试看 test.py

from subpackage.hello_world import do_something

do_something()

It should work just fine.

它应该工作得很好。

Now, the second issue:

现在,第二个问题:

__init__.pywon't be called in package/since you don't use package/as a package. __init__.pywill be used if you do an import of package/or anything in it, for eg:

__init__.py不会被调用,package/因为您不用package/作包。__init__.py如果您执行导入package/或其中的任何操作,将使用,例如:

from package import test

Otherwise, it won't be loaded at all.

否则,它根本不会被加载。

However, if you want to load do_something()on the import of subpackage, put from submodule.hello_word import do_somethingin subpackage/__init__.py, and then, in you test.py, do a import subpackage.

但是,如果你想负载do_something()上分装的进口,把from submodule.hello_word import do_somethingsubpackage/__init__.py,然后,在你test.py,做一个import subpackage

回答by Daniel Roseman

It's an absolute hard-and-fast rule in Python that a name must always be defined or imported within the module where you're using it. Here you never import anything inside test.py - so as the error says, do_somethingis not defined.

在 Python 中,必须始终在使用名称的模块中定义或导入名称,这是绝对的硬性规定。在这里,您永远不会在 test.py 中导入任何内容 - 正如错误所说,do_something未定义。

Even if your package/__init__.pyfile was executed (which, as others have pointed out, it isn't), your code still wouldn't work as it is, because the import of do_somethinghas to be done inside test.py if you want to reference it in that file.

即使您的package/__init__.py文件被执行(正如其他人指出的那样,它不是),您的代码仍然无法正常工作,因为do_something如果您想引用它,则必须在 test.py 中完成导入在那个文件中。