我有如下目录:
mydirectory
├── __init__.py
├── file1.py
└── file2.py
我在file1.py中定义了一个函数f。
如果我在file2.py中执行以下操作:
from .file1 import f
我遇到了以下错误:
SystemError: 未加载父模块“”,无法执行相对导入
为什么会出现这个错误?如何解决?
将包内的模块作为可执行文件启动是一种不良实践。
在开发时,你可以构建一个库,它旨在被其他程序导入,因此不应该允许直接执行其子模块,或者你可以构建一个可执行文件,在这种情况下,没有理由将其作为包的一部分。
这就是为什么在setup.py
中要区分包和脚本。包将放置在site-packages
下,而脚本将安装在/usr/bin
(或类似位置,具体取决于操作系统)。
我的建议是使用以下布局:
/
├── mydirectory
| ├── __init__.py
| ├── file1.py
└── file2.py
当 file2.py
导入 file1.py
时,它像任何想要使用库 mydirectory
的其他代码一样进行了绝对导入:
from mydirectory.file1 import f
当您为项目编写setup.py
脚本时,只需将mydirectory
列为一个包,将file2.py
列为脚本,一切都会正常工作。无需操作sys.path
。
如果您因某种原因确实想要运行包的子模块,则正确的方法是使用-m
开关:python -m mydirectory.file1
这样加载整个包并将模块作为脚本执行,使得相对导入可以成功。
我个人会避免这样做。另外很多人甚至不知道可以这样做,并且最终会遇到与你一样的错误,并认为包已损坏。
关于当前被接受的答案,它说你应该只使用一个隐式的相对导入from file1 import f
,因为它可以工作,因为它们在同一个目录中:
这是错误的!
file1
模块,它肯定会出错(因为它将被导入而不是您的模块!)。即使它能工作,file1
也不会被视为mydirectory
包的一部分。这可能很重要。
例如,如果file1
使用pickle
,则包的名称对于正确加载/卸载数据非常重要。
test
或 tests
的目录,其中包含所有的测试文件,而实际的源代码则在另一个目录中。 - Bakuriu由于 file1
和 file2
在同一个目录中,因此您甚至不需要有一个 __init__.py
文件。 如果您将要扩展规模,则保留它。
要在同一目录中的文件中导入某些内容,只需像这样操作:
from file1 import f
即,您不需要进行相对路径 .file1
,因为它们在同一个目录中。
如果您的主函数、脚本或整个应用程序的运行位置在另一个目录中,则您必须将所有内容相对于正在执行的位置进行处理。
file1
的文件。 - Jensmyproject/
mypackage
├── __init__.py
├── file1.py
├── file2.py
└── file3.py
mymainscript.py
从一个文件导入到另一个文件的示例
#file1.py
from myproject import file2
from myproject.file3 import MyClass
在主脚本中导入example包
#mymainscript.py
import mypackage
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/simple_stmts.html#the-import-statement
https://docs.python.org/3/glossary.html#term-import-path
变量 sys.path 是一个字符串列表,它确定解释器在模块搜索路径中的查找顺序。它初始化为一个默认路径,该路径取自环境变量 PYTHONPATH,如果未设置 PYTHONPATH,则取自内置默认路径。您可以使用标准列表操作来修改它:import sys
sys.path.append('/ufs/guido/lib/python')
sys.path.insert(0, '/ufs/guido/myhaxxlib/python')
file2.py
吗? - Blenderpython3 file2.py
。 - John Smith Optionalsite-packages
,但脚本应该放在/usr/bin
或类似位置(因此需要使用绝对导入)。应该清楚地区分编写以执行和编写作为库一部分的Python模块之间的区别。 - Bakuriu