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

通常,以下工作之一:

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

这是为什么?


当前回答

希望这对外面的人来说是有价值的——我浏览了六篇stackoverflow的帖子,试图找出与上面帖子类似的相对进口。我按照建议设置了所有内容,但仍在运行ModuleNotFoundError:没有名为“my_module_name”的模块

由于我只是在本地开发并四处游玩,所以我没有创建/运行setup.py文件。我显然也没有设置我的巨蟒。

我意识到,当我像以前一样运行代码时,当测试与模块位于同一目录中时,我找不到模块:

$ python3 test/my_module/module_test.py                                                                                                               2.4.0
Traceback (most recent call last):
  File "test/my_module/module_test.py", line 6, in <module>
    from my_module.module import *
ModuleNotFoundError: No module named 'my_module'

然而,当我明确指定路径时,事情就开始工作了:

$ PYTHONPATH=. python3 test/my_module/module_test.py                                                                                                  2.4.0
...........
----------------------------------------------------------------------
Ran 11 tests in 0.001s

OK

因此,如果有人尝试了一些建议,认为他们的代码结构正确,但仍然发现自己处于与我类似的情况,如果您不将当前目录导出到PYTHONPATH,请尝试以下任一操作:

运行代码并显式包含如下路径:$PYTHONPATH=。python3测试/my_module/模块测试.py为了避免调用PYTHONPATH=。,创建一个包含如下内容的setup.py文件,并运行python setup.py开发,将包添加到路径中:

#设置.py从setuptools导入安装程序,find_packages设置(name=“示例”,packages=find_packages())

其他回答

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

包/模块.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

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

我尝试了以上所有方法,但都没有效果,结果发现我的包名中错误地包含了-。

简而言之,在__init__.py所在的目录中不要有-。在发现这样的无意义之后,我从未感到欢欣鼓舞。

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。

仅此而已。

将其放入包的__init__.py文件中:

# For relative imports to work in Python 3.6
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))

假设您的包是这样的:

├── project
│   ├── package
│   │   ├── __init__.py
│   │   ├── module1.py
│   │   └── module2.py
│   └── setup.py

现在在您的包中使用常规导入,例如:

# in module2.py
from module1 import class1

这在python 2和3中都有效。

太长,读不下去了通过在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中运行项目了!!