天天看点

python跨包导入包_跨Python包导入的正确方法

“最佳”上下文外的选择可能不存在,但是您可以有一些标准来选择哪个更适合您的用例,对于这样的判断,您应该知道不同的可能方法及其特性。可能最好的信息来源是PEP 328本身,它包含了声明不同可能性的一些基本原理。在

一种常见的方法是使用“绝对导入”,在您的情况下,它类似于:from package_name.utilities import important

这样,你就可以把这个文件变成一个脚本。它有点独立于其他模块和包,主要由其位置决定。如果您有一个包结构,并且需要从它的位置更改一个模块,那么拥有绝对路径将有助于该单个文件保持不变,但所有使用该模块的文件都应该更改。当然,您也可以将__init__.py文件导入为:

^{pr2}$

而这些进口商品也有相同的特点。注意,utilities.important试图在__init__.py内找到一个变量{},而不是从重要.py,因此拥有“import important”__init__.py将有助于避免由于文件结构和命名空间结构之间的区别而导致的错误。在

另一种方法是相对方法,通过使用:from ..utilities import important

第一个点(from .stuff import ___或from . import ___)表示“此[sub]包中的模块”,或者只有点时__init__.py。从第二点开始,我们讨论的是父目录。通常,在脚本/可执行文件中不允许在任何导入中以点开头,但是如果您关心具有相对导入的脚本,可以阅读explicit relative imports (PEP 366)。在

相对进口的理由可以在PEP 328上找到:With the shift to absolute imports, the question arose whether relative imports should be allowed at all. Several use cases were presented, the most important of which is being able to rearrange the structure of large packages without having to edit sub-packages. In addition, a module inside a package can't easily import itself without relative imports.

无论哪种情况,模块都与子包绑定在一起,即不管用户先尝试导入哪个,都首先导入package_name,除非您使用系统路径以包的形式搜索子包(例如,使用包内部的根目录搜索路径)……但这听起来很奇怪,为什么要这么做?在

__init__.py可以自动导入模块名,因为它应该关心它的命名空间内容。例如,假设important.py有一个名为top_secret的对象,这是一个字典。从任何你需要的地方找到它from package_name.utilities.important import top_secret

也许你不想太具体:from package_name.utilities import top_secret

这将通过一个__init__.py完成,其中包含以下行:from .important import top_secret

这可能混合了相对和绝对的导入,但是对于__init__.py你可能知道子包作为子包是有意义的,也就是说,作为一个抽象本身。如果它只是一堆文件,它们位于同一个地方,需要显式的模块名,那么__init__.py可能是空的(或几乎是空的)。但是为了避免用户显式的模块名,可以在根__init__.py上使用from .utilities import top_secret

完全是间接的,但是名称空间以这种方式变得平坦,而文件是为某个内部组织嵌套的。例如,wx包(wxPython)就是这样做的:可以直接找到from wx import ___的所有内容。在

如果您想遵循这种方法,您还可以使用一些元编程来查找内容,例如,使用__all__来检测模块的所有名称,或者查找文件位置以知道哪些模块/子包在那里可以导入。但是,一些简单的代码完成实用程序可能会在执行此操作时丢失。在

对于某些上下文,您可能有其他类型的约束。例如,macropy对导入进行了一些“魔术”,但不能处理作为脚本调用的文件,因此至少需要2个模块才能使用此包。在

无论如何,您应该始终询问您的代码或API组织是否真的需要嵌套到子包中。PEP 20告诉我们“扁平比嵌套好”,这不是一条定律,而是一种观点,它建议您应该保持一个扁平的包结构,除非某些程序需要嵌套原因。同样,您不需要为每个类提供一个模块,也不需要任何类似的模块。在