Python 中 import 的机制与实现
admin
2023-07-31 00:31:12
0

本文所涉及到的代码在github上。

概述

Python 是一门优美简单、功能强大的动态语言。在刚刚接触这门语言时,我们会被其优美的格式、简洁的语法和无穷无尽的类库所震撼。在真正的将python应用到实际的项目中,你会遇到一些无法避免的问题。最让人困惑不解的问题有二类,一个 编码问题,另一个则是引用问题。

本文主要讨论关于Python中import的机制与实现、以及介绍一些有意思的Python Hooks。

Python 类库引入机制

首先,看一个简单的例子:

1234567891011 \”\”\”目录结构如下:├── __init__.py├── main.py└── string.py\”\”\”# main.py 内容如下import stringprint string.a# string.py 内容如下a = 2

现在,考虑一下:

  1. 当我们执行main.py的时候,会发生什么事情?
  2. 在main.py文件执行到
    import string 的时候,解释器导入的string类库是当前文件夹下的string.py还是系统标准库的string.py呢?
  3. 如果明确的指明⾃己要引⼊的类库?

为了搞清楚上面的问题,我们需要了解关于Python类库引入的机制。

Python的两种引入机制

Python 提供了二种引入机制:

  1. relative import
  2. absolute import

relative import

relative import 也叫作相对引入,在Python2.5及之前是默认的引入方法。它的使用方法如下:

123 from .string import afrom ..string import afrom ...string import a

这种引入方式使用一个点号来标识引入类库的精确位置。与linux的相对路径表示相似,一个点表示当前目录,每多一个点号则代表向上一层目录。

1234567891011 \”\”\”├── __init__.py├── foo.py└── main.py\”\”\”# foo.pya = 2# main.pyprint __name__from .foo import aprint a

相对引入,那么我们需要知道相对什么来引入。相对引入使用被引入文件的
__name__ 属性来决定该文件在整个包结构的位置。那么如果文件的__name__没有包含任何包的信息,例如
__name__ 被设置为了__main__,则认为其为‘top level script’,而不管该文件的位置,这个时候相对引入就没有引入的参考物。如上面的程序所示,当我们执行
python main.py 时,Python解释器会抛出 ValueError: Attempted relative import in non-package的异常。

为了解决这个问题,PEP 0366 — Main module explicit relative imports提出了一个解决方案。允许用户使用python -m ex2.main的方式,来执行该文件。在这个方案下,引入了一个新的属性__package__

1234567891011 liuchang@localhost  ~/Codes/pycon$ cat ex2/main.pyprint __name__print __package__from .foo import aprint aliuchang@localhost  ~/Codes/pycon$ python m ex2.main__main__ex22

absolute import

absolute import 也叫作完全引入,非常类似于Java的引入进制,在Python2.5被完全实现,但是是需要通过
from __future__ import absolute_import 来打开该引入进制。在Python2.6之后以及Python3,完全引用成为Python的默认的引入机制。它的使用方法如下:

12 from pkg import foofrom pkg.moduleA import foo

要注意的是,需要从包目录最顶层目录依次写下,而不能从中间开始。

在使用该引入方式时,我们碰到比较多的问题就是因为位置原因,Python找不到相应的库文件,抛出ImportError的异常。让我们看一个完全引用的例子:

1234567891011121314 \”\”\”ex3├── __init__.py├── foo.py└── main.py\”\”\”# foo.pya = 2 # main.pycrayon-line crayon-striped-line\” id=\”crayon-5812b3e36c16b868889009-8\”>a = 2 # main.py和无穷无尽的类库所震撼。在真正的将python应用到实际的项目中,你会遇到一些无法避免的问题。最让人困惑不解的问题有二类,一个 编码问题,另一个则是引用问题。

本文主要讨论关于Python中import的机制与实现、以及介绍一些有意思的Python Hooks。

Python 类库引入机制

首先,看一个简单的例子:

1234567891011 \”\”\”目录结构如下:├── __init__.py├── main.py└── string.py\”\”\”# main.py 内容如下import stringprint string.a# string.py 内容如下a = 2

现在,考虑一下:

  1. 当我们执行main.py的时候,会发生什么事情?
  2. 在main.py文件执行到
    import string 的时候,解释器导入的string类库是当前文件夹下的string.py还是系统标准库的string.py呢?
  3. 如果明确的指明⾃己要引⼊的类库?

为了搞清楚上面的问题,我们需要了解关于Python类库引入的机制。

Python的两种引入机制

Python 提供了二种引入机制:

  1. relative import
  2. absolute import

relative import

relative import 也叫作相对引入,在Python2.5及之前是默认的引入方法。它的使用方法如下:

123 from .string import afrom ..string import afrom ...string import a

这种引入方式使用一个点号来标识引入类库的精确位置。与linux的相对路径表示相似,一个点表示当前目录,每多一个点号则代表向上一层目录。

1234567891011 \”\”\”├── __init__.py├── foo.py└── main.py\”\”\”# foo.pya = 2# main.pyprint __name__from .foo import aprint a

相对引入,那么我们需要知道相对什么来引入。相对引入使用被引入文件的
__name__ 属性来决定该文件在整个包结构的位置。那么如果文件的__name__没有包含任何包的信息,例如
__name__ 被设置为了__main__,则认为其为‘top level script’,而不管该文件的位置,这个时候相对引入就没有引入的参考物。如上面的程序所示,当我们执行
python main.py 时,Python解释器会抛出 ValueError: Attempted relative import in non-package的异常。

为了解决这个问题,PEP 0366 — Main module explicit relative imports提出了一个解决方案。允许用户使用python -m ex2.main的方式,来执行该文件。在这个方案下,引入了一个新的属性__package__

1234567891011 liuchang@localhost  ~/Codes/pycon$ cat ex2/main.pyprint __name__print __package__from .foo import aprint aliuchang@localhost  ~/Codes/pycon$ python m ex2.main__main__ex22

absolute import

absolute import 也叫作完全引入,非常类似于Java的引入进制,在Python2.5被完全实现,但是是需要通过
from __future__ import absolute_import 来打开该引入进制。在Python2.6之后以及Python3,完全引用成为Python的默认的引入机制。它的使用方法如下:

12 from pkg import foofrom pkg.moduleA import foo

要注意的是,需要从包目录最顶层目录依次写下,而不能从中间开始。

在使用该引入方式时,我们碰到比较多的问题就是因为位置原因,Python找不到相应的库文件,抛出ImportError的异常。让我们看一个完全引用的例子:

1234567891011121314 \”\”\”ex3├── __init__.py├── foo.py└── main.py\”\”\”# foo.py

相关内容

热门资讯

500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
python绘图库Matplo... 本文简单介绍了Python绘图库Matplotlib的安装,简介如下: matplotlib是pyt...
Prometheus+Graf... 一,Prometheus概述 1,什么是Prometheus?Prometheus是最初在Sound...