Python 中的模块导入和 __init__.py

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35727134/
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 16:53:08  来源:igfitidea点击:

module imports and __init__.py in Python

pythonpython-2.7import

提问by Aenaon

I am trying to understand what the best practices are with regards to Python's (v2.7) import mechanics. I have a project that has started to grow a bit and lets say my code is organised as follows:

我试图了解关于 Python (v2.7) 导入机制的最佳实践是什么。我有一个已经开始增长的项目,可以说我的代码组织如下:

foo/
    __init__.py
    Foo.py
    module1.py
    module2.py
    module3.py

The package name is fooand underneath it I have module Foo.pywhich contains code for the class Foo. Hence I am using the same name for the package, module and class which might not be very clever to start with.

包名是foo,在它下面我有Foo.py包含类代码的模块Foo。因此,我对包、模块和类使用相同的名称,这可能不是很聪明。

__init__.pyis empty and class Fooneeds to import module1, module2 and module3hence part of my Foo.pyfile looks like:

__init__.py是空的,Foo需要导入类,module1, module2 and module3因此我的Foo.py文件的一部分看起来像:

# foo/Foo.py

import module1
import module2
import module3

class Foo(object):
    def __init__(self):
....
....
if __name__ == '__main__':
    foo_obj = Foo()

However I later revisited this and I thought it would be better to have all imports in the __init__.pyfile. Hence my __init__.pynow looks like:

但是我后来重新审视了这个,我认为最好在__init__.py文件中包含所有导入。因此我__init__.py现在看起来像:

# foo/__init__.py

import Foo
import module1
import module2
import module3
....
....

and my Foo.pyonly needs to import foo:

Foo.py只需要导入foo

# foo/Foo.py

import foo

While this looks convenient since it is an one liner, I am a bit worried that it might be creating circular imports. What I mean is that when the script Foo.pyis run it will import everything it can and then __init__.pywill be called which will import Foo.pyagain (is that correct?). Additionally using the same name for package, module and class makes things more confusing.

虽然这看起来很方便,因为它是单行的,但我有点担心它可能会创建循环导入。我的意思是,当脚本Foo.py运行时,它将导入所有可以导入的内容,然后__init__.py将被调用,然后Foo.py再次导入(正确吗?)。此外,对包、模块和类使用相同的名称会使事情变得更加混乱。

Does it make sense the way I have done it? Or am I asking for trouble?

我这样做的方式有意义吗?还是我自找麻烦?

回答by Brendan Abel

A couple things you could do to improve your organizaton, if only to adhere to some popular python conventions and standards.

如果只是遵守一些流行的 Python 约定和标准,您可以做一些事情来改善您的组织。

If you search this topic, you will inevitably run across people recommending the PEP8guidelines. These are the de facto canonical standards for organizing python code.

如果您搜索此主题,您将不可避免地遇到推荐PEP8指南的人。这些是组织 Python 代码的事实上的规范标准。

Modules should have short, all-lowercase names. Underscores can be used in the module name if it improves readability. Python packages should also have short, all-lowercase names, although the use of underscores is discouraged.

模块应该有简短的全小写名称。如果可以提高可读性,可以在模块名称中使用下划线。Python 包也应该有简短的、全小写的名称,但不鼓励使用下划线。

Based on these guidelines, your project modules should be named like this:

根据这些指南,您的项目模块应该像这样命名:

foo/
    __init__.py
    foo.py
    module1.py
    module2.py
    module3.py

I find it's generally best to avoid importing modules unnecessarily in __init__.pyunless you're doing it for namespace reasons. For example, if you want the namespace for your package to look like this

我发现通常最好避免不必要地导入模块,__init__.py除非您出于命名空间的原因这样做。例如,如果您希望包的命名空间如下所示

from foo import Foo

instead of

代替

from foo.foo import Foo

Then it makes sense to put

那么把它放在有意义的

from .foo import Foo

in your __init__.py. As your package gets larger, some users may not want to use all of the sub-packages and modules, so it doesn't make sense to force the user to wait for all those modules to load by implicitly importing them in your __init__.py. Also, you have to consider whether you even want module1, module2, and module3as part of your external API. Are they only used by Fooand not intended to be for end users? If they're only used internally, then don't include them in the __init__.py

在您的__init__.py. 随着你的包变大,一些用户可能不想使用所有的子包和模块,所以通过在你的__init__.py. 此外,您还必须考虑是否要将module1module2、 和module3作为外部 API 的一部分。它们是否Foo仅供最终用户使用而不打算供最终用户使用?如果它们仅在内部使用,则不要将它们包含在__init__.py

I'd also recommend using absolute or explicit relative importsfor importing sub-modules. For example, in foo.py

我还建议使用绝对或显式相对导入来导入子模块。例如,在foo.py

Absolute

绝对

from foo import module1
from foo import module2
from foo import module3

Explicit Relative

显式相对

from . import module1
from . import module2
from . import module3

This will prevent any possible naming issues with other packages and modules. It will also make it easier if you decide to support Python3, since the implicit relative import syntax you're currently using is not supported in Python3.

