相对进口数十亿次 [英] Relative imports for the billionth time

查看:86
本文介绍了相对进口数十亿次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我来过这里:

  • http://www.python.org/dev/peps/pep-0328/
  • http://docs.python.org/2/tutorial/modules.html#packages
  • Python packages: relative imports
  • python relative import example code does not work
  • Ultimate answer to relative python imports
  • Relative imports in Python
  • Python: Disabling relative import

以及我没有的大量网址复制,一些在SO上,一些在其他网站上,当我认为我很快就有解决方案时。

and plenty of URLs that I did not copy, some on SO, some on other sites, back when I thought I'd have the solution quickly.

永远反复出现的问题是:使用Windows 7, 32位Python 2.7.3,如何解决这个非包装中尝试相对导入的消息?我在pep-0328上构建了一个包的精确副本:

The forever-recurring question is this: With Windows 7, 32-bit Python 2.7.3, how do I solve this "Attempted relative import in non-package" message? I built an exact replica of the package on pep-0328:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
        moduleY.py
    subpackage2/
        __init__.py
        moduleZ.py
    moduleA.py

我确实在相应的模块中创建了名为spam和eggs的函数。当然,它没有用。答案显然是我列出的第4个网址,但这对我来说都是校友。我访问过的其中一个网址上有此响应:

I did make functions named spam and eggs in their appropriate modules. Naturally, it didn't work. The answer is apparently in the 4th URL I listed, but it's all alumni to me. There was this response on one of the URLs I visited:


相对导入使用模块的name属性来确定模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它设置为'main'),则解析相对导入,就像模块是顶级模块一样,无论模块实际位于文件系统的哪个位置。

Relative imports use a module's name attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to 'main') then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.

以上回应看起来很有希望,但这对我来说都是象形文字。所以我的问题是,我怎么让Python不回到我身​​边试图在非包装中进行相对导入?有一个答案涉及-m,据说。

The above response looks promising, but it's all hieroglyphs to me. So my question, how do I make Python not return to me "Attempted relative import in non-package"? has an answer that involves -m, supposedly.

有人可以告诉我为什么Python会给出错误信息,非包装意味着什么!,为什么以及如何定义'包',以及精确的答案,足以让幼儿园儿童理解

Can somebody please tell me why Python gives that error message, what it Means by non-package!, why and how do you define a 'package', and the precise answer put in terms easy enough for a kindergartener to understand.

编辑:导入是从控制台完成的。

The imports were done from the console.

推荐答案

脚本与模块

以下是对此的解释。简短的版本是直接运行Python文件和从其他地方导入该文件之间存在很大差异。 只知道文件所在的目录并不能确定Python认为它所在的包。另外,这还取决于如何将文件加载到Python中(通过运行或导入)。

Here's an explanation. The short version is that there is a big difference between directly running a Python file, and importing that file from somewhere else. Just knowing what directory a file is in does not determine what package Python thinks it is in. That depends, additionally, on how you load the file into Python (by running or by importing).

加载Python文件有两种方法:作为顶级脚本,或作为
模块。如果直接执行文件,则会将文件作为顶级脚本加载,例如在命令行上键入 python myfile.py 。如果您执行 python -m myfile ,或者在 import 语句时加载它,它将作为模块加载遇到其他一些文件。一次只能有一个顶级脚本;顶级脚本是您开始运行的Python文件。

There are two ways to load a Python file: as the top-level script, or as a module. A file is loaded as the top-level script if you execute it directly, for instance by typing python myfile.py on the command line. It is loaded as a module if you do python -m myfile, or if it is loaded when an import statement is encountered inside some other file. There can only be one top-level script at a time; the top-level script is the Python file you ran to start things off.

命名

加载文件时,会为其指定一个名称(存储在 __ name __ 属性中)。如果它作为顶级脚本加载,则其名称为 __ main __ 。如果它作为模块加载,它的名称是文件名,前面是它所属的任何包/子包的名称,用点分隔。

When a file is loaded, it is given a name (which is stored in its __name__ attribute). If it was loaded as the top-level script, its name is __main__. If it was loaded as a module, its name is the filename, preceded by the names of any packages/subpackages of which it is a part, separated by dots.

所以例如在你的例子中:

So for instance in your example:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

如果您导入 moduleX (注意:导入,未直接执行),其名称为 package.subpackage1.moduleX 。如果您导入 moduleA ,则其名称将为 package.moduleA 。但是,如果从命令行直接运行 <$ em $ c> moduleX ,则其名称将改为 __ main __ ,如果从命令行直接运行 moduleA ,其名称将为 __ main __ 。当模块作为顶级脚本运行时,它将失去其正常名称,而其名称则改为 __ main __

if you imported moduleX (note: imported, not directly executed), its name would be package.subpackage1.moduleX. If you imported moduleA, its name would be package.moduleA. However, if you directly run moduleX from the command line, its name will instead be __main__, and if you directly run moduleA from the command line, its name will be __main__. When a module is run as the top-level script, it loses its normal name and its name is instead __main__.

通过其包含的包访问模块

还有一个问题:模块的名称取决于它是否直接导入从它所在的目录,或通过包导入。如果您在目录中运行Python,并尝试导入同一目录(或其子目录)中的文件,这只会有所不同。例如,如果在目录 package / subpackage1 中启动Python解释器,然后执行 import moduleX ,则名称为 moduleX 将只是 moduleX ,而不是 package.subpackage1.moduleX 。这是因为Python在启动时将当前目录添加到其搜索路径中;如果它在当前目录中找到要导入的模块,它将不知道该目录是包的一部分,并且包信息不会成为模块名称的一部分。

