3.4 通过import复用已有的功能
Python语言是面向对象的程序设计语言,所以提供了以“模块”(Module)、“包”(Package)和“库”等不同形式的程序复用功能。在编程时若需要实现某项功能,可以优先考虑通过import语句导入已有的比较成熟的功能模块,而不是从头开始开发。注:Python语言也被称为“胶水”语言,有很多开源模块都可以通过import(导入或引入)到程序项目中来加快项目的实现,这些模块一般称为包或程序包,也被称为库。本书大部分地方都统一称这些模块或包为“库”。在本书的行文中,在单独说明库名时,库名的第一个英文字母都大写,而在范例程序中用import导入库时,还要遵照库的原始名字中的英文字母大小写,否则无法正确导入。
3.4.1 通过import导入现有的模块
Python的模块是一个扩展名为py的Python文件,在模块中可以封装方法、类和变量。Python中的模块分为三种:自定义模块、内置标准模块和第三方提供的开源模块。
通用性的方法、类和属性往往会被封装到模块中,这样就能达到“一次编写多次调用”的效果,而无需在每个调用类中重复编写。在下面的ModuleDemo.py范例程序中演示了定义模块的常规方法。
1 # !/usr/bin/env python 2 # coding=utf-8 3 def displayModuleName(): 4 print("CalModule") 5 def add(x,y): 6 return x+y 7 def minus(x,y): 8 return x-y 9 PI=3.14 # 封装变量 10 class Stock: 11 def __init__(self, stockCode,price): 12 self.stockCode, self.price=stockCode,price 13 def buy(self): 14 print("Buy " + self.stockCode + " with the price:" + self.price)
在第3行到第8行中定义了多个方法,在第9行中定义了PI这个变量,而在第10行到第14行定义了一个Stock类。在模块中一般放的是“定义”类的代码,而不会放“调用”类的代码。
定义好模块后,就可以在其他Python文件中通过import来导入定义好的现有模块,并使用其中的功能,如下ImportDemo.py范例程序所示。
1 # !/usr/bin/env python 2 # coding=utf-8 3 import ModuleDemo as tool 4 from ModuleDemo import Stock as stockTool 5 6 print(tool.PI) # 3.14 7 print(tool.add(1,2)) # 3 8 print(tool.minus(1,2)) # -1 9 tool.displayModuleName() # CalModule 10 #stockTool.add(1,2) # 出错 11 myStockTool=stockTool("600001","10") 12 myStockTool.buy() #Buy 600001 with the price:10
在类中导入模块的方式一般有两种:第一种如第3行所示,通过import语句和模块名导入指定的模块,并在as之后给这个模块起个别名;另一种方式是只导入该模块中指定的内容,如第4行所示,通过from模块名import类名(或方法名或属性名)的方式导入指定的内容,在as之后同样可以起个别名。
导入模块或指定内容后,在第6行到第9行中,即可通过tool这个别名访问模块中的属性和方法。由于stockTool这个别名仅仅是指向模块中的Stock类,因此通过它无法调用到add方法,而只能如第11行和第12行所示,调用Stock类中的方法。
3.4.2 包是模块的升级
如果以模块的形式复用代码出现了模块冲突的情况,则无法导入实现功能不同但名字相同的模块,为了解决这个问题,可以用包的形式来复用现有功能。
从表现形式上来看,包是一个目录,其中包含若干个扩展名为.py的模块,而且包里还得包含一个__init__.py的文件,哪怕这个文件是空的也行。这样就可以通过“包名.模块名”的方式来复用模块,从而能避免模块冲突的情况。
下面来实践一下。按照如下步骤来创建一个包,在charter3的项目中,新建一个名为myPackage的目录,随后在其中放入如图3-1所示的文件。
图3-1 包组织结构的示意图
__init__.py文件是每个包所必有的,否则会出错,这里仅是个空文件。范例程序ModuleDemo.py在3.5.1小节已经给出,新加的CalModuleDemo.py模块代码如下:
1 # !/usr/bin/env python 2 # coding=utf-8 3 E=2.718 4 G=9.8 5 def calGravity (m): 6 return m*G
在第3行和第4行定义了两个变量,而在第5行中封装了calGravity方法。这样,在myPackage这个包中放入一个__init__.py类。
随后在charter3项目中新建一个名为UsePackageDemo.py的文件,在其中调用包中的模块,代码如下。
1 # !/usr/bin/env python 2 # coding=utf-8 3 import myPackage.CalModuleDemo as calTool 4 from myPackage import ModuleDemo as myTool 5 print(myTool.PI) # 3.14 6 print (calTool.calGravity(10)) # 98.0 7 print (calTool.E) # 2.718
请注意第3行和第4行导入包中模块的方式,在第3行是通过“包名.模块名”的方式导入CalModuleDemo这个模块,而在第4行则是通过“from包名import模块名”的方式导入模块。导入后,则可以如第5行到第7行所示,通过“别名.属性”和“别名.方法名”的方式来调用。
3.4.3 导入并使用第三方库NumPy的步骤
Python中的模块(Module)和包(Package)都能被称为“库”,在实际的项目中,很多时候是通过导入第三方库,也就是复用库中封装的诸多功能。为了全书名称的统一,后面提及第三方模块或包的时候,都统一称为库。单独提及库名的时候,库名的第一个英文字母都用大写,在程序代码中用import导入库或程序语句中特指库名称时,则回归库名原始的英文名称大小写习惯。
比如之前用到的列表等功能类即是封装在Python标准库中的,在本书之后的篇幅中还会用到一些开源库。下面将以NumPy这个开源的科学计算库为例,演示一下导入并使用第三方库的具体步骤。
由于我们安装的是python3.4.4版本,因此在Scripts目录中能看到pip.exe,如图3-2所示。
图3-2 pip.exe所在的文件夹
请确保在环境变量的Path里,已经设置了pip.exe所在的路径D:\Python34\Scripts。
在“命令提示符”窗口中,执行命令pip install -U numpy,其中-U表示以当前用户的身份安装,安装好以后,会告知安装到了哪个路径。
依次单击“Window”→“Preferences”菜单,在随后弹出的对话框的左侧,找到PyDev,并在“Interpreter – Python”这个选项中,在System PATHONPATH框内,单击“New Folder”按钮,而后添加NumPy库的安装路径,如图3-3所示,这样在项目中就可以调用NumPy库中的方法或函数了。
图3-3 设置NumPy安装所在的路径
完成上述步骤后,就可以调用NumPy库中的方法了,范例程序NumpyDemo.py中的代码如下。
1 # !/usr/bin/env python 2 # coding=utf-8 3 import numpy as np # 导入NumPy库,起了个别名np 4 arr=np.array(np.arange(4)) # 创建一个序列 5 print(arr) # 输出 [0 1 2 3] 6 print(np.eye(2)) # 创建一个维度是2的对角矩阵,输出如下 7 # [[1. 0.] 8 # [0. 1.]]
通过调用NumPy库提供的方法,就能对数组序列和矩阵进行计算。本节的重点不是讲述NumPy库中有哪些方法,而是以这个库为例,介绍如何通过pip命令安装并导入第三方库。在后续章节中,还会用到其他第三方库,也可以照此方法导入。