Python 3 中的相对导入不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/16637428/
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 import in Python 3 is not working
提问by John Smith Optional
I have the following directory:
我有以下目录:
mydirectory
├── __init__.py
├── file1.py 
└── file2.py
I have a function f defined in file1.py.
我在 file1.py 中定义了一个函数 f。
If, in file2.py, I do
如果在 file2.py 中,我这样做
from .file1 import f
I get the following error:
我收到以下错误:
SystemError: Parent module '' not loaded, cannot perform relative import
SystemError: 父模块 '' 未加载,无法执行相对导入
Why? And how to make it work?
为什么?以及如何让它发挥作用?
采纳答案by mrKelley
since file1and file2are in the same directory, you don't even need to have an __init__.pyfile.  If you're going to be scaling up, then leave it there.
由于file1和file2位于同一目录中,因此您甚至不需要__init__.py文件。如果你要扩大规模,那就把它留在那里。
To import something in a file in the same directory, just do like this
要在同一目录中的文件中导入某些内容,只需这样做
from file1 import f
from file1 import f
i.e., you don't need to do the relative path .file1because they are in the same directory.
即,您不需要执行相对路径,.file1因为它们在同一目录中。
If your main function, script, or whatever, that will be running the whole application is in another directory, then you will have to make everything relative to wherever that is being executed.
如果将运行整个应用程序的主函数、脚本或其他任何内容都在另一个目录中,那么您将必须使所有内容都与正在执行的位置相关。
回答by stalk
When launching a python source file, it is forbidden to import another file, that is in the current package, using relative import.
启动python源文件时,禁止使用相对导入方式导入当前包中的其他文件。
In documentationit is said:
在文档中是这样说的:
Note that relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.
请注意,相对导入基于当前模块的名称。由于主模块的名称始终为“__main__”,因此用作 Python 应用程序主模块的模块必须始终使用绝对导入。
So, as @mrKelleysaid, you need to use absolute import in such situation.
因此,正如@mrKelley所说,在这种情况下您需要使用绝对导入。
回答by The Demz
myproject/
mypackage
├── __init__.py
├── file1.py
├── file2.py 
└── file3.py
mymainscript.py
Example to import from one file to another
从一个文件导入到另一个文件的示例
#file1.py
from myproject import file2
from myproject.file3 import MyClass
Import the package example to the mainscript
将包示例导入主脚本
#mymainscript.py
import mypackage
https://docs.python.org/3/tutorial/modules.html#packages
https://docs.python.org/3/tutorial/modules.html#packages
https://docs.python.org/3/reference/import.html#regular-packages
https://docs.python.org/3/reference/import.html#regular-packages
https://docs.python.org/3/reference/simple_stmts.html#the-import-statement
https://docs.python.org/3/reference/simple_stmts.html#the-import-statement
https://docs.python.org/3/glossary.html#term-import-path
https://docs.python.org/3/glossary.html#term-import-path
The variable sys.path is a list of strings that determines the interpreter's search path for modules. It is initialized to a default path taken from the environment variable PYTHONPATH, or from a built-in default if PYTHONPATH is not set. You can modify it using standard list operations:
变量 sys.path 是一个字符串列表,用于确定解释器的模块搜索路径。它被初始化为从环境变量 PYTHONPATH 中获取的默认路径,如果未设置 PYTHONPATH,则从内置默认值中初始化。您可以使用标准列表操作修改它:
import sys
sys.path.append('/ufs/guido/lib/python')
sys.path.insert(0, '/ufs/guido/myhaxxlib/python')
Inserting it at the beginning has the benefit of guaranteeing that the path is searched before others (even built-in ones) in the case of naming conflicts.
在开头插入它的好处是可以保证在命名冲突的情况下在其他路径(甚至是内置路径)之前搜索路径。
回答by Bakuriu
Launching modules inside a package as executables is a bad practice.
将包内的模块作为可执行文件启动是一种不好的做法。
When you develop something you either build a library, which is intended to be imported by other programs and thus it doesn't make much sense to allow executing its submodules directly, or you build an executable in which case there's no reason to make it part of a package.
当您开发某些东西时,您要么构建一个库,该库旨在由其他程序导入,因此允许直接执行其子模块没有多大意义,要么构建一个可执行文件,在这种情况下,没有理由将其作为一部分一个包。
This is why in setup.pyyou distinguish between packages and scripts. The packages will go under site-packageswhile the scripts will be installed under /usr/bin(or similar location depending on the OS).
这就是为什么setup.py要区分包和脚本的原因。软件包将site-packages安装,而脚本将安装在/usr/bin(或类似位置,取决于操作系统)。
My recommendation is thus to use the following layout:
因此,我的建议是使用以下布局:
/
├── mydirectory
|    ├── __init__.py
|    ├── file1.py 
└── file2.py
Where file2.pyimports file1.pyas any other code that wants to use the library mydirectory, with an absolute import:
其中file2.py进口file1.py为想要使用该库的任何其他代码mydirectory,具有绝对的进口:
from mydirectory.file1 import f
When you write a setup.pyscript for the project you simply list mydirectoryas a package and file2.pyas a script and everything will work. No need to fiddle with sys.path.
当您setup.py为项目编写脚本时,您只需将其mydirectory作为包和file2.py脚本列出,一切都会正常进行。无需摆弄sys.path.
If you ever, for some reason, really want to actually run a submodule of a package, the proper way to do it is to use the -mswitch:
如果您出于某种原因真的想实际运行包的子模块,那么正确的方法是使用-m开关:
python -m mydirectory.file1
This loads the whole package and then executes the module as a script, allowing the relative import to succeed.
这会加载整个包,然后将模块作为脚本执行,从而使相对导入成功。
I'd personally avoid doing this. Also because a lot of people don't even know you can do this and will end up getting the same error as you and think that the package is broken.
我个人会避免这样做。也因为很多人甚至不知道你可以这样做,最终会得到和你一样的错误,并认为包坏了。
Regarding the currently accepted answer, which says that you should just use an implicitrelative import from file1 import fbecause it will work since they are in the same directory:
关于当前接受的答案,它说您应该只使用隐式相对导入,from file1 import f因为它会起作用,因为它们位于同一目录中:
This is wrong!
这是错误的!
- It will notwork in python3 where implicit relative imports are disallowed and will surely break if you happen to have installed a 
file1module (since it will be imported instead of your module!). Even if it works the
file1will not be seen as part of themydirectorypackage. This canmatter.For example if
file1usespickle, the name of the package is important for proper loading/unloading of data.
- 它会不会在python3工作,其中隐含的相对进口是不允许的,如果你碰巧已经安装了,必将打破
file1模块(因为它将代替进口你的模块!)。 即使它有效,
file1也不会被视为mydirectory包的一部分。这可关系。例如,如果
file1使用pickle,包的名称对于正确加载/卸载数据很重要。

