返回介绍

为什么要使用包导入

发布于 2024-01-29 22:24:16 字数 3076 浏览 0 评论 0 收藏 0

如果刚学Python,确认已经精通了简单的模块,才能进入包的领域,因为这里有些高级的功能。然而,包也扮演了重要的角色,尤其是在较大程序中:包让导入更具信息性,并可以作为组织工具,简化模块的搜索路径,而且可以解决模糊性。

首先,因为包导入提供了程序文件的目录信息,因此可以轻松地找到文件,从而可以作为组织工具来使用。没有包导入时,通常得通过查看模块搜索路径才能找出文件。再者,如果根据功能把文件组织成子目录,包导入会让模块扮演的角色更为明显,也使代码更具可读性。例如,正常导入模块搜索路径上某个目录内的文件时,就像这样:

与下面包含路径的导入相比,提供的信息就更少:

包导入也可以大幅简化PYTHONPATH和.pth文件搜索路径设置。实际上,如果所有跨目录的导入,都使用包导入,并且让这些包导入都相对于一个共同的根目录,把所有Python程序代码都存在其中,在搜索路径上就只需一个单独的接入点:通用的根目录。最后,包导入让你想导入的文件更明确,从而解决了模糊性。下一节要深入探索包导入所扮演的角色。

三个系统的传说

实际中需要包导入的场合,就是解决当多个同名程序文件安装在同一个机器上时,所引发的模糊性。这是与安装相关的问题,也是通常实际中所要留意的地方。让我们用一个假设的场景来说明。

假设程序员开发了一个Python程序,它包含了一个文件utilities.py,其中包含了通用的工具代码,还有一个顶层文件main.py让用户来启动程序。这个程序的文件会以import utilities加载并使用通用的代码。当程序分发给用户时,采用的是.tar或.zip文件的形式,其中包含了该程序的所有文件,而当它在安装时,会把所有文件解压放进目标机器上的某一个名为system1的目录中。

现在,假设有第二位程序员开发了另一个不同的程序,而其文件也命名为utilities.py和main.py,而且同样也在程序文件中使用import utilities来加载一般的代码文件。当获得第二个系统并安装在和第一个系统相同的计算机上时,它的文件会解压并安装至接收机器上某处文件夹名为system2的新目录内,使其不会覆写第一个系统的同名文件。

到目前为止,都没有什么问题:两个系统可共存,在同一台机器上运行。而实际上,不需要配置模块搜索路径,来使用计算机上的这些程序。因为Python总是先搜索主目录(也就是包含顶层文件的目录),任一个系统内的文件的导入,都会自动看见该系统目录内的所有文件。例如,如果点击system1\main.py,所有的导入都会先搜索system1。同样地,如果启动system2\main.py,则会改为先搜索system2。记住,只有在跨目录进行导入时才需要模块搜索路径的设置。

尽管如此,假设在机器上安装这两套程序之后,决定在自己的系统中使用每一个utilities.py文件内的一些程序代码。毕竟,这是通用工具的代码,而Python代码的本质都是想再利用的。就此而言,想在第三个目录内所编写的文件内写下了下面的代码,来载入两个文件其中的一个:

现在,问题开始出现了。为了让这能够工作,需要设置模块搜索路径,引入包含utilities.py文件的目录。但是,要在路径内先放哪个目录呢:system1还是system2?

这个问题在于搜索路径本质上是线性的。搜索总是从左至右扫描,所以不管这个困境你想多久,一定会得到搜索路径上最左侧(最先列出)的目录内的utilities.py。也就是说,永远无法导入另一个目录的那个文件。每次导入操作时,可以试着在脚本内修改sys.path,但那是外部的工作,很容易出错。在默认情况下,可以说你走到了一个死胡同。这个问题正是包所能够解决的。不要在单独的目录内把文件安装成单纯的文件列表,而是将它们打包,在共同根目录之下,安装成子目录。例如,可能想组织这个例子中的所有代码,变成下面这样的安装层次。

现在,就是把共同根目录添加到搜索路径中。如果程序代码的导入就相对于这个通用的根目录,就能以包导入,导入任何一个系统的工具文件:该文件所在目录名称会使其路径具有唯一性(因此,引用的模块也是这样)。事实上,只要使用import语句,就可以在同一个模块内导入这两个工具文件,而每次引用工具模块时,都要重复其完整的路径。

在这里,所在目录名称让模块的引用变得具有唯一性。

注意:如果需要读取两个或两个以上路径内的同名属性时,才需要使用import,在这种情况下不能用from。如果被调用的函数名称在每个路径内都不同,from语句就可以避免每当调用其中一个函数时,就得重复完整的包的路径的问题,这一点先前已经说过。

此外,注意到,在前边所展示的安装层次中,__init__.py文件已加入到system1和system2目录中来使其工作,但是不需要在根目录内增加。只有在程序代码内,import语句所列的目录才需要这些文件。回想一下,Python首次通过包的目录处理导入时,这些文件就会自动运行了。

从技术上来讲,在这种情况下,system3目录不需要放在根目录下:只有被导入的代码包需要。然而,因为不知道何时模块可能在其他程序中有用,你可能还是想将其放在通用的根目录下,来避免以后类似的变量名冲突问题。

最后,注意两个初始系统的导入依然正常运作。因为它们的主目录都会先搜索,在搜索路径上多余的通用根目录,对于system1和system2内的代码是不相关的。它们只需写import utilities,就可以找到自己的文件。再者,如果在通用的根目录下解开所有的Python系统,路径配置就会变得很简单:只需要一次添加通用的根目录就可以了。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文