假设我有以下文件,
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中的以下语句运行:
“它将首先在包的目录中查找”
假设我稍微修改了文件结构(添加了一个核心目录):
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
,它将加载内置的string
模块。同样在第二种情况下,如果必须遵守“将首先在软件包目录中查找”的语句,是否应该加载本地
string.py
,因为pkg
是“软件包目录”?我对“程序包目录”一词的理解是,它是
__init__.py
文件夹集合的根文件夹。因此,在这种情况下,pkg是“软件包目录”。它适用于main.py
以及core/main.py
等子目录中的文件,因为它是此“包”的一部分。这在技术上正确吗?
PS:代码段中
#
之后的内容是文件的实际内容(无前导空格)。 最佳答案
软件包是带有__init__.py
文件的目录,是的,并且在模块搜索路径中找到时作为模块加载。因此,如果父目录位于模块搜索路径中,则pkg
只是一个包,您可以将其导入并视为包。
但是通过将pkg/core/main.py
文件作为脚本运行,Python将pkg/core
目录添加到了模块搜索路径,而不是pkg
的父目录。现在,您的模块搜索路径上确实有一个__init__.py
文件,但这不是定义包的原因。您只有一个__main__
模块,与其他任何模块都没有包关系,并且您不能依赖隐式相对导入。
您有三种选择:
不要将包中的文件作为脚本运行。将脚本文件放在包外部,然后根据需要导入脚本。您可以将其放在pkg
目录旁边,或者确保先将pkg
目录安装到模块搜索路径上已经存在的目录中,或者确保脚本计算要添加到sys.path
的正确路径。
使用-m
command line switch就像脚本一样运行模块。如果使用python -m pkg.core
,Python将查找__main__.py
文件并将其作为脚本运行。 -m
开关会将当前工作目录添加到模块搜索路径,因此,当您位于正确的工作目录中时,可以使用该命令,并且一切正常。或者将软件包安装在模块搜索路径上已经存在的目录中。
让您的脚本将正确的目录添加到模块搜索路径(基于os.path.absolute(__file__)
获取当前文件的路径)。考虑到您的脚本始终被命名为__main__
,并且导入pkg.core.main
会添加另一个独立的模块对象。您将拥有两个单独的命名空间。
我也强烈建议不要使用隐式相对导入。您可以通过添加嵌套的软件包或具有相同名称的模块来轻松地屏蔽顶级模块和软件包。如果尝试在pkg/time.py
包内使用time
,则在标准库import time
模块之前可以找到pkg
。而是使用显式相对模块引用的Python 3模型;将from __future__ import absolute_import
添加到所有文件,然后使用from . import <name>
明确指出从何处导入模块。
关于python - 隐式相对导入在Python中如何工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48304317/