Python 第 10 亿次相对进口
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14132789/
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
Relative imports for the billionth time
提问by
I've been here:
我来过这里:
- 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
- http://www.python.org/dev/peps/pep-0328/
- http://docs.python.org/2/tutorial/modules.html#packages
- Python 包:相对导入
- python相对导入示例代码不起作用
- 相对python导入的终极答案
- Python 中的相对导入
- Python:禁用相对导入
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.
以及许多我没有复制的 URL,一些在 SO 上,一些在其他网站上,当我以为我会很快找到解决方案时又回来了。
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:
永远反复出现的问题是:在 Windows 7、32 位 Python 2.7.3 中,如何解决此“在非包中尝试相对导入”消息?我在 pep-0328 上构建了该包的精确副本:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
The imports were done from the console.
导入是从控制台完成的。
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:
我确实在相应的模块中创建了名为 spam 和 egg 的函数。自然,它没有用。答案显然在我列出的第 4 个 URL 中,但对我来说都是校友。我访问过的其中一个 URL 上有这样的回复:
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.
相对导入使用模块的名称属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它被设置为“main”),则相对导入将被解析为好像该模块是顶级模块,而不管该模块实际位于文件系统上的哪个位置。
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 不返回给我“在非包中尝试相对导入”?据说有一个涉及-m的答案。
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.
有人可以告诉我为什么 Python 会给出该错误消息,“非包”是什么意思,你为什么以及如何定义“包”,以及用足够容易让幼儿园儿童理解的术语的准确答案。
采纳答案by BrenBarn
Script vs. Module
脚本与模块
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 认为它在哪个包中。另外,这取决于您如何将文件加载到 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.pyon the command line. It is loaded as a module if you do python -m myfile, or if it is loaded when an importstatement 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.
有两种方法可以加载 Python 文件:作为顶级脚本,或者作为模块。如果直接执行文件,例如通过python myfile.py在命令行上键入,则文件将作为顶级脚本加载。如果您这样做python -m myfile,它会作为模块加载,或者如果import在其他文件中遇到语句时加载它。一次只能有一个顶级脚本;顶级脚本是您运行的 Python 文件。
Naming
命名
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.
加载文件时,会为其指定一个名称(存储在其__name__属性中)。如果它是作为顶级脚本加载的,则其名称为__main__. 如果它是作为模块加载的,它的名称是文件名,前面是它所属的任何包/子包的名称,用点分隔。
So for instance in your example:
因此,例如在您的示例中:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
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 runmoduleXfrom the command line, its name will instead be __main__, and if you directly run moduleAfrom 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__.
如果您导入moduleX(注意:已导入,未直接执行),其名称将为package.subpackage1.moduleX. 如果您导入moduleA,其名称将是package.moduleA. 但是,如果您直接从命令行运行moduleX,其名称将改为__main__,如果您直接从命令行运行moduleA,其名称将是__main__. 当一个模块作为顶级脚本运行时,它会失去它的正常名称,而它的名称是__main__.
Accessing a module NOT through its containing package
不通过其包含的包访问模块
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/subpackage1and then do import moduleX, the name of moduleXwill 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 解释器package/subpackage1然后执行import moduleX,则名称moduleX将是moduleX,而不是package.subpackage1.moduleX。这是因为 Python 在启动时将当前目录添加到其搜索路径中;如果在当前目录中找到要导入的模块,则不会知道该目录是包的一部分,包信息也不会成为模块名称的一部分。
A special case is if you run the interpreter interactively (e.g., just type pythonand start entering Python code on the fly). In this case the name of that interactive session is __main__.
一种特殊情况是,如果您以交互方式运行解释器(例如,只需键入python并开始即时输入 Python 代码)。在这种情况下,该交互式会话的名称是__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:
现在看看您在问题中包含的引用:
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.
相对导入使用模块的名称属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它被设置为“main”),则相对导入将被解析为好像该模块是顶级模块,而不管该模块实际位于文件系统上的哪个位置。
Relative imports...
相对进口...
Relative imports use the module's nameto 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 ..moduleAwould mean package.moduleA. For a from .. importto work, the module's name must have at least as many dots as there are in the importstatement.
相对导入使用模块的名称来确定它在包中的位置。当您使用诸如 之类的相对导入时from .. import foo,点表示在包层次结构中增加一些级别。例如,如果您当前模块的名称是package.subpackage1.moduleX,则..moduleA表示package.moduleA. 要使 afrom .. import起作用,模块名称的点数必须至少与import语句中的点数一样多。
... are only relative in a package
...仅在一个包中是相对的
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 .. importstatements inside it. If you try to do so, you will get the "relative-import in non-package" error.
但是,如果您的模块的名称是__main__,则不会将其视为在包中。它的名称没有点,因此您不能from .. import在其中使用语句。如果您尝试这样做,您将收到“非包中的相对导入”错误。
Scripts can't import relative
脚本无法导入相对
What you probably did is you tried to run moduleXor 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.
您可能所做的是尝试从命令行运行moduleX或类似操作。执行此操作时,其名称设置为__main__,这意味着其中的相关导入将失败,因为其名称并未表明它在包中。请注意,如果您从模块所在的同一目录中运行 Python,然后尝试导入该模块,也会发生这种情况,因为如上所述,Python 会“过早”地在当前目录中找到该模块而没有意识到它是包的一部分。
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.
还要记住,当您运行交互式解释器时,该交互式会话的“名称”始终是__main__. 因此,您不能直接从交互式会话中进行相对导入。相对导入仅用于模块文件中。
Two solutions:
两种解决方案:
If you really do want to run
moduleXdirectly, but you still want it to be considered part of a package, you can dopython -m package.subpackage1.moduleX. The-mtells Python to load it as a module, not as the top-level script.Or perhaps you don't actually want to run
moduleX, you just want to run some other script, saymyfile.py, that usesfunctions insidemoduleX. If that is the case, putmyfile.pysomewhere else– notinside thepackagedirectory – and run it. If insidemyfile.pyyou do things likefrom package.moduleA import spam, it will work fine.
如果您确实想
moduleX直接运行,但仍希望将其视为包的一部分,则可以执行python -m package.subpackage1.moduleX. 该-m告诉Python来加载它作为一个模块,而不是顶级的脚本。或许你并不真的想运行
moduleX,你只是想运行其他一些脚本,说myfile.py,那使用函数中moduleX。如果是这样的话,把myfile.py其他地方-没有内部package目录-并运行它。如果myfile.py你在里面做这样的事情from package.moduleA import spam,它会工作得很好。
Notes
笔记
For either of these solutions, the package directory (
packagein 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.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__isNone.)
对于这些解决方案中的任何一个,
package必须可以从 Python 模块搜索路径 (sys.path)访问包目录(在您的示例中)。如果不是,您将根本无法可靠地使用包中的任何内容。自 Python 2.6 起,用于包解析目的的模块“名称”不仅由其
__name__属性决定,还由__package__属性决定。这就是为什么我避免使用显式符号__name__来引用模块的“名称”。由于 Python 2.6 模块的“名称”实际上是__package__ + '.' + __name__,或者只是__name__如果__package__是None。)
回答by theodox
__name__changes depending on whether the code in question is run in the global namespace or as part of an imported module.
__name__更改取决于相关代码是在全局命名空间中运行还是作为导入模块的一部分运行。
If the code is not running in the global space, __name__will be the name of the module. If it is running in global namespace -- for example, if you type it into a console, or run the module as a script using python.exe yourscriptnamehere.pythen __name__becomes "__main__".
如果代码不在全局空间中运行,__name__将是模块的名称。如果它在全局命名空间中运行——例如,如果您在控制台中键入它,或者使用python.exe yourscriptnamehere.pythen__name__将模块作为脚本运行"__main__"。
You'll see a lot of python code with if __name__ == '__main__'is used to test whether the code is being run from the global namespace – that allows you to have a module that doubles as a script.
你会看到很多 python 代码 if __name__ == '__main__'用于测试代码是否从全局命名空间运行——这允许你拥有一个兼作脚本的模块。
Did you try to do these imports from the console?
您是否尝试从控制台进行这些导入?
回答by Federico
Here is one solution that I would not recommend, but might be useful in some situations where modules were simply not generated:
这是我不推荐的一种解决方案,但在某些根本不生成模块的情况下可能很有用:
import os
import sys
parent_dir_name = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(parent_dir_name + "/your_dir")
import your_script
your_script.a_function()
回答by Lars
I had a similar problem where I didn't want to change the Python module search path and needed to load a module relatively from a script(in spite of "scripts can't import relative with all"as BrenBarn explained nicely above).
我有一个类似的问题,我不想更改 Python 模块搜索路径,并且需要从脚本相对加载模块(尽管BrenBarn 在上面很好地解释了“脚本不能相对于所有导入”)。
So I used the following hack. Unfortunately, it relies on the impmodule that
became deprecated since version 3.4 to be dropped in favour of importlib.
(Is this possible with importlib, too? I don't know.) Still, the hack works for now.
所以我使用了以下技巧。不幸的是,它依赖于imp自 3.4 版以来已弃用的模块以支持importlib. (这也可以用importlib吗?我不知道。)不过,这个 hack 暂时有效。
Example for accessing members of moduleXin subpackage1from a script residing in the subpackage2folder:
从驻留在文件夹中的脚本访问moduleXin成员的示例:subpackage1subpackage2
#!/usr/bin/env python3
import inspect
import imp
import os
def get_script_dir(follow_symlinks=True):
"""
Return directory of code defining this very function.
Should work from a module as well as from a script.
"""
script_path = inspect.getabsfile(get_script_dir)
if follow_symlinks:
script_path = os.path.realpath(script_path)
return os.path.dirname(script_path)
# loading the module (hack, relying on deprecated imp-module)
PARENT_PATH = os.path.dirname(get_script_dir())
(x_file, x_path, x_desc) = imp.find_module('moduleX', [PARENT_PATH+'/'+'subpackage1'])
module_x = imp.load_module('subpackage1.moduleX', x_file, x_path, x_desc)
# importing a function and a value
function = module_x.my_function
VALUE = module_x.MY_CONST
A cleaner approach seems to be to modify the sys.path used for loading modules as mentioned by Federico.
一种更简洁的方法似乎是修改 Federico 提到的用于加载模块的 sys.path。
#!/usr/bin/env python3
if __name__ == '__main__' and __package__ is None:
from os import sys, path
# __file__ should be defined in this case
PARENT_DIR = path.dirname(path.dirname(path.abspath(__file__)))
sys.path.append(PARENT_DIR)
from subpackage1.moduleX import *
回答by torek
Here's a general recipe, modified to fit as an example, that I am using right now for dealing with Python libraries written as packages, that contain interdependent files, where I want to be able to test parts of them piecemeal. Let's call this lib.fooand say that it needs access to lib.fileAfor functions f1and f2, and lib.fileBfor class Class3.
这是一个通用配方,经过修改以适合作为示例,我现在正在使用它来处理编写为包的 Python 库,其中包含相互依赖的文件,我希望能够在其中逐个测试它们的一部分。让我们调用它lib.foo并说它需要访问lib.fileAfor 函数f1和f2, 和lib.fileB类Class3。
I have included a few printcalls to help illustrate how this works. In practice you would want to remove them (and maybe also the from __future__ import print_functionline).
我已经包含了一些print调用来帮助说明这是如何工作的。在实践中,您可能希望删除它们(也可能是该from __future__ import print_function行)。
This particular example is too simple to show when we really need to insert an entry into sys.path. (See Lars' answerfor a case where we doneed it, when we have two or more levels of package directories, and then we use os.path.dirname(os.path.dirname(__file__))—but it doesn't really hurthere either.) It's also safe enough to do this without the if _i in sys.pathtest. However, if each imported file inserts the same path—for instance, if both fileAand fileBwant to import utilities from the package—this clutters up sys.pathwith the same path many times, so it's nice to have the if _i not in sys.pathin the boilerplate.
这个特殊的例子太简单了,无法说明我们何时真正需要在sys.path. (在我们确实需要它的情况下,请参阅Lars 的回答,当我们有两个或更多级别的包目录时,然后我们使用- 但在这里也没有真正受到伤害。)如果没有测试。但是,如果每个导入文件插入相同的路径-例如,如果两个并希望导入实用程序从包中,这个杂波了具有相同路径很多次,所以很高兴有在样板。os.path.dirname(os.path.dirname(__file__))if _i in sys.pathfileAfileBsys.pathif _i not in sys.path
from __future__ import print_function # only when showing how this works
if __package__:
print('Package named {!r}; __name__ is {!r}'.format(__package__, __name__))
from .fileA import f1, f2
from .fileB import Class3
else:
print('Not a package; __name__ is {!r}'.format(__name__))
# these next steps should be used only with care and if needed
# (remove the sys.path manipulation for simple cases!)
import os, sys
_i = os.path.dirname(os.path.abspath(__file__))
if _i not in sys.path:
print('inserting {!r} into sys.path'.format(_i))
sys.path.insert(0, _i)
else:
print('{!r} is already in sys.path'.format(_i))
del _i # clean up global name space
from fileA import f1, f2
from fileB import Class3
... all the code as usual ...
if __name__ == '__main__':
import doctest, sys
ret = doctest.testmod()
sys.exit(0 if ret.failed == 0 else 1)
The idea here is this (and note that these all function the same across python2.7 and python 3.x):
这里的想法是这样的(请注意,这些在 python2.7 和 python 3.x 中的功能都相同):
If run as
import liborfrom lib import fooas a regular package import from ordinary code,__packageisliband__name__islib.foo. We take the first code path, importing from.fileA, etc.If run as
python lib/foo.py,__package__will be None and__name__will be__main__.We take the second code path. The
libdirectory will already be insys.pathso there is no need to add it. We import fromfileA, etc.If run within the
libdirectory aspython foo.py, the behavior is the same as for case 2.If run within the
libdirectory aspython -m foo, the behavior is similar to cases 2 and 3. However, the path to thelibdirectory is not insys.path, so we add it before importing. The same applies if we run Python and thenimport foo.(Since
.isinsys.path, we don't really need to add the absolute version of the path here. This is where a deeper package nesting structure, where we want to dofrom ..otherlib.fileC import ..., makes a difference. If you're not doing this, you can omit all thesys.pathmanipulation entirely.)
如果作为
import lib或from lib import foo作为从普通代码导入的常规包运行,__packageislib和__name__islib.foo。我们采用第一个代码路径,从.fileA等导入。如果运行为
python lib/foo.py,__package__将是 None 并且__name__将是__main__。我们采用第二个代码路径。该
lib目录已经存在,sys.path因此无需添加它。我们从fileA等进口。如果在
lib目录中运行python foo.py,则行为与情况 2 相同。如果在
libas 目录中运行python -m foo,则行为类似于情况 2 和 3。但是,该lib目录的路径不在 中sys.path,因此我们在导入之前添加它。如果我们运行 Python 然后import foo.(由于
.是在sys.path,我们并不真正需要添加此路径的绝对的版本。这是一个更深层次的包嵌套结构,我们想要做的from ..otherlib.fileC import ...,有差别。如果你不这样做,就可以在sys.path完全省略所有操作。)
Notes
笔记
There is still a quirk. If you run this whole thing from outside:
仍然有一个怪癖。如果你从外面运行这整个事情:
$ python2 lib.foo
or:
或者:
$ python3 lib.foo
the behavior depends on the contents of lib/__init__.py. If that exists and is empty, all is well:
行为取决于 的内容lib/__init__.py。如果存在并且为空,则一切正常:
Package named 'lib'; __name__ is '__main__'
But if lib/__init__.pyitselfimports routineso that it can export routine.namedirectly as lib.name, you get:
但是如果lib/__init__.py它本身导入routine以便它可以routine.name直接导出为lib.name,你会得到:
$ python2 lib.foo
Package named 'lib'; __name__ is 'lib.foo'
Package named 'lib'; __name__ is '__main__'
That is, the module gets imported twice, once via the package and then again as __main__so that it runs your maincode. Python 3.6 and later warn about this:
也就是说,模块被导入两次,一次通过包,然后再一次,__main__以便它运行您的main代码。Python 3.6 及更高版本对此发出警告:
$ python3 lib.routine
Package named 'lib'; __name__ is 'lib.foo'
[...]/runpy.py:125: RuntimeWarning: 'lib.foo' found in sys.modules
after import of package 'lib', but prior to execution of 'lib.foo';
this may result in unpredictable behaviour
warn(RuntimeWarning(msg))
Package named 'lib'; __name__ is '__main__'
The warningis new, but the warned-about behavior is not. It is part of what some call the double import trap. (For additional details see issue 27487.) Nick Coghlan says:
该警告是新的,但警告说,有关的行为是不能。它是某些人所说的双重导入陷阱的一部分。(有关更多详细信息,请参阅issue 27487。)Nick Coghlan 说:
This next trap exists in all current versions of Python, including 3.3, and can be summed up in the following general guideline: "Never add a package directory, or any directory inside a package, directly to the Python path".
下一个陷阱存在于所有当前版本的 Python 中,包括 3.3,可以总结为以下一般准则:“永远不要将包目录或包内的任何目录直接添加到 Python 路径”。
Note that while we violate that rule here, we do it onlywhen the file being loaded is notbeing loaded as part of a package, and our modification is specifically designed to allow us to access other files in that package. (And, as I noted, we probably shouldn't do this at all for single level packages.) If we wanted to be extra-clean, we might rewrite this as, e.g.:
请注意,虽然我们在这里违反了该规则,但我们仅在加载的文件不是作为包的一部分加载时才这样做,并且我们的修改专门设计为允许我们访问该包中的其他文件。(而且,正如我所指出的,我们可能根本不应该对单级包执行此操作。)如果我们想要更加干净,我们可以将其重写为,例如:
import os, sys
_i = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if _i not in sys.path:
sys.path.insert(0, _i)
else:
_i = None
from sub.fileA import f1, f2
from sub.fileB import Class3
if _i:
sys.path.remove(_i)
del _i
That is, we modify sys.pathlong enough to achieve our imports, then put it back the way it was (deleting one copy of _iif and only if we added one copy of _i).
也就是说,我们修改sys.path足够长的时间以实现我们的导入,然后将其恢复原样(_i当且仅当我们添加 的一个副本时删除一个副本_i)。
回答by ec2604
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.
相对导入使用模块的名称属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它被设置为“main”),则相对导入将被解析为好像该模块是顶级模块,而不管该模块实际位于文件系统上的哪个位置。
Wrote a little python package to PyPi that might help viewers of this question. The package acts as workaround if one wishes to be able to run python files containing imports containing upper level packages from within a package / project without being directly in the importing file's directory. https://pypi.org/project/import-anywhere/
给 PyPi 写了一个小 python 包,可能会帮助这个问题的观众。如果希望能够从包/项目中运行包含包含上层包的导入的 python 文件,而无需直接在导入文件的目录中,则该包可作为解决方法。https://pypi.org/project/import-anywhere/
回答by Rami Ka.
This is really a problem within python. The origin of confusion is that people mistakenly takes the relative import as path relative which is not.
这确实是python中的一个问题。混淆的根源在于人们错误地将相对导入视为路径相对而并非如此。
For example when you write in faa.py:
例如,当您在faa.py 中编写时:
from .. import foo
This has a meaning only if faa.pywas identified and loadedby python, during execution, as a part of a package. In that case,the module's namefor faa.pywould be for example some_packagename.faa. If the file was loaded just because it is in the current directory, when python is run, then its name would not refer to any package and eventually relative import would fail.
这具有只有一个意思faa.py被识别并加载由蟒,在执行期间,作为一个包的一部分。在这种情况下,该模块的名称为faa.py将是例如some_packagename.faa。如果文件只是因为它在当前目录中而被加载,那么当 python 运行时,它的名称将不会引用任何包,最终相对导入将失败。
A simple solution to refer modules in the current directory, is to use this:
在当前目录中引用模块的一个简单解决方案是使用这个:
if __package__ is None or __package__ == '':
# uses current directory visibility
import foo
else:
# uses current package visibility
from . import foo
回答by Steve L
So after carping about this along with many others, I came across a note posted by Dorian Bin this articlethat solved the specific problem I was having where I would develop modules and classes for use with a web service, but I also want to be able to test them as I'm coding, using the debugger facilities in PyCharm. To run tests in a self-contained class, I would include the following at the end of my class file:
因此,在与许多其他人一起讨论了这一点之后,我发现了Dorian B在本文中发布的一条说明,该说明解决了我在开发用于 Web 服务的模块和类时遇到的特定问题,但我也想成为能够在我编码时使用 PyCharm 中的调试器工具测试它们。要在自包含类中运行测试,我将在类文件的末尾包含以下内容:
if __name__ == '__main__':
# run test code here...
but if I wanted to import other classes or modules in the same folder, I would then have to change all my import statements from relative notation to local references (i.e. remove the dot (.)) But after reading Dorian's suggestion, I tried his 'one-liner' and it worked! I can now test in PyCharm and leave my test code in place when I use the class in another class under test, or when I use it in my web service!
但是如果我想在同一文件夹中导入其他类或模块,那么我必须将所有导入语句从相对符号更改为本地引用(即删除点 (.))但是在阅读了 Dorian 的建议之后,我尝试了他的 '单线',它奏效了!我现在可以在 PyCharm 中进行测试,并在我在另一个被测类中使用该类或在我的 Web 服务中使用它时保留我的测试代码!
# import any site-lib modules first, then...
import sys
parent_module = sys.modules['.'.join(__name__.split('.')[:-1]) or '__main__']
if __name__ == '__main__' or parent_module.__name__ == '__main__':
from codex import Codex # these are in same folder as module under test!
from dblogger import DbLogger
else:
from .codex import Codex
from .dblogger import DbLogger
The if statement checks to see if we're running this module as mainor if it's being used in another module that's being tested as main. Perhaps this is obvious, but I offer this note here in case anyone else frustrated by the relative import issues above can make use of it.
if 语句检查我们是否将此模块作为main运行,或者它是否正在另一个被测试为main 的模块中使用。也许这很明显,但我在此提供此说明,以防其他对上述相关导入问题感到沮丧的人可以使用它。
回答by Sakshi Jain
To make Python not return to me "Attempted relative import in non-package". package/
为了让 Python 不返回给我“在非包中尝试相对导入”。包裹/
init.py subpackage1/ init.py moduleX.py moduleY.py subpackage2/ init.py moduleZ.py moduleA.py
init.py subpackage1/ init.py moduleX.py moduleY.py subpackage2/ init.py moduleZ.py moduleA.py
This error occurs only if you are applying relative import to the parent file. For example parent file already returns mainafter you code "print(name)" in moduleA.py .so THIS file is already mainit cannot return any parent package further on. relative imports are required in files of packages subpackage1 and subpackage2 you can use ".." to refer to the parent directory or module .But parent is if already top level package it cannot go further above that parent directory(package). Such files where you are applying relative importing to parents can only work with the application of absolute import. If you will use ABSOLUTE IMPORT IN PARENT PACKAGE NO ERROR will come as python knows who is at the top level of package even if your file is in subpackages because of the concept of PYTHON PATH which defines the top level of the project
仅当您对父文件应用相对导入时才会出现此错误。例如,在 moduleA.py 中编码“print( name)”后,父文件已经返回main。所以这个文件已经是main它不能进一步返回任何父包。在包 subpackage1 和 subpackage2 的文件中需要相对导入,您可以使用“..”来引用父目录或模块。您将相对导入应用于父级的此类文件只能与绝对导入的应用程序一起使用。如果您将使用 ABSOLUTE IMPORT IN PARENT PACKAGE NO ERROR will come as python知道谁在包的顶层,即使您的文件在子包中,因为 PYTHON PATH 的概念定义了项目的顶层
回答by Brad Dre
@BrenBarn's answer says it all, but if you're like me it might take a while to understand. Here's my case and how @BrenBarn's answer applies to it, perhaps it will help you.
@BrenBarn 的回答说明了一切,但如果您像我一样可能需要一段时间才能理解。这是我的案例以及@BrenBarn 的答案如何适用于它,也许它会对您有所帮助。
The case
案子
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
Using our familiar example, and add to it that moduleX.py has a relative import to ..moduleA. Given that I tried writing a test script in the subpackage1 directory that imported moduleX, but then got the dreaded error described by the OP.
使用我们熟悉的示例,并向其中添加 moduleX.py 对 ..moduleA 的相对导入。鉴于我尝试在导入 moduleX 的 subpackage1 目录中编写测试脚本,但随后出现了 OP 描述的可怕错误。
Solution
解决方案
Move test script to the same level as package and import package.subpackage1.moduleX
将测试脚本移动到与包相同的级别并导入 package.subpackage1.moduleX
Explanation
解释
As explained, relative imports are made relative to the current name. When my test script imports moduleX from the same directory, then module name inside moduleX is moduleX. When it encounters a relative import the interpreter can't back up the package hierarchy because it's already at the top
如前所述,相对导入是相对于当前名称进行的。当我的测试脚本从同一目录导入 moduleX 时,moduleX 中的模块名称是 moduleX。当遇到相对导入时,解释器无法备份包层次结构,因为它已经在顶部
When I import moduleX from above, then name inside moduleX is package.subpackage1.moduleX and the relative import can be found
当我从上面导入moduleX时,moduleX里面的名字是package.subpackage1.moduleX,可以找到相对导入

