首页 > Python笔记 阅读数:19

Python import用法:导入标准库

英特尔公司曾经有一个著名的宣传口号——Intel Inside(内有英特尔)。其实,Python 也有一个类似的非著名口号—— batteries included(内配电池)。这里的 batteries,显然是一个隐喻,它表示的是,在 Python 生态系统中,Python 拥有许多内置的非常有用的模块,能为 Python 快捷开发提供“能源”支持。

随着开发阅历的增加,我们会逐渐体会到,越是复杂的项目,越不大可能从零起步。“他山之石,可以攻玉”,通过多年的积累,Python 的生态圈已拥有大量性能稳定、形式多样的类库,不论是 Python 官方提供的内置库,还是第三方提供的外部库,都可以很方便地被我们拿来即用。

如果采用默认方式安装 Python 时仅仅安装部分核心模块,则在启动 Python 时,也仅仅加载这些核心模块。如果想使用一些特定功能的模块(如数学函数模块、数据处理模块或绘图模块),我们需要先下载这些模块,并在代码中显式加载这些模块。

相比于单纯安装 Python 而言,使用 Anaconda 安装 Python 有一个好处,它提前帮我们安装了大量常用的库(如 NumPy 或 Matplotlib 等),我们要做的就是,在用这些库之前,先将它们导入(import)当前工程。

导入其他库的方法很简单,语法如下:

import 模块名 [as 别名]


比如,当我们想计算某个角的正弦值时,要引用模块 math。这时,就要在 Python 文件开始的地方用 import math 来导入。在调用 math 模块中的函数时,必须遵照如下格式:

模块名.函数名


当 Python 解释器遇到 import 语句时,如果模块在当前搜索路径下,就会被自动导入。
In [1]: import math      #导入数据库 math
In [2]: math.sin(0.4)    #求 0.4 的正弦值
Out[2]: 0.3894183423086505

为了后面程序引用方便,也可以在导入模块的同时为模块取一个更加简单的别名(这个操作是可选项),然后用“别名.函数(属性)名”的方式来使用其中的函数或属性,示例代码如下:
In [3]: import random as rd             #导入随机数库 random,并取一个别名rd
In [4]: x = rd.random()                 #通过别名访问 random(),获取[0,1)区间的随机小数
In [5]: print ("x =", x)
x = 0.07822125715265305
In [6]: import numpy as np              #导入数据处理库 numpy,并取一个别名 np
In [7]: a = np.array((1, 2, 3, 4, 5))   #通过Array()生成一 维矩阵
In [8]: print(a)
[1 2 3 4 5]

这里,我们简单解释一下 In [7] 处的代码。一些初学者可能会困惑,Numpy 库下属的方法 array( ) 为何会有两层圆括号呢?乍看下,这有违 C、C++、Java 等编程语言的惯例。

事实上,Python 并没有违反常规,array( ) 接收的参数只有一个,而这里的参数恰好是一个元组 (1, 2, 3, 4, 5),碰巧元组的外围装饰就是一对圆括号,放在一起好像这个函数的参数需要用两层括号包裹一样,然而这纯属巧合。类似的误读还可能发生在列表上,读者可以思考一下,在哪些情况下,某个对象索引会出现两层方括号[[]]?

上面使用模块中对象的方法有点烦琐。有没有更简单的方法呢?答案是有的。我们可以通过如下方法从某个模块中导入指定的对象。

from 模块名 import 对象名 [as 别名]


使用这种方法,可以从较大的类库包中导入某个特定的对象,并为这个对象取一个别名(这是可选项)。这样做的好处在于,减少了对象的查询次数,提高了访问速度,当然也减少了用户的代码输入量。因为在使用这些被导入的对象时,就像使用本地对象一样可以“直呼其名”,代码如下所示:
In [9]: from math import cos         #仅从 math 模块中导入余弦函数 cos( )
In [10]: cos(3)                      #求 3 的余弦值,此时并没使用 math.来明确 cos( )的来源
-0.9899924966004454
In [11]: from math import sin as f   #仅从 math 模块中导入正弦函数 sin( ),并取别名为 f
In [12]: f(3)                        #直接使用 f 代替 sin( )
0.1411200080598672

当然,还有一种极端的方式,即把整个模块中的所有函数一次性地全部导入,如下所示:
In [13]: from math import *   #导入 math 模块中的所有函数①
In [14]: sin(5)               #求正弦值
Out[14]: -0.9589242746631385
In [15]: cos(1)               #求余弦值
Out[15]: 0.5403023058681398
In [16]: sqrt(2)              #求 2 的平方根
Out[16]: 1.4142135623730951
① 这里“*”为通配符,表示模块内的所有对象。

上述代码虽然写起来比较简单(直接使用函数名,不需要用到“模块名.函数名”的形式),但并不推荐使用。这是因为,模块存在的目的之一,就是构建命名空间(namespace)。通过命名空间,可以实现变量作用域的隔离,从而使得相同的变量名也可以在各自区域内自由使用。

这就好比我们说“北京的张三”和“上海的张三”是可区分的。如果我们把“北京的”和“上海的”这两个条件去掉,剩下两个同名的“张三”,就无法区分了,而这里的“北京的”和“上海的”就好比编程语言中的命名空间。

回到模块加载的讨论上,如果我们使用“import *”来加载某个模块的所有对象,实际上就是去掉了这个模块的命名空间限制,如果多个模块都是通过“import *”来加载的,那么同名的对象,只有最后一个有效,而之前加载的对象,由于没有区分度,便会被后出现的同名对象所覆盖。

相关文章