Python 中的隐式相对导入如何工作?
How do implicit relative imports work in Python?
假设我有以下文件,
pkg/
pkg/__init__.py
pkg/main.py # import string
pkg/string.py # print("Package's string module imported")
现在,如果我 运行 main.py
,它会显示 "Package's string module imported"
。
这是有道理的,并且按照 link 中的声明工作:
"it will first look in the package's directory"
假设我稍微修改了文件结构(添加了一个核心目录):
pkg/
pkg/__init__.py
plg/core/__init__.py
pkg/core/main.py # import string
pkg/string.py # print("Package's string module imported")
现在,如果我 运行 python core/main.py
,它会加载 built-in string
模块。
同样在第二种情况下,如果它必须遵守声明“它将首先在包的目录中查找” 它不应该加载本地 string.py
因为 pkg
是 "package directory"?
我对术语 "package directory" 的理解是特别是 [=59] 的根文件夹 =] 个文件夹 __init__.py
。所以在这种情况下,pkg 就是 "package directory"。它适用于 main.py
以及 core/main.py
等子目录中的文件,因为它是 "package".
的一部分
这在技术上是否正确?
PS:代码段中#
之后的内容是文件的实际内容(没有前导空格)。
包是带有 __init__.py
文件的目录,是的,当在模块搜索路径 上找到时,它们会作为模块 加载。所以 pkg
只是一个可以导入的包,如果父目录在模块搜索路径上.
,则可以将其视为包
但是通过运行将pkg/core/main.py
文件作为脚本,Python将pkg/core
目录添加到模块搜索路径,而不是 pkg
的父目录。现在您的模块搜索路径上确实有一个 __init__.py
文件,但这不是定义包的内容。你只有一个 __main__
模块,与其他任何东西都没有包关系,你不能依赖隐式相对导入。
您有三个选择:
不要 运行 包内的文件作为脚本。将脚本文件 放在包的 之外,并根据需要导入您的包。您可以将它 next 放到 pkg
目录中,或者确保 pkg
目录首先安装到模块搜索路径中已有的目录中,或者通过让您的脚本计算出添加到 sys.path
.
的正确路径
使用-m
command line switch到运行一个模块就好像它是一个脚本。如果您使用 python -m pkg.core
Python 将查找 __main__.py
文件和 运行 作为脚本。 -m
开关会将当前工作目录添加到您的模块搜索路径中,因此您可以在正确的工作目录中使用该命令,一切都会正常进行。或者将您的包安装在模块搜索路径中已有的目录中。
让您的脚本将正确的目录添加到模块搜索路径(基于 os.path.absolute(__file__)
获取当前文件的路径)。考虑到您的脚本 always 名为 __main__
,导入 pkg.core.main
将添加第二个独立的模块对象;你会有两个独立的命名空间。
我还强烈建议不要使用隐式相对导入。您可以通过添加同名的嵌套包或模块来轻松屏蔽顶级模块和包。如果您尝试在 pkg
包中使用 import time
,则 pkg/time.py
会在标准库 time
模块之前找到。相反,使用 显式 相关模块引用的 Python 3 模型;将 from __future__ import absolute_import
添加到您的所有文件,然后使用 from . import <name>
明确说明您的模块是从哪里导入的。
假设我有以下文件,
pkg/
pkg/__init__.py
pkg/main.py # import string
pkg/string.py # print("Package's string module imported")
现在,如果我 运行 main.py
,它会显示 "Package's string module imported"
。
这是有道理的,并且按照 link 中的声明工作:
"it will first look in the package's directory"
假设我稍微修改了文件结构(添加了一个核心目录):
pkg/
pkg/__init__.py
plg/core/__init__.py
pkg/core/main.py # import string
pkg/string.py # print("Package's string module imported")
现在,如果我 运行 python core/main.py
,它会加载 built-in string
模块。
同样在第二种情况下,如果它必须遵守声明“它将首先在包的目录中查找” 它不应该加载本地 string.py
因为 pkg
是 "package directory"?
我对术语 "package directory" 的理解是特别是 [=59] 的根文件夹 =] 个文件夹 __init__.py
。所以在这种情况下,pkg 就是 "package directory"。它适用于 main.py
以及 core/main.py
等子目录中的文件,因为它是 "package".
这在技术上是否正确?
PS:代码段中#
之后的内容是文件的实际内容(没有前导空格)。
包是带有 __init__.py
文件的目录,是的,当在模块搜索路径 上找到时,它们会作为模块 加载。所以 pkg
只是一个可以导入的包,如果父目录在模块搜索路径上.
但是通过运行将pkg/core/main.py
文件作为脚本,Python将pkg/core
目录添加到模块搜索路径,而不是 pkg
的父目录。现在您的模块搜索路径上确实有一个 __init__.py
文件,但这不是定义包的内容。你只有一个 __main__
模块,与其他任何东西都没有包关系,你不能依赖隐式相对导入。
您有三个选择:
不要 运行 包内的文件作为脚本。将脚本文件 放在包的 之外,并根据需要导入您的包。您可以将它 next 放到
pkg
目录中,或者确保pkg
目录首先安装到模块搜索路径中已有的目录中,或者通过让您的脚本计算出添加到sys.path
. 的正确路径
使用
-m
command line switch到运行一个模块就好像它是一个脚本。如果您使用python -m pkg.core
Python 将查找__main__.py
文件和 运行 作为脚本。-m
开关会将当前工作目录添加到您的模块搜索路径中,因此您可以在正确的工作目录中使用该命令,一切都会正常进行。或者将您的包安装在模块搜索路径中已有的目录中。让您的脚本将正确的目录添加到模块搜索路径(基于
os.path.absolute(__file__)
获取当前文件的路径)。考虑到您的脚本 always 名为__main__
,导入pkg.core.main
将添加第二个独立的模块对象;你会有两个独立的命名空间。
我还强烈建议不要使用隐式相对导入。您可以通过添加同名的嵌套包或模块来轻松屏蔽顶级模块和包。如果您尝试在 pkg
包中使用 import time
,则 pkg/time.py
会在标准库 time
模块之前找到。相反,使用 显式 相关模块引用的 Python 3 模型;将 from __future__ import absolute_import
添加到您的所有文件,然后使用 from . import <name>
明确说明您的模块是从哪里导入的。