这将防止其他包和模块出现任何可能的命名问题。如果您决定支持 Python3,它也会更容易,因为 Python3 不支持您当前使用的隐式相对导入语法。

Also, files inside your package generally shouldn't contain a

此外,包内的文件通常不应包含

if __name__ == '__main__'

This is because running a file as a script means it won't be considered part of the package that it belongs to, so it won't be able to make relative imports.

这是因为将文件作为脚本运行意味着它不会被视为它所属的包的一部分,因此它将无法进行相对导入。

The best way to provide executable scripts to users is by using the scriptsor console_scriptsfeature of setuptools. The way you organize your scripts can be different depending on which method you use, but I generally organize mine like this:

向用户提供可执行的脚本,最好的方法是使用scriptsconsole_scripts特征setuptools。您组织脚本的方式可能因您使用的方法而异,但我通常这样组织我的:

foo/
    __init__.py
    foo.py
    ...
scripts/
     foo_script.py
setup.py

回答by user812786

According to PEP 0008, "Public and internal interfaces":

根据PEP 0008,“公共和内部接口”

Imported names should always be considered an implementation detail. Other modules must not rely on indirect access to such imported names unless they are an explicitly documented part of the containing module's API, such as os.path or a package's __init__module that exposes functionality from submodules.

导入的名称应始终被视为实现细节。其他模块不得依赖于对此类导入名称的间接访问,除非它们是包含模块 API 的明确记录部分,例如 os.path 或__init__从子模块公开功能的包模块。

So this would suggest that it isok to put imports in the __init__module, if __init__is being used to expose functions from submodules. Hereis a short blog post I found with a couple examples of Pythonic uses of __init__, using imports to make subpackages available at package level.

因此,这将表明它确定把进口的__init__模块,如果__init__被用来从子模块暴露功能。是我发现的一篇简短的博客文章,其中包含几个 Pythonic 使用 的示例__init__,使用导入使子包在包级别可用。

Your example of moving the import statements to __init__in order to have only one import in Foo, does notseem to follow this rule. My interpretation is that the imports in your __init__should be used for externalinterfaces, otherwise, just put your import statements in the file that needs them. This saves you trouble when submodule names change and keeps you from unnecessary or difficult-to-find imports when you add more files that use a different subset of submodules.

你的移动import语句的例子__init__,以只有一个进口的Foo,并不能似乎遵循这个规则。我的解释是,您的导入__init__应该用于外部接口,否则,只需将您的导入语句放在需要它们的文件中即可。这可以在子模块名称更改时为您省去麻烦,并在您添加更多使用不同子模块子集的文件时避免不必要的或难以找到的导入。

As far as circular references, this is definitely possible in Python (for example). I wrote about that before I actually tried your toy example, but to make the example work I had to move Foo.pyup a level, like so:

至于循环引用,这在 Python 中绝对是可能的(例如)。在我实际尝试您的玩具示例之前,我写了相关内容,但是为了使示例工作,我必须Foo.py向上移动一个级别,如下所示:

Foo.py
foo/
    __init__.py
    module1.py
    module2.py
    module3.py

With that setup and some print statements, running python Foo.pygives the output:

使用该设置和一些打印语句,运行python Foo.py会给出输出:

module 1
module 2
module 3
hello Foo constructor

and exits normally. Note that this is due to adding the if __name__ == "__main__"- if you add a print statement outside of that, you can see Python is still loading the module twice. A better solution would be to remove the import from your __init__.py. As I said earlier, that may or may not make sense, depending on what those submodules are.

并正常退出。请注意,这是由于添加了if __name__ == "__main__"- 如果在此之外添加打印语句,您可以看到 Python 仍在加载模块两次。更好的解决方案是从您的__init__.py. 正如我之前所说,这可能有意义也可能没有意义,这取决于这些子模块是什么。

回答by Eagain

You can refer to the 'Style Guide for Python Code' for best practices, the import is kept in the class in that guide.

您可以参考“Python 代码风格指南”以获得最佳实践,导入保存在该指南的类中。

https://www.python.org/dev/peps/pep-0008/#imports

https://www.python.org/dev/peps/pep-0008/#imports

回答by Trishant Pahwa

Try this:

尝试这个:

package1

包1

package1.py

__init__.py

包1.py

__init__.py

package2

包2

test.py

测试文件

package1.py:-

package1.py:-

class abc:
    a = 'hello'
    def print_a(self):
    print(a)

__init__.py:-

__init__.py:-

from .package1 import abc

package2.py:-

package2.py:-

From package1.package1 import abc

I use these __init__.py to import from a package.

我使用这些 __init__.py 从包中导入。

回答by brettb

I can't state definitively if this is the correct way, but I've always done it the former way. That is, I have always kept __init__.pyempty, and just imported things within Foo.pyas needed.

我不能肯定地说这是否是正确的方法,但我一直都是用前一种方法来做的。也就是说,我一直保持__init__.py空白,只是Foo.py根据需要导入其中的东西。

From how you describe it, it does seem like there is some circular logic happening in the latter form.

从您的描述来看,后一种形式似乎确实存在一些循环逻辑。