Python code in one module gains access to the code in another module by the process of importing it.
简单来说,我们日常看到的.py
文件,都称作是一个module
。
当你的 python 代码需要获取外部的一些功能(一些已经造好的轮子),你就需要使用到 import
这个声明关键字。import
可以协助导入其他 module 。(类似 C 预约的 include
)
import
声明是常见的导入方式,但它不是唯一的方式。即其实可以通过其他方式进行 module 导入。
import
语句结合了两个操作:
__import()__
实现。__import()__
的返回值用作命名空间绑定操作。import
语句执行时,__import__()
会被调用,Python 会查找 module 并创建一个 module object 并初始化它;如果 module 没找到,会抛出 ModuleNotFoundError
的一个 exception 。
import
vs __import__()
简单来说,调用__import__()
只是 import
声明操作的一个子集。
直接调用 import() 仅执行模块搜索,如果找到,则执行模块创建操作。虽然可能会出现某些副作用,例如导入父包,以及更新各种缓存(包括 sys.modules),但只有 import 语句执行名称绑定操作。
When a module named spam is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path. sys.path is initialized from these locations:The directory containing the input script (or the current directory when no file is specified). PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH). The installation-dependent default.
import
执行时,会尝试使用以下顺序查找 module:
sys.path
的顺序查找 py
执行文件本身所在文件夹; PYTHONPATH
环境变量;可以通过下面操作查看sys.path的路径
$ python3
Python 3.5.2 (default, Jan 26 2021, 13:30:48)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/home/tester/opt/2.7.5.1', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']
所以,如果需要使用一些第三方的库,除了通过 pip 安装后直接调用以外,也可以把module放置到对应的目录,然后使用 PYTHONPATH
指定该目录。
foo.bar.baz
时,会先尝试导入 foo
,然后foo.bar
,最后foo.bar.baz
,如果任何一个中间导入失败,会触发ModuleNotFoundError
。sys.modules
这个 cache进行查找,如果返回 None 则会抛出 ModuleNotFoundError
错误,如果 module name 找不到,Python 会尝试继续往下查找finders
and loaders
两者结合查找 module 并进行导入操作,finders
负责查找相关路径, loaders
负责加载。Python’s default
sys.meta_path
has three meta path finders, one that knows how to import built-in modules, one that knows how to import frozen modules, and one that knows how to import modules from an import path (i.e. the path based finder).
有上文可知,python import 时候会遵循一定的查找顺序。除了第二章说的3个路径,实际前置还有一层 cache
sys.modules
,The module cache.sys.meta_path
: 一般有3个finders这3个finders对应的路径,恰好是上面第二章说的3个搜索路径
可以通过 Python 交互命令进行查看
guotianwei@office-desktop[SJC]~$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print(sys.meta_path)
[<class '_frozen_importlib.BuiltinImporter'>, <class '_frozen_importlib.FrozenImporter'>, <class '_frozen_importlib_external.PathFinder'>]
相对导入,以 .
打头,跟 linux 文件系统类似,.
和 ..
分别代表当前 package 和父级 package
绝对导入,一般是 import <>
or from <> import <>
这种形式
例如:
package 目录结构如下
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
下面的都是相对导入
from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY
from ..subpackage1 import moduleY
from ..subpackage2.moduleZ import eggs
from ..moduleA import foo
下面是绝对导入
import package.subpackage1.moduleX
from package.subpackage1 import moduleX
一般我们使用 import 导入 module 时,应该遵循怎样的原则,PEP8 给了如下建议:
Imports should be grouped in the following order:Standard library imports. Related third party imports. Local application/library specific imports. You should put a blank line between each group of imports.
import 组织顺序:
Python 新版本提供了一个 api可以控制 import 的规则,避免使用老的方式直接变更 __import__()
复杂的操作,并减少错误发生的概念。
importlib
模块提供了丰富的 API 来与导入系统进行交互。例如 importlib.import_module()
提供了一个推荐的、比内置的 __import__()
更简单的 API 来调用导入机制。
sys.modules
会在 module import 完成后更新 cache,供下次 import 快速访问。
sys.modules
, The module cache This mapping serves as a cache of all modules that have been previously imported, including the intermediate paths. So if foo.bar.baz was previously imported, sys.modules will contain entries for foo, foo.bar, and foo.bar.baz. Each key will have as its value the corresponding module object.
finder 的工作是搜索,跟 loader 工作分离
A finder’s job is to determine whether it can find the named module using whatever strategy it knows about.
搜索路径,不只是 sys.path
的所有路径,一些 subpackages 的查找可能依赖于 parent package 的 __path__
。
import path: A list of locations (or path entries) that are searched by the path based finder for modules to import. During import, this list of locations usually comes from
sys.path
, but for subpackages it may also come from the parent package’s__path__
attribute.
import 机制是可扩展的,详细查看 Import hooks
这个概念。有两个主要的 import hooks: meta hooks 和 import path hooks
The import machinery is designed to be extensible; the primary mechanism for this are the import hooks. There are two types of import hooks: meta hooks and import path hooks.
3个默认的finder,对应不同的策略查找 module
Python’s default sys.meta_path has three meta path finders, one that knows how to import built-in modules, one that knows how to import frozen modules, and one that knows how to import modules from an import path (i.e. the path based finder).
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。