如果您已经处理过具有多个文件的Python项目,那么您之前必须使用import语句。

即使对于有几个项目的Pythonistas,进口也可能令人困惑!您可能正在阅读此内容,因为您希望更深入地了解Python中的导入,尤其是绝对和相对导入。

在本教程中,您将了解两者之间的差异,以及它们的优缺点。让我们一起潜入!

快速回顾引入

您需要很好地理解Python模块和包,以了解导入的工作原理。Python模块是一个具有.py扩展名的文件,Python包是任何包含模块的文件夹(或者在Python 2中,包含__init__.py文件的文件夹)。

当一个模块中的代码需要访问另一个模块或包中的代码时会发生什么?你导入它!

进口如何运作

但是进口究竟是如何运作的呢?假设你导入一个abc这样的模块:

import abc的第一件事Python将做的是查找的名字abc在sys.modules。这是先前导入的所有模块的缓存。

如果在模块高速缓存中找不到该名称,Python将继续搜索内置模块列表。这些是预先安装了Python的模块,可以在Python标准库中找到。如果在内置模块中找不到该名称,则Python会在由其定义的目录列表中搜索该名称sys.path。此列表通常包括当前目录,首先搜索该目录。

当Python找到模块时,它会将其绑定到本地范围中的名称。这意味着abc现在已经定义并且可以在当前文件中使用而不会抛出NameError。

如果找不到名字,你会得到一个ModuleNotFoundError。您可以在此处找到有关Python文档中导入的更多信息!

注意:安全问题

请注意,Python的导入系统存在一些重大的安全风险。这主要归功于其灵活性。例如,模块缓存是可写的,并且可以使用导入系统覆盖核心Python功能。从第三方软件包导入还可能使您的应用程序面临安全威胁。

引入语句的语法

既然您已了解import语句的工作原理,那么让我们来探索它们的语法。您可以导入包和模块。(请注意,导入包实际上是将包的__init__.py文件作为模块导入。)您还可以从包或模块中导入特定对象。

通常有两种类型的导入语法。当您使用第一个时,直接导入资源,如下所示:

import abcabc 可以是包或模块。

使用第二种语法时,从另一个包或模块导入资源。这是一个例子:

from abc import xyzxyz 可以是模块,子包或对象,例如类或函数。

您还可以选择重命名导入的资源,如下所示:

import abc as other_name这将重命名导入的资源abc,以other_name在脚本中。它现在必须被引用other_name,否则将无法识别。

导入报表的样式

PEP 8 是Python的官方风格指南,在编写import语句时有一些指示。这是一个总结:

在任何模块注释和文档字符串之后,应始终将导入写入文件的顶部。进口应根据进口情况进行划分。一般有三组:标准库导入(Python的内置模块)相关的第三方导入(已安装且不属于当前应用程序的模块)本地应用程序导入(属于当前应用程序的模块)每组导入应用空格分隔。在每个导入组中按字母顺序排序导入也是一个好主意。这使得查找特定导入变得更加容易,尤其是当文件中有许多导入时。

以下是如何设置import语句样式的示例:

"""Illustration of good import statement styling.Note that the imports come after the docstring."""# Standard library importsimport datetimeimport os# Third party importsfrom flask import Flaskfrom flask_restful import Apifrom flask_sqlalchemy import SQLAlchemy# Local application importsfrom local_module import local_classfrom local_package import local_function绝对引入

你已经掌握了如何编写import语句以及如何像专业人士那样设置样式的速度。现在是时候学习更多有关绝对进口的知识了。

绝对导入使用项目根文件夹中的完整路径指定要导入的资源。

语法和实际例子

假设您有以下目录结构:

└── project ├── package1 │ ├── module1.py │ └── module2.py └── package2 ├── __init__.py ├── module3.py ├── module4.py └── subpackage1 └── module5.py有一个目录,project其中包含两个子目录,package1和package2。该package1目录有两个文件,module1.py和module2.py。

该package2目录下有三个文件:两个模块,module3.py并module4.py和初始化文件__init__.py。它还包含一个目录,subpackage该目录又包含一个文件module5.py。

我们假设如下:

package1/module2.py包含一个函数function1。package2/__init__.py包含一个类class1。package2/subpackage1/module5.py包含一个函数function2。以下是绝对引入的实际例子:

from package1 import module1 from package1.module2 import function1 from package2 import class1 from package2.subpackage1.module5 import function2请注意,您必须从顶级包文件夹中为每个包或文件提供详细路径。这有点类似于它的文件路径,但我们使用dot(.)而不是斜杠(/)。

绝对引入的利弊

绝对引入是首选,因为它们非常清晰和直接。只需查看语句,就可以很容易地确定导入资源的确切位置。此外,即使import语句的当前位置发生更改,绝对导入仍然有效。事实上,PEP 8明确建议绝对引入。

但是,有时候,绝对导入会变得非常冗长,具体取决于目录结构的复杂程度。想象一下这样的声明:

from package1.subpackage2.subpackage3.subpackage4.module5 import function6那太荒谬了吧?幸运的是,在这种情况下,相对进口是一个很好的选择!

相对引入

相对导入指定要相对于当前位置导入的资源 - 即import语句所在的位置。有两种类型的相对导入:隐式和显式。Python 3中已经弃用了隐式相对导入,所以我不会在这里介绍它们。

语法和实际例子

相对导入的语法取决于当前位置以及要导入的模块,包或对象的位置。以下是相关导入的几个示例:

from .some_module import some_classfrom ..some_package import some_functionfrom . import some_class您可以看到上面的每个import语句中至少有一个点。相对导入使用点表示法来指定位置。

单个点表示引用的模块或包与当前位置位于同一目录中。两个点表示它位于当前位置的父目录中 - 即上面的目录。三个点表示它位于祖父目录中,依此类推。如果您使用类Unix操作系统,这可能会让您熟悉!

假设您具有与以前相同的目录结构:

└── project ├── package1 │ ├── module1.py │ └── module2.py └── package2 ├── __init__.py ├── module3.py ├── module4.py └── subpackage1 └── module5.py回想一下文件内容:

package1/module2.py包含一个函数function1。package2/__init__.py包含一个类class1。package2/subpackage1/module5.py包含一个函数function2。你可以导入function1到package1/module1.py文件中是这样的:

# package1/module1.pyfrom .module2 import function1这里只使用一个点,因为module2.py它与当前模块位于同一目录中,即module1.py。

您可以这样导入class1和function2导入package2/module3.py文件:

# package2/module3.pyfrom . import class1from .subpackage1.module5 import function2在第一个import语句中,单点表示您class1从当前包导入。请记住,导入包实际上是将包的__init__.py文件作为模块导入。

在第二个import语句中,您将再次使用单个点,因为subpackage1它与当前模块位于同一目录中,即module3.py。

相对引入的利弊

相对引入的一个明显优势是它们非常简洁。根据当前位置,他们可以将您之前看到的可笑的长导入语句变为如下这样简单:

from ..subpackage4.module5 import function6幸的是,相对导入可能很混乱,特别是对于目录结构可能会发生变化的共享项目。相对导入也不像绝对导入那样可读,并且要告诉导入资源的位置并不容易。

结论

在绝对和相对引入的速成课程结束时做好工作!现在,您可以快速了解导入的工作原理。您已经学习了编写import语句的最佳实践,并且您知道绝对和相对导入之间的区别。

利用您的新技能,您可以放心地从Python标准库,第三方软件包和您自己的本地软件包导入软件包和模块。请记住,除非路径很复杂并且声明太长,否则通常应选择相对于绝对导入的绝对导入。