我想从同一目录中的另一个文件导入一个函数。

通常,以下工作之一:

from .mymodule import myfunction
from mymodule import myfunction

…但另一个给了我一个错误:

ImportError: attempted relative import with no known parent package
ModuleNotFoundError: No module named 'mymodule'
SystemError: Parent module '' not loaded, cannot perform relative import

这是为什么?


当前回答

TL;DR:给@Aya的答案,用pathlib库更新,并为未定义__file__的Jupyter笔记本工作:

要导入在..下定义的my_function/my_Folder_where_the_package_lives/my_package.py关于您编写代码的位置。

然后执行以下操作:

import os
import sys
import pathlib

PACKAGE_PARENT = pathlib.Path(__file__).parent
#PACKAGE_PARENT = pathlib.Path.cwd().parent # if on jupyter notebook
SCRIPT_DIR = PACKAGE_PARENT / "my_Folder_where_the_package_lives"
sys.path.append(str(SCRIPT_DIR))

from my_package import my_function

其他回答

我为Python创建了一个新的实验性导入库:ultraimport

它使程序员能够对导入进行更多的控制,并使其明确无误。此外,当导入失败时,它还会提供更好的错误消息。

它允许您执行相对的、基于文件系统的导入,无论您如何运行代码,也无论您当前的工作目录是什么,这些导入始终有效。运行脚本或模块并不重要。您也不必更改sys.path,这可能会产生其他副作用。

然后你会改变

from .mymodule import myfunction

to

import ultraimport
myfunction = ultraimport('__dir__/mymodule.py', 'myfunction')

这样,即使您将代码作为脚本运行,导入也始终有效。

像这样导入脚本时的一个问题是,后续的相对导入可能会失败。ultraimport有一个内置的预处理器来自动重写相关的导入。

将要导入的文件移动到外部目录有帮助。当主文件在其自己的目录中生成任何其他文件时,这是非常有用的。前任:之前:

Project  
|---dir1  
|-------main.py  
|-------module1.py  

之后:

Project  
|---module1.py  
|---dir1  
|-------main.py  

为了避免这个问题,我设计了一个重新包装包装的解决方案,这对我来说已经奏效了一段时间。它将上层目录添加到lib路径:

import repackage
repackage.up()
from mypackage.mymodule import myfunction

使用智能策略(检查调用堆栈),重新打包可以在各种情况下进行相对导入。

我需要从主项目目录运行python3才能使其正常工作。

例如,如果项目具有以下结构:

project_demo/
├── main.py
├── some_package/
│   ├── __init__.py
│   └── project_configs.py
└── test/
    └── test_project_configs.py

解决方案

我将在文件夹project_demo/中运行python3,然后执行

from some_package import project_configs

值得注意的是,有时是缓存导致了这一切——在将类重新排列到新目录中之后,我尝试了不同的方法,并且在删除__pycache之后,相对导入开始工作__