跨Python包导入的正确方法
假设我有两个Python包跨Python包导入的正确方法,python,packaging,Python,Packaging,假设我有两个Python包 /package_name __init__.py /dohickey __init__.py stuff.py other_stuff.py shiny_stuff.py /thingamabob __init__.py cog_master.py round_cogs.py teethless_cogs.py
/package_name
__init__.py
/dohickey
__init__.py
stuff.py
other_stuff.py
shiny_stuff.py
/thingamabob
__init__.py
cog_master.py
round_cogs.py
teethless_cogs.py
/utilities
__init__.py
important.py
super_critical_top_secret_cog_blueprints.py
使用实用程序包的最佳方式是什么?假设shinny_stuff.py需要导入important.py,那么最好的方法是什么
现在我在想
from .utilities import important
但这是最好的办法吗?将实用程序添加到路径并以这种方式导入是否更有意义
import sys
sys.path.append(os.path.basename(os.path.basename(__file__)))
import utilities.super_critical_top_secret_cog_blueprints
这似乎很难添加到我的每个文件中 我认为最安全的方法是始终使用绝对导入,因此在您的情况下:
from package_name.utilities import important
这样,如果您决定在其他包中移动您的shiny_stuff.py(假设包名仍在您的sys.path中),您就不必更改代码。我认为最安全的方法是始终使用绝对导入,因此在您的情况下:
from package_name.utilities import important
这样,如果您决定在其他包中移动您的shinny_stuff.py,您就不必更改代码(假设包_名称仍在sys.path中).如果需要移动到其他位置,请使用绝对导入。如果需要移动到其他位置,请使用绝对导入。根据Nick Coghlan(Python核心开发人员)的说法: (在“双重进口陷阱”标题下) 将包目录添加到路径为模块提供了两种不同的引用方式。上面的链接是一篇关于Python导入系统的优秀博文。直接将其添加到路径意味着您可能拥有一个模块的两个副本,这是您不想要的。从.utilities import import import import important进行相对导入是可以的,而绝对导入
import package\u name.utilities.important
也是可以的。根据Nick Coghlan(Python核心开发人员)的说法:
(在“双重进口陷阱”标题下)
将包目录添加到路径为模块提供了两种不同的引用方式。上面的链接是一篇关于Python导入系统的优秀博文。直接将其添加到路径意味着您可能拥有一个模块的两个副本,这是您不想要的。从.utilities import import import import important进行相对导入是可以的,而绝对导入import package\u name.utilities.important
也是可以的。可能不存在“最佳”上下文外选择,但您可以有一些标准来选择更适合您的用例,对于这种判断,我们应该知道不同的可能方法及其特点。可能最好的信息来源是信息本身,它包含了一些关于声明不同可能性的基本原理
一种常见的方法是使用“绝对导入”,在您的情况下,它类似于:
from package_name.utilities import important
这样,您就可以将此文件设置为脚本。它在某种程度上独立于其他模块和包,主要由其位置固定。如果您有一个包结构,并且需要从其位置更改一个模块,那么拥有绝对路径将有助于保持此单个文件不变,但是使用此模块的所有文件都应该更改。当然,您也可以将\uuuu init\uuuu.py
文件导入为:
from package_name import utilities
这些进口商品都有相同的特点。请注意,实用程序.important
尝试在\uuuu init\uuuuuuuuuuuuuuuuupy
中查找变量import important.py
,而不是从import important.py中查找变量,因此使用“import important important”\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
另一种方法是相对方法,使用:
from ..utilities import important
第一个点(from.stuff import
或from.import
)表示“此[子]包中的模块”,或当只有点时,表示\uuu init\uuuuuu.py
。从第二点开始,我们讨论的是父目录。通常,脚本/可执行文件中不允许在任何导入中以点开头,但如果您关心具有相对导入的脚本,则可以阅读
可在PEP 328本身上找到相对导入的理由:
随着向绝对进口的转变,出现了一个问题,即是否应该允许相对进口。介绍了几个用例,其中最重要的是能够重新安排大型软件包的结构,而无需编辑子软件包。此外,如果没有相对导入,包中的模块无法轻松导入自身
无论哪种情况,模块都与子包绑定在一起,即无论用户尝试首先导入哪个包,都会首先导入包\u name
,除非您使用sys.path搜索子包作为包(即,使用sys.path中的包根)……但这听起来很奇怪,为什么要这样做
\uuuu init\uuuuu.py
可以自动导入模块名称,因为您应该关心其名称空间内容。例如,假设important.py
有一个名为top\u secret
的对象,它是一个字典。从你需要的任何地方找到它
from package_name.utilities.important import top_secret
也许您希望不那么具体:
from package_name.utilities import top_secret
这将通过一个\uuuu init\uuuu.py
完成,其中包含以下行:
from .important import top_secret
这可能混合了相对导入和绝对导入,但是对于\uuuu init\uuuu.py
来说,您可能知道子包作为子包是有意义的,也就是说,它本身就是一个抽象。如果只是位于同一位置的一组文件,并且需要显式的模块名,那么\uuuu init\uuuuuuuuuuuy.py
可能是空的(或者几乎是空的)。但是为了避免用户使用显式的模块名,可以在根\uuuu init\uuuu.py
上使用相同的方法
from .utilities import top_secret
完全是间接的,但是当文件为某些内部组织嵌套时,名称空间以这种方式变得平坦。例如,wx
包(wxPython)可以这样做:所有东西都可以直接从wx导入中找到
如果需要,还可以使用一些元编程来查找内容