If you’ve worked on a Python project that has more than one file, chances are you’ve had to use an import statement before.
如果您从事的Python项目有多个文件,那么您以前可能不得不使用import语句。
Even for Pythonistas with a couple of projects under their belt, imports can be confusing! You’re probably reading this because you’d like to gain a deeper understanding of imports in Python, particularly absolute and relative imports.
即使对于拥有多个项目的Pythonista使用者,导入也可能会造成混淆! 您可能正在阅读本文,因为您想对Python中的导入(尤其是绝对导入和相对导入)有更深入的了解。
In this tutorial, you’ll learn the differences between the two, as well as their pros and cons. Let’s dive right in!
在本教程中,您将学习两者之间的区别以及它们的优缺点。 让我们潜入吧!
Free Bonus: 5 Thoughts On Python Mastery, a free course for Python developers that shows you the roadmap and the mindset you’ll need to take your Python skills to the next level.
免费奖金: 关于Python精通的5个想法 ,这是针对Python开发人员的免费课程,向您展示了将Python技能提升到新水平所需的路线图和心态。
进口快速回顾 (A Quick Recap on Imports)
You need to have a good understanding of Python modules and packages to know how imports work. A Python module is a file that has a .py
extension, and a Python package is any folder that has modules inside it (or, in Python 2, a folder that contains an __init__.py
file).
您需要对Python模块和软件包有充分的了解,才能知道导入的工作方式。 Python模块是具有.py
扩展名的文件,而Python包是内部具有模块的任何文件夹(或者在Python 2中是包含__init__.py
文件的文件夹)。
What happens when you have code in one module that needs to access code in another module or package? You import it!
当一个模块中的代码需要访问另一模块或程序包中的代码时,会发生什么? 您导入它!
导入方式 (How Imports Work)
But how exactly do imports work? Let’s say you import a module abc
like so:
但是进口究竟如何工作? 假设您像这样导入模块abc
:
import import abc
abc
The first thing Python will do is look up the name abc
in sys.modules
. This is a cache of all modules that have been previously imported.
Python要做的第一件事是在sys.modules
查找名称abc
。 这是先前已导入的所有模块的缓存。
If the name isn’t found in the module cache, Python will proceed to search through a list of built-in modules. These are modules that come pre-installed with Python and can be found in the Python Standard Library. If the name still isn’t found in the built-in modules, Python then searches for it in a list of directories defined by sys.path
. This list usually includes the current directory, which is searched first.
如果在模块缓存中找不到该名称,Python将继续搜索内置模块列表。 这些是Python预先安装的模块,可以在Python标准库中找到 。 如果在内置模块中仍找不到该名称,则Python然后在sys.path
定义的目录列表中搜索该名称。 该列表通常包括当前目录,该目录首先被搜索。
When Python finds the module, it binds it to a name in the local scope. This means that abc
is now defined and can be used in the current file without throwing a NameError
.
当Python找到模块时,它将其绑定到本地范围内的名称。 这意味着现在已经定义了abc
并且可以在当前文件中使用abc
而不抛出NameError
。
If the name is never found, you’ll get a ModuleNotFoundError
. You can find out more about imports in the Python documentation here!
如果未找到名称, ModuleNotFoundError
收到ModuleNotFoundError
。 您可以在此处的Python文档中找到有关导入的更多信息!
Note: Security Concerns
注意:安全问题
Be aware that Python’s import system presents some significant security risks. This is largely due to its flexibility. For example, the module cache is writable, and it is possible to override core Python functionality using the import system. Importing from third-party packages can also expose your application to security threats.
请注意,Python的导入系统存在一些重大的安全风险。 这主要是由于其灵活性。 例如,模块缓存是可写的,并且可以使用导入系统覆盖Python的核心功能。 从第三方程序包导入还会使您的应用程序面临安全威胁。
Here are a couple of interesting resources to learn more about these security concerns and how to mitigate them:
以下是一些有趣的资源,以了解有关这些安全问题以及如何缓解这些问题的更多信息:
- 10 common security gotchas in Python and how to avoid them by Anthony Shaw (Point 5 talks about Python’s import system.)
- Episode #168: 10 Python security holes and how to plug them from the TalkPython podcast (The panelists begin talking about imports at around the 27:15 mark.)
- Anthony Shaw 撰写的Python中的10个常见安全陷阱以及如何避免它们 (第5点讨论了Python的导入系统。)
- 第168集:10个Python安全漏洞以及如何从TalkPython播客中插入漏洞(小组成员在27:15左右开始讨论导入)。
导入语句的语法 (Syntax of Import Statements)
Now that you know how import statements work, let’s explore their syntax. You can import both packages and modules. (Note that importing a package essentially imports the package’s __init__.py
file as a module.) You can also import specific objects from a package or module.
现在您知道了导入语句的工作原理,让我们探究它们的语法。 您可以导入软件包和模块。 (请注意,导入软件包实际上是将软件包的__init__.py
文件作为模块导入。)您还可以从软件包或模块中导入特定的对象。
There are generally two types of import syntax. When you use the first one, you import the resource directly, like this:
通常有两种类型的导入语法。 使用第一个资源时,可以直接导入资源,如下所示:
abc
can be a package or a module.
abc
可以是程序包或模块。
When you use the second syntax, you import the resource from another package or module. Here’s an example:
当您使用第二种语法时,您将从另一个包或模块中导入资源。 这是一个例子:
from from abc abc import import xyz
xyz
xyz
can be a module, subpackage, or object, such as a class or function.
xyz
可以是模块,子包或对象,例如类或函数。
You can also choose to rename an imported resource, like so:
您还可以选择重命名导入的资源,如下所示:
This renames the imported resource abc
to other_name
within the script. It must now be referenced as other_name
, or it will not be recognized.
这会将导入的资源abc
重命名为脚本中的other_name
。 现在必须将其引用为other_name
,否则将无法识别它。
导入声明的样式 (Styling of Import Statements)
PEP 8, the official style guide for Python, has a few pointers when it comes to writing import statements. Here’s a summary:
PEP 8 是Python的官方样式指南,在编写导入语句时有一些提示。 总结如下:
-
Imports should always be written at the top of the file, after any module comments and docstrings.
-
Imports should be divided according to what is being imported. There are generally three groups:
- standard library imports (Python’s built-in modules)
- related third party imports (modules that are installed and do not belong to the current application)
- local application imports (modules that belong to the current application)
-
Each group of imports should be separated by a blank space.
导入应始终写在文件顶部,在任何模块注释和文档字符串之后。
-
进口应根据进口的物品进行划分。 通常分为三类:
- 标准库导入(Python的内置模块)
- 相关的第三方导入(已安装但不属于当前应用程序的模块)
- 本地应用程序导入(属于当前应用程序的模块)
每组导入都应以空格分隔。
It’s also a good idea to order your imports alphabetically within each import group. This makes finding particular imports much easier, especially when there are many imports in a file.
在每个导入组中按字母顺序对导入进行排序也是一个好主意。 这使查找特定的导入变得容易得多,尤其是当文件中有很多导入时。
Here’s an example of how to style import statements:
以下是如何设置导入语句样式的示例:
"""Illustration of good import statement styling.
"""Illustration of good import statement styling.
Note that the imports come after the docstring.
Note that the imports come after the docstring.
"""
"""
# Standard library imports
# Standard library imports
import import datetime
datetime
import import os
os
# Third party imports
# Third party imports
from from flask flask import import Flask
Flask
from from flask_restful flask_restful import import Api
Api
from from flask_sqlalchemy flask_sqlalchemy import import SQLAlchemy
SQLAlchemy
# Local application imports
# Local application imports
from from local_module local_module import import local_class
local_class
from from local_package local_package import import local_function
local_function
The import statements above are divided into three distinct groups, separated by a blank space. They are also ordered alphabetically within each group.
上面的import语句分为三个不同的组,用空格隔开。 在每个组中,它们也按字母顺序排列。
绝对进口 (Absolute Imports)
You’ve gotten up to speed on how to write import statements and how to style them like a pro. Now it’s time to learn a little more about absolute imports.
您已经掌握了如何编写导入语句以及如何像专家一样设置它们的风格。 现在是时候学习更多有关绝对导入的知识了。
An absolute import specifies the resource to be imported using its full path from the project’s root folder.
绝对导入使用项目的根文件夹中的完整路径指定要导入的资源。
语法和实际示例 (Syntax and Practical Examples)
Let’s say you have the following directory structure:
假设您具有以下目录结构:
There’s a directory, project
, which contains two sub-directories, package1
and package2
. The package1
directory has two files, module1.py
and module2.py
.
有一个目录project
,它包含两个子目录package1
和package2
。 package1
目录包含两个文件module1.py
和module2.py
。
The package2
directory has three files: two modules, module3.py
and module4.py
, and an initialization file, __init__.py
. It also contains a directory, subpackage
, which in turn contains a file, module5.py
.
package2
目录包含三个文件:两个模块module3.py
和module4.py
,以及初始化文件__init__.py
。 它还包含一个目录subpackage
,该目录又包含一个文件module5.py
。
Let’s assume the following:
让我们假设以下内容:
package1/module2.py
contains a function,function1
.package2/__init__.py
contains a class,class1
.package2/subpackage1/module5.py
contains a function,function2
.
-
package1/module2.py
包含一个函数function1
。 -
package2/__init__.py
包含一个类class1
。 -
package2/subpackage1/module5.py
包含一个函数function2
。
The following are practical examples of absolute imports:
以下是绝对导入的实际示例:
from from package1 package1 import import module1
module1
from from package1.module2 package1.module2 import import function1
function1
from from package2 package2 import import class1
class1
from from package2.subpackage1.module5 package2.subpackage1.module5 import import function2
function2
Note that you must give a detailed path for each package or file, from the top-level package folder. This is somewhat similar to its file path, but we use a dot (.
) instead of a slash (/
).
请注意,您必须从顶级程序包文件夹中为每个程序包或文件提供详细的路径。 这有点类似于它的文件路径,但是我们使用点( .
)而不是斜杠( /
)。
绝对进口的利与弊 (Pros and Cons of Absolute Imports)
Absolute imports are preferred because they are quite clear and straightforward. It is easy to tell exactly where the imported resource is, just by looking at the statement. Additionally, absolute imports remain valid even if the current location of the import statement changes. In fact, PEP 8 explicitly recommends absolute imports.
绝对导入是首选,因为它们非常清楚和直接。 仅通过查看语句,就可以很容易地准确知道导入的资源在哪里。 此外,即使import语句的当前位置发生更改,绝对导入仍然有效。 实际上,PEP 8明确建议绝对导入。
Sometimes, however, absolute imports can get quite verbose, depending on the complexity of the directory structure. Imagine having a statement like this:
但是,有时绝对导入可能会变得非常冗长,具体取决于目录结构的复杂性。 想象一下这样的声明:
That’s ridiculous, right? Luckily, relative imports are a good alternative in such cases!
太荒谬了吧? 幸运的是,在这种情况下,相对进口是一个不错的选择!
相对进口 (Relative Imports)
A relative import specifies the resource to be imported relative to the current location—that is, the location where the import statement is. There are two types of relative imports: implicit and explicit. Implicit relative imports have been deprecated in Python 3, so I won’t be covering them here.
相对导入指定相对于当前位置(即,导入语句所在的位置)的要导入的资源。 相对导入有两种类型:隐式和显式。 隐式相对导入已在Python 3中弃用,因此在此不再赘述。
语法和实际示例 (Syntax and Practical Examples)
The syntax of a relative import depends on the current location as well as the location of the module, package, or object to be imported. Here are a few examples of relative imports:
相对导入的语法取决于当前位置以及要导入的模块,包或对象的位置。 以下是相对导入的一些示例:
from from .some_module .some_module import import some_class
some_class
from from ..some_package ..some_package import import some_function
some_function
from from . . import import some_class
some_class
You can see that there is at least one dot in each import statement above. Relative imports make use of dot notation to specify location.
您可以看到上面的每个import语句中至少有一个点。 相对导入使用点符号来指定位置。
A single dot means that the module or package referenced is in the same directory as the current location. Two dots mean that it is in the parent directory of the current location—that is, the directory above. Three dots mean that it is in the grandparent directory, and so on. This will probably be familiar to you if you use a Unix-like operating system!
单点表示所引用的模块或软件包与当前位置位于同一目录中。 两个点表示它位于当前位置的父目录中,即上面的目录中。 三个点表示它位于祖父母目录中,依此类推。 如果您使用类似Unix的操作系统,这可能对您来说很熟悉!
Let’s assume you have the same directory structure as before:
假设您具有与以前相同的目录结构:
Recall the file contents:
调出文件内容:
package1/module2.py
contains a function,function1
.package2/__init__.py
contains a class,class1
.package2/subpackage1/module5.py
contains a function,function2
.
-
package1/module2.py
包含一个函数function1
。 -
package2/__init__.py
包含一个类class1
。 -
package2/subpackage1/module5.py
包含一个函数function2
。
You can import function1
into the package1/module1.py
file this way:
您可以通过以下方式将function1
导入package1/module1.py
文件:
# package1/module1.py
# package1/module1.py
from from .module2 .module2 import import function1
function1
You’d use only one dot here because module2.py
is in the same directory as the current module, which is module1.py
.
您在这里只使用一个点,因为module2.py
与当前模块位于相同的目录module1.py
。
You can import class1
and function2
into the package2/module3.py
file this way:
您可以通过以下方式将class1
和function2
导入package2/module3.py
文件:
In the first import statement, the single dot means that you are importing class1
from the current package. Remember that importing a package essentially imports the package’s __init__.py
file as a module.
在第一个import语句中,单点表示您正在从当前包中导入class1
。 请记住,导入程序包实际上__init__.py
程序包的__init__.py
文件作为模块导入。
In the second import statement, you’d use a single dot again because subpackage1
is in the same directory as the current module, which is module3.py
.
在第二个import语句中,您将再次使用一个点,因为subpackage1
与当前模块位于相同的目录module3.py
。
相对进口的利与弊 (Pros and Cons of Relative Imports)
One clear advantage of relative imports is that they are quite succinct. Depending on the current location, they can turn the ridiculously long import statement you saw earlier to something as simple as this:
相对进口的一个明显优势是它们非常简洁。 根据当前位置,他们可以将您之前看到的可笑的冗长的import语句变成如下所示的简单内容:
from from ..subpackage4.module5 ..subpackage4.module5 import import function6
function6
Unfortunately, relative imports can be messy, particularly for shared projects where directory structure is likely to change. Relative imports are also not as readable as absolute ones, and it’s not easy to tell the location of the imported resources.
不幸的是,相对导入可能会很混乱,尤其是对于目录结构可能会更改的共享项目。 相对导入也不如绝对导入更易读,而且很难说出导入资源的位置。
结论 (Conclusion)
Good job for making it to the end of this crash course on absolute and relative imports! Now you’re up to speed on how imports work. You’ve learned the best practices for writing import statements, and you know the difference between absolute and relative imports.
在绝对和相对进口方面速成教程的结尾,做得很好! 现在,您可以加快导入的工作速度。 您已经了解了编写导入语句的最佳实践,并且知道绝对导入和相对导入之间的区别。
With your new skills, you can confidently import packages and modules from the Python standard library, third party packages, and your own local packages. Remember that you should generally opt for absolute imports over relative ones, unless the path is complex and would make the statement too long.
借助您的新技能,您可以放心地从Python标准库,第三方程序包和您自己的本地程序包中导入程序包和模块。 请记住,通常您应该选择绝对导入而不是相对导入,除非路径复杂并且会使语句过长。
Thanks for reading!
谢谢阅读!
翻译自: https://www.pybloggers.com/2018/09/absolute-vs-relative-imports-in-python/