我有以下目录:
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
,包的名称对于正确加载/卸载数据很重要。
因为file1
和file2
都在同一个目录中,所以你甚至不需要有一个__init__.py
文件。如果你要扩大规模,那就把它留在那里。
要在同一目录中的文件中导入某些内容,只需这样做
from file1 import f
即,您不需要执行相对路径.file1
,因为它们位于同一目录中。
如果将运行整个应用程序的主函数、脚本或其他内容位于另一个目录中,那么您必须使所有内容都与正在执行的位置相关。
myproject/
mypackage
├── __init__.py
├── file1.py
├── file2.py
└── file3.py
mymainscript.py
从一个文件导入到另一个文件的示例
#file1.py
from myproject import file2
from myproject.file3 import MyClass
将包示例导入主脚本
#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')
在开头插入它的好处是在命名冲突的情况下保证在其他路径(甚至是内置路径)之前搜索路径。