Python 3 中的相对导入

relative import in Python 3

假设我的项目结构如下:

myproject
├── calendar.py
├── foo.py
└── __init__.py

在foo.py,我有

from calendar import isleap

我认为在 Python 3.x 中没有使用明确的 .calendar 上面的代码应该加载内置日历模块而不是我自己的日历模块,但显然我的本地 calendar.py 仍在导入并且它抛出错误,因为 mypkg/calendar.py 中没有 'isleap'。为什么我的本地日历模块被导入到这里?

我必须将 calendar.py 重命名为 cal.py 才能完成这项工作..

看来你的路径或目录结构设置有误。

鉴于以下结构,您的日历模块的全名应该是 myproject.calendar。您可以通过打印模块的 __name__ 属性来检查这一点。为此,您的程序用于导入本地模块的路径必须是包含 myproject.

的文件夹
myproject
├── calendar.py
├── foo.py
└── __init__.py

看来您使用的路径实际上是myproject。意思是 calendar.py 变成了根级模块 calendar,而不是 myproject.calendar。 Python 比内置模块更喜欢本地模块,因此导入您的 calendar 模块。

更常见的情况是您可能会这样做。

MyProjectFolder
├── main.py
└── myproject
    ├── calendar.py
    ├── foo.py
    └── __init__.py

然后 运行 你的程序是这样的:

#! /bin/bash
cd /path/to/MyProjectFolder
python main.py

Python 将检查您的本地模块并首先由 import 加载它们。

from calendar import isleap 将首先在您的语言环境包中搜索模块 calendar。如果找不到,它将从内置库中导入 calendar.

from .calendar import isleap 只会从您的语言环境模块 calendar 导入。如果未找到,则引发异常 ImportError.

这就是为什么你应该在包中使用相对导入。

您可以使用类似的技巧来导入内置库而不检查本地模块。但这只是一个技巧。我永远不会在生产中使用它。你最好重命名你的模块 calendar.

import imp, sys
f, pathname, desc = imp.find_module("calendar", sys.path[1:])
calendar = imp.load_module("calendar", f, pathname, desc)
f.close()

from calendar import isleap

from __future__ import absolute_import 是 Python 3 上的默认值。因此 from calendar import isleap 语句导入顶级模块 calendar.

如果您看到其他结果;这意味着要么你没有使用 Python 3,要么你正试图 运行 包内的一个 python 模块作为脚本(myproject 目录本身在 sys.path).如果是后者,那么您的 calendar.py 成为顶级模块并且(由于当前目录位于 sys.path 中的 stdlib 目录之前)from calendar import isleap 从当前目录导入 calendar.py"Never add a package directory, or any directory inside a package, directly to the Python path"

为避免这种情况,请不要直接从 python 包中 运行 模块,例如,不要这样做:cd myproject; python foo.py。改为这样做:python -mmyproject.foo(或者你可以 define what scripts should be run in setup.py or create a similar script manually: from myproject import foo; foo.main())。

如果你想 运行 一个 Python 包作为脚本然后创建 myproject/__main__.py 然后 运行 python -mmyproject.


如果你想在Python3中进行相对导入;明确地做到这一点,例如,在 myproject/foo.py 中:

from .calendar import something

或者进行绝对导入:

from myproject.calendar import something