There is an additional wrinkle: the module's name depends on whether it was imported "directly" from the directory it is in, or imported via a package. This only makes a difference if you run Python in a directory, and try to import a file in that same directory (or a subdirectory of it). For instance, if you start the Python interpreter in the directory package/subpackage1 and then do import moduleX, the name of moduleX will just be moduleX, and not package.subpackage1.moduleX. This is because Python adds the current directory to its search path on startup; if it finds the to-be-imported module in the current directory, it will not know that that directory is part of a package, and the package information will not become part of the module's name.

特殊情况是,如果您以交互方式运行解释器(例如,只需键入 python 并立即开始输入Python代码)。在这种情况下,该交互式会话的名称是 __ main __

A special case is if you run the interpreter interactively (e.g., just type python and start entering Python code on the fly). In this case the name of that interactive session is __main__.

现在,这是您的错误消息的关键:如果模块的名称没有点,则不认为它是包的一部分。文件在磁盘上的实际位置并不重要。重要的是它的名称,它的名称取决于你如何加载它。

Now here is the crucial thing for your error message: if a module's name has no dots, it is not considered to be part of a package. It doesn't matter where the file actually is on disk. All that matters is what its name is, and its name depends on how you loaded it.

现在看看你在问题中包含的引用:

Now look at the quote you included in your question:


相对导入使用模块的name属性来确定模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它设置为'main'),则解析相对导入,就像模块是顶级模块一样,无论模块实际位于文件系统的哪个位置。

Relative imports use a module's name attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to 'main') then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.

相对进口......

相对进口使用模块的名称来确定它在包中的位置。当您从.. import foo 使用相对导入(如)时,这些点表示在包层次结构中增加一些级别。例如,如果您当前模块的名称是 package.subpackage1.moduleX ,那么 .. moduleA 将意味着 package.moduleA 。要使从... import 起作用,模块的名称必须至少与 import 声明。

Relative imports use the module's name to determine where it is in a package. When you use a relative import like from .. import foo, the dots indicate to step up some number of levels in the package hierarchy. For instance, if your current module's name is package.subpackage1.moduleX, then ..moduleA would mean package.moduleA. For a from .. import to work, the module's name must have at least as many dots as there are in the import statement.

...只是包中的亲戚

但是,如果您的模块名称是 __ main __ ,则不会将其视为包中。它的名字没有点,因此你不能在其中的.. import 语句中使用。如果您尝试这样做,您将收到非包装中的相对导入错误。

However, if your module's name is __main__, it is not considered to be in a package. Its name has no dots, and therefore you cannot use from .. import statements inside it. If you try to do so, you will get the "relative-import in non-package" error.

脚本无法导入相对

您可能尝试从命令行运行 moduleX 等。执行此操作时,其名称设置为 __ main __ ,这意味着其中的相对导入将失败,因为其名称不会显示它在包中。请注意,如果您从模块所在的同一目录运行Python,然后尝试导入该模块,也会发生这种情况,因为如上所述,Python会在太早找到当前目录中的模块,而不会意识到它是包的一部分。

What you probably did is you tried to run moduleX or the like from the command line. When you did this, its name was set to __main__, which means that relative imports within it will fail, because its name does not reveal that it is in a package. Note that this will also happen if you run Python from the same directory where a module is, and then try to import that module, because, as described above, Python will find the module in the current directory "too early" without realizing it is part of a package.

还要记住,当您运行交互式解释器时,该交互式会话的名称始终为 __ main __ 。因此,您不能直接从交互式会话进行相对导入。相对导入仅用于模块文件。

Also remember that when you run the interactive interpreter, the "name" of that interactive session is always __main__. Thus you cannot do relative imports directly from an interactive session. Relative imports are only for use within module files.

两种解决方案:


  1. 如果你真的想直接运行 moduleX ,但你仍然希望它被视为包的一部分,你可以做 python -m package.subpackage1.moduleX -m 告诉Python将其作为模块加载,而不是作为顶级脚本加载。

  1. If you really do want to run moduleX directly, but you still want it to be considered part of a package, you can do python -m package.subpackage1.moduleX. The -m tells Python to load it as a module, not as the top-level script.

或者您可能实际上并不想运行 moduleX ,您只想运行其他一些脚本,例如 myfile .py moduleX 中使用函数。如果是这种情况,请将 myfile.py 放在其他地方 --- 而不是 package 目录 - 并运行它。如果在 myfile.py 里面你从package.moduleA导入垃圾邮件那样做了之类的东西,它就能正常工作。

Or perhaps you don't actually want to run moduleX, you just want to run some other script, say myfile.py, that uses functions inside moduleX. If that is the case, put myfile.py somewhere else --- not inside the package directory -- and run it. If inside myfile.py you do things like from package.moduleA import spam, it will work fine.

注释


  • 对于这些解决方案中的任何一个,必须可以从Python模块搜索路径访问包目录( package )( sys.path中)。如果不是,您将无法可靠地使用包中的任何内容。

  • For either of these solutions, the package directory (package in your example) must be accessible from the Python module search path (sys.path). If it is not, you will not be able to use anything in the package reliably at all.

从Python 2.6开始,模块的包名名称 - 分辨率的目的不仅取决于其 __ name __ 属性,还取决于 __ package __ 属性。这就是为什么我要避免使用显式符号 __ name __ 来引用模块的名称。从Python 2.6开始,模块的名称实际上是 __ package__ +'。'+ _ ___ __ ,或只是 __ name __ if __ package __ 。)

Since Python 2.6, the module's "name" for package-resolution purposes is determined not just by its __name__ attributes but also by the __package__ attribute. That's why I'm avoiding using the explicit symbol __name__ to refer to the module's "name". Since Python 2.6 a module's "name" is effectively __package__ + '.' + __name__, or just __name__ if __package__ is None.)

这篇关于相对进口数十亿次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