Python导入在将文件用作模块和直接调用时都有效

2024-10-02 10:20:40 发布

您现在位置:Python中文网/ 问答频道 /正文

今天我读了关于Python中的absolute and relative imports,我想知道当包含导入的脚本用作模块并且直接调用它时,是否有一种Python方式使导入工作。例如:

└── project
      ├── main.py
      └── package
             ├── submoduleA.py
             └── submoduleB.py

main.py

from package.submoduleA import submoduleAfunction
submoduleAfunction() 

子模块b.py

def submoduleBfunction():
    print('Hi from submoduleBfunction')

子模a.py

# Absolute import, works when called directly: python3 package/submoduleA.py 
from submoduleB import submoduleBfunction 

# Relative import, works when imported as module: python3 main.py
# from .submoduleB import submoduleBfunction 

def submoduleAfunction():
    submoduleBfunction()
    
if __name__=="__main__":
    submoduleAfunction()

如你所见,我有绝对进口和相对进口。它们中的每一个都在特定的情况下工作。但是,有没有一种类似于Python的方法可以使这两种情况都有效呢?到目前为止,我已经完成了处理sys.path的技巧,但我不确定这在任何情况下(即从解释器调用或在不同的操作系统中调用)都会起作用,或者即使这违反了任何建议

import sys
import pathlib
sys.path.append(str(pathlib.Path(__file__).parent.resolve()))

Tags: 模块frompyimportpackagemaindefsys
3条回答
# Absolute import, works when called directly: python3 package/submoduleA.py 
from submoduleB import submoduleBfunction 

因为submoduleAsubmoduleB的“兄弟姐妹”,所以这实际上是一个隐式的相对导入。关于他们style guide说:

Implicit relative imports should never be used and have been removed in Python 3.

当作为脚本运行python3 package/submoduleA.py时,它甚至可以工作的唯一原因是Python将脚本的目录前置到sys.path。从docs开始:

As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter.

也就是说,目录/path/to/package被注入sys.path,允许直接导入submoduleB

不应该使用隐式相对导入,那么应该使用什么来代替呢?没关系,您可以使用正确的绝对导入形式:

from package.submoduleB import submoduleBfunction

或相对导入:

from .submoduleB import submoduleBfunction

只要已将package安装到环境中(安装包就是将代码放入位于sys.path上的site-packages中),这两种方法都可以

如果您必须以脚本形式直接运行package/submoduleA.py,即considered an anti-pattern,则需要使用绝对导入版本。在这种情况下,相对导入do not work。您需要改用python3 -m package.submoduleA,以使相对导入版本正常工作

一种可能是将绝对导入包含在try块中,然后捕获一个ImportException。在出现异常的情况下,您可能将其用作模块,然后执行相对导入

try:
    ​from submoduleB import submoduleBfunction 
except ImportException:
    from .submoduleB import submoduleBfunction 

免责声明:

  • 您的里程数可能会有所不同,我意识到我的答案并不能完全回答这个问题(使用相对导入)。我是罪魁祸首(我的错)

  • 为我辩护:谷歌python避免相对导入返回540k次点击

我通常避免相对导入,因为它们似乎在这类事情上有太多的特殊情况,我非常喜欢在适当的时候直接将python文件作为脚本运行

例如,我的constants.py文件可以作为脚本运行—它将breakpoint(),我可以检查它的内容,其中很多内容来自环境变量

假设project目录位于Python路径中,我只会使用from project.package.submoduleA import submoduleAfunction。这在所有情况下都有效

(我发现显式导入的另一个好处是,我想将我的顶级包(myproject重命名为myproject2)。所有内容都显式允许我快速sed更改。请注意下面评论中Wim的评论)

相关问题 更多 >

    热门问题