隐式相对导入在Python中如何工作?

隐式相对导入在Python中如何工作?,python,module,python-2.x,Python,Module,Python 2.x,假设我有以下文件 pkg/ pkg/__init__.py pkg/main.py # import string pkg/string.py # print("Package's string module imported") 现在,如果我运行main.py,它会显示“已导入包的字符串模块” 这是有道理的,并且按照以下内容中的陈述工作: “它将首先在包的目录中查找” 假设我稍微修改了文件结构(添加了一个核心目录): 现在,如果我运行pythoncore/main.py,它将加载内置的str

假设我有以下文件

pkg/
pkg/__init__.py
pkg/main.py # import string
pkg/string.py # print("Package's string module imported")
现在,如果我运行
main.py
,它会显示
“已导入包的字符串模块”

这是有道理的,并且按照以下内容中的陈述工作:

“它将首先在包的目录中查找”

假设我稍微修改了文件结构(添加了一个核心目录):

现在,如果我运行
pythoncore/main.py
,它将加载内置的
string
模块

同样在第二种情况下,如果它必须遵守语句“它将首先查看包的目录”它是否应该加载本地
字符串.py
,因为
pkg
是“包目录”

我对术语“包目录”的理解是特别是根文件夹,它是一个集合,其中包含
\uu init\uuuuuuuuuuuuuuuupy
。因此,在本例中,pkg是“包目录”。它适用于
main.py
以及子目录中的文件,如
core/main.py
,因为它是这个“包”的一部分

这在技术上正确吗


PS:代码片段中
之后的内容是文件的实际内容(不带前导空格)。

包是带有
\uu init\uuuuupy.py
文件的目录,是的,在模块搜索路径上找到时作为模块加载。因此,
pkg
只是一个包,如果父目录位于模块搜索路径上,则可以导入该包并将其视为一个包

但是通过以脚本形式运行
pkg/core/main.py
文件,Python将
pkg/core
目录添加到模块搜索路径,而不是
pkg
的父目录。现在,在模块搜索路径上确实有一个
\uuuu init\uuuuuuuuuy.py
文件,但这不是定义包的原因。您只有一个
\uuuuuuuuuuuuuuuu主模块,与其他任何模块都没有包关系,并且您不能依赖隐式相对导入

您有三种选择:

  • 不要将包内的文件作为脚本运行。将脚本文件放在包的外部,并根据需要导入包。您可以将它放在
    pkg
    目录旁边,或者确保
    pkg
    目录首先安装到模块搜索路径上已经存在的目录中,或者让脚本计算要添加到
    sys.path
    的正确路径

  • 使用可以像运行脚本一样运行模块。如果您使用
    python-mpkg.core
    python将查找
    \uuuuu main\uuuuuu.py
    文件并将其作为脚本运行。
    -m
    开关会将当前工作目录添加到模块搜索路径中,因此当您在正确的工作目录中时,您可以使用该命令,一切都会正常工作。或者将软件包安装在模块搜索路径上已存在的目录中

  • 让您的脚本将正确的目录添加到模块搜索路径中(基于
    os.path.absolute(\uu\u file\uu)
    以获取当前文件的路径)。考虑到您的脚本始终命名为
    \uuuu main\uuu
    ,导入
    pkg.core.main
    将添加第二个独立的模块对象;您将有两个独立的名称空间


  • 我还强烈建议不要使用隐式相对导入。通过添加具有相同名称的嵌套包或模块,可以轻松屏蔽顶级模块和包<如果您试图在
    pkg
    包中使用
    import time
    ,则会在标准库
    time
    模块之前找到code>pkg/time.py
    。相反,使用Python3模型的显式相对模块引用;将
    from\uuuuu future\uuuu import absolute\u import
    添加到所有文件中,然后使用
    from。导入
    以明确模块的导入位置。

    谢谢。我认为这涵盖了我的疑问以及我最初的问题,即运行模块中的脚本。但我应该澄清的一点是,通过“包目录”,我想到的是一组文件夹的根目录,其中包含
    \uuu init\uuuuuuuuupy
    。原因是当我说
    zope
    package时,我指的通常是根文件夹。看起来“package”这个词被重载了,表示不同的意思。可能您希望根据该假设编辑第一行:-@Nishant:
    zope
    可能是包的根文件夹,但该文件夹本身不会添加到
    sys.path
    模块搜索路径。您希望该文件夹的父目录位于模块搜索路径上。谢谢@Martijn Pieters,这是非常重要的一点。我不知道。@Nishant:但是,一个包可以有更多的嵌套包。因此,如果
    zope/foo
    是一个包含
    zope/foo/\uuu init\uuuu.py
    文件的目录,那么
    zope.foo
    也可以是一个包。因此,包目录是任何包含
    \uuuu init\uuuu.py
    文件的目录。
    pkg/
    pkg/__init__.py
    plg/core/__init__.py
    pkg/core/main.py # import string
    pkg/string.py # print("Package's string module imported")