Python 在将文件用作模块和直接调用时都有效的导入
Python imports that work both when using a file as a module and when called directly
我今天在 Python 中阅读了有关 absolute and relative imports 的内容,我想知道当包含导入的脚本用作模块时是否有一种 pythonic 方法可以使导入工作并且直接调用的时候。例如:
└── project
├── main.py
└── package
├── submoduleA.py
└── submoduleB.py
main.py
from package.submoduleA import submoduleAfunction
submoduleAfunction()
submoduleB.py
def submoduleBfunction():
print('Hi from submoduleBfunction')
submoduleA.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()
如你所见,我有绝对导入和相对导入。他们每个人都在特定情况下工作。但是有没有一种 pythonic 的方式让它适用于这两种情况?到目前为止,我已经完成了 sys.path
的技巧,但我不确定这是否适用于所有情况(即从解释器或不同的 OS 中调用)或者即使这样反对任何建议。
import sys
import pathlib
sys.path.append(str(pathlib.Path(__file__).parent.resolve()))
一种可能性是将绝对导入包含在 try
块中并捕获 ImportException
。如果出现异常,您可能将其用作模块,然后进行相对导入。
try:
from submoduleB import submoduleBfunction
except ImportException:
from .submoduleB import submoduleBfunction
免责声明:
您的情况可能有所不同,我意识到我的回答并未完全回答问题(使用 relative 导入)。 Mea maxima culpa(我的错)。
我的辩护词:谷歌搜索 python 避免相对导入 returns 540k 次点击。
我通常避免相对导入,因为它们似乎在这类事情上有太多特殊情况,而且我非常喜欢 运行宁 python 文件在适当的时候直接作为脚本。
例如,我的 constants.py
文件可以 运行 作为脚本 - 它会 breakpoint()
我可以检查它的内容,其中大部分来自环境变量。
假设 project
的 parent 目录在您的 Python 路径中,我将只使用 from project.package.submoduleA import submoduleAfunction
。这适用于所有情况。
(我发现显式导入的一个 可能 额外好处是当我想重命名我的顶级包时(myproject
到 myproject2
)。明确一切让我能够快速 sed
更改。请注意 Wim 在下面的评论中的评论)
# Absolute import, works when called directly: python3 package/submoduleA.py
from submoduleB import submoduleBfunction
因为 submoduleA
是 submoduleB
的“兄弟”,这实际上是一个隐含的相对导入。 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
安装到环境中,两者都可以(安装软件包会将代码放入 site-packages,位于 sys.path
上)。
如果您绝对必须 运行 package/submoduleA.py
直接作为脚本,在本例中为 considered an anti-pattern, then you will need to use the absolute import version. Relative imports do not work。您需要改用 python3 -m package.submoduleA
才能使相对导入版本正常工作。
我今天在 Python 中阅读了有关 absolute and relative imports 的内容,我想知道当包含导入的脚本用作模块时是否有一种 pythonic 方法可以使导入工作并且直接调用的时候。例如:
└── project
├── main.py
└── package
├── submoduleA.py
└── submoduleB.py
main.py
from package.submoduleA import submoduleAfunction
submoduleAfunction()
submoduleB.py
def submoduleBfunction():
print('Hi from submoduleBfunction')
submoduleA.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()
如你所见,我有绝对导入和相对导入。他们每个人都在特定情况下工作。但是有没有一种 pythonic 的方式让它适用于这两种情况?到目前为止,我已经完成了 sys.path
的技巧,但我不确定这是否适用于所有情况(即从解释器或不同的 OS 中调用)或者即使这样反对任何建议。
import sys
import pathlib
sys.path.append(str(pathlib.Path(__file__).parent.resolve()))
一种可能性是将绝对导入包含在 try
块中并捕获 ImportException
。如果出现异常,您可能将其用作模块,然后进行相对导入。
try:
from submoduleB import submoduleBfunction
except ImportException:
from .submoduleB import submoduleBfunction
免责声明:
您的情况可能有所不同,我意识到我的回答并未完全回答问题(使用 relative 导入)。 Mea maxima culpa(我的错)。
我的辩护词:谷歌搜索 python 避免相对导入 returns 540k 次点击。
我通常避免相对导入,因为它们似乎在这类事情上有太多特殊情况,而且我非常喜欢 运行宁 python 文件在适当的时候直接作为脚本。
例如,我的 constants.py
文件可以 运行 作为脚本 - 它会 breakpoint()
我可以检查它的内容,其中大部分来自环境变量。
假设 project
的 parent 目录在您的 Python 路径中,我将只使用 from project.package.submoduleA import submoduleAfunction
。这适用于所有情况。
(我发现显式导入的一个 可能 额外好处是当我想重命名我的顶级包时(myproject
到 myproject2
)。明确一切让我能够快速 sed
更改。请注意 Wim 在下面的评论中的评论)
# Absolute import, works when called directly: python3 package/submoduleA.py
from submoduleB import submoduleBfunction
因为 submoduleA
是 submoduleB
的“兄弟”,这实际上是一个隐含的相对导入。 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
安装到环境中,两者都可以(安装软件包会将代码放入 site-packages,位于 sys.path
上)。
如果您绝对必须 运行 package/submoduleA.py
直接作为脚本,在本例中为 considered an anti-pattern, then you will need to use the absolute import version. Relative imports do not work。您需要改用 python3 -m package.submoduleA
才能使相对导入版本正常工作。