本文所涉及到的代码在github上。
概述
Python 是一门优美简单、功能强大的动态语言。在刚刚接触这门语言时,我们会被其优美的格式、简洁的语法和无穷无尽的类库所震撼。在真正的将python应用到实际的项目中,你会遇到一些无法避免的问题。最让人困惑不解的问题有二类,一个 编码问题,另一个则是引用问题。
本文主要讨论关于Python中import的机制与实现、以及介绍一些有意思的Python Hooks。
Python 类库引入机制
首先,看一个简单的例子:
1 2 3 4 5 6 7 8 9 10 11 |
""" 目录结构如下: ├── __init__.py ├── main.py └── string.py """ # main.py 内容如下 import string print string.a # string.py 内容如下 a = 2 |
现在,考虑一下:
- 当我们执行main.py的时候,会发生什么事情?
- 在main.py文件执行到 import string 的时候,解释器导入的string类库是当前文件夹下的string.py还是系统标准库的string.py呢?
- 如果明确的指明⾃己要引⼊的类库?
为了搞清楚上面的问题,我们需要了解关于Python类库引入的机制。
Python的两种引入机制
Python 提供了二种引入机制:
- relative import
- absolute import
relative import
relative import 也叫作相对引入,在Python2.5及之前是默认的引入方法。它的使用方法如下:
1 2 3 |
from .string import a from ..string import a from ...string import a |
这种引入方式使用一个点号来标识引入类库的精确位置。与linux的相对路径表示相似,一个点表示当前目录,每多一个点号则代表向上一层目录。
1 2 3 4 5 6 7 8 9 10 11 |
""" ├── __init__.py ├── foo.py └── main.py """ # foo.py a = 2 # main.py print __name__ from .foo import a print 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__
。
1 2 3 4 5 6 7 8 9 10 11 |
liuchang@localhost ~/Codes/pycon $ cat ex2/main.py print __name__ print __package__ from .foo import a print a liuchang@localhost ~/Codes/pycon $ python -m ex2.main __main__ ex2 2 |
absolute import
absolute import 也叫作完全引入,非常类似于Java的引入进制,在Python2.5被完全实现,但是是需要通过 from __future__ import absolute_import 来打开该引入进制。在Python2.6之后以及Python3,完全引用成为Python的默认的引入机制。它的使用方法如下:
1 2 |
from pkg import foo from pkg.moduleA import foo |
要注意的是,需要从包目录最顶层目录依次写下,而不能从中间开始。
在使用该引入方式时,我们碰到比较多的问题就是因为位置原因,Python找不到相应的库文件,抛出ImportError的异常。让我们看一个完全引用的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
""" ex3 ├── __init__.py ├── foo.py └── main.py """ # foo.py a = 2 # main.py crayon-line crayon-striped-line" id="crayon-5812b3e36c16b868889009-8">a = 2 # main.py 和无穷无尽的类库所震撼。在真正的将python应用到实际的项目中,你会遇到一些无法避免的问题。最让人困惑不解的问题有二类,一个 编码问题,另一个则是引用问题。
本文主要讨论关于Python中import的机制与实现、以及介绍一些有意思的Python Hooks。 Python 类库引入机制首先,看一个简单的例子:
现在,考虑一下:
为了搞清楚上面的问题,我们需要了解关于Python类库引入的机制。 Python的两种引入机制Python 提供了二种引入机制:
relative importrelative import 也叫作相对引入,在Python2.5及之前是默认的引入方法。它的使用方法如下:
这种引入方式使用一个点号来标识引入类库的精确位置。与linux的相对路径表示相似,一个点表示当前目录,每多一个点号则代表向上一层目录。
相对引入,那么我们需要知道相对什么来引入。相对引入使用被引入文件的
__name__ 属性来决定该文件在整个包结构的位置。那么如果文件的 为了解决这个问题,PEP 0366 — Main module explicit relative imports提出了一个解决方案。允许用户使用
absolute importabsolute import 也叫作完全引入,非常类似于Java的引入进制,在Python2.5被完全实现,但是是需要通过 from __future__ import absolute_import 来打开该引入进制。在Python2.6之后以及Python3,完全引用成为Python的默认的引入机制。它的使用方法如下:
要注意的是,需要从包目录最顶层目录依次写下,而不能从中间开始。 在使用该引入方式时,我们碰到比较多的问题就是因为位置原因,Python找不到相应的库文件,抛出ImportError的异常。让我们看一个完全引用的例子:
|