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

通常,以下工作之一:

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

这是为什么?


当前回答

太长,读不下去了通过在python脚本的入口点添加以下内容,将脚本路径附加到系统路径。

import os.path
import sys
PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))

现在,您可以在PyCharma和Terminal中运行项目了!!

其他回答

TL;博士

您只能相对导入同一包中另一个模块内的模块。

概念澄清

我们在books/docs/articles中看到了很多示例代码,它们向我们展示了如何相对导入模块,但当我们这样做时,它失败了。

原因是,简单地说,我们没有按照python模块机制的预期运行代码,即使代码编写得完全正确。这就像某种运行时的事情。

模块加载取决于您如何运行代码。这就是困惑的根源。

什么是模块?

当且仅当模块被另一个文件导入时,它才是python文件。给定一个文件mod.py,它是一个模块吗?是和否,如果您运行python-mod.py,它不是一个模块,因为它没有导入。

什么是套餐?

包是包含Python模块的文件夹。

顺便说一下,如果您不需要任何包初始化或自动加载子模块,那么python 3.3中不需要__init__.py。您不需要在目录中放置空白__init__.py。

这证明只要有文件被导入,包就只是一个文件夹。


真实答案

现在,这个描述变得更加清晰了。

您只能相对导入同一包中另一个模块内的模块。

给定目录:

. CWD
|-- happy_maker.py # content: print('Sends Happy')
`-- me.py # content: from . import happy_maker

运行python-me.py,我们尝试了没有已知父包的相对导入

me.py是直接运行的,它不是一个模块,我们不能在其中使用相对导入。

解决方案1

使用import happy_maker而不是from。导入happy_maker

解决方案2

将工作目录切换到父文件夹。

. CWD
|-- happy
|   |-- happy_maker.py
    `-- me.py

运行python-m happy.me。

当我们在包含happy的目录中时,happy是一个包,me.py,happy_maker.py是模块,我们现在可以使用相对导入,我们仍然希望运行me.py。所以我们使用-m,这意味着将模块作为脚本运行。


Python习语

. CWD
|-- happy
|   |-- happy_maker.py # content: print('Sends Happy')
|   `-- me.py # content: from . import happy_maker
`-- main.py # content: import happy.me

这种结构就是python习语。main是我们的脚本,Python中的最佳实践。最后,我们到达了那里。


兄弟姐妹或祖父母

另一个常见需求:

.
|-- happy
|   |-- happy_maker.py
|   `-- me.py
`-- sad
    `-- sad_maker.py

我们想在me.py中导入sad_maker,怎么做?

首先,我们需要在同一个包中实现快乐和悲伤,所以我们必须升级到目录级别。然后从。。伤心地在me.py中导入sadmaker。

仅此而已。

如果以上任何一项都不适用,则可以显式指定模块。

目录:

├── Project
│     ├── Dir
│     │    ├── __init__.py
│     │    ├── module.py
│     │    └── standalone.py

解决方案:

#in standalone.py
from Project.Dir.module import ...

module-要导入的模块

我的样板,以使包中的模块具有可独立运行的相对导入。

包/模块.py

## Standalone boilerplate before relative imports
if __package__ is None:                  
    DIR = Path(__file__).resolve().parent
    sys.path.insert(0, str(DIR.parent))
    __package__ = DIR.name

from . import variable_in__init__py
from . import other_module_in_package
...

现在,您可以以任何方式使用模块:

照常运行模块:python-m package.module将其用作模块:python-c“来自包导入模块”独立运行:python package/module.py或者使用shebang(#!/bin/env-python):package/module.py

NB!如果模块与包同名,则使用sys.path.append而不是sys.path.insert将导致难以跟踪的错误。例如my_script/my_script.py

当然,如果您的包层次结构中有较高级别的相对导入,那么这是不够的,但在大多数情况下,这是可以的。

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

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