Python语言和标准库(第六章:模块)
模块提供了一种程序之间共享python代码的便捷方式。python提供了几百个模块的库,您可以在脚步中调用它们,也可以创建自己的模块。
本章介绍
研究模块的内部机制
创建一个仅包含函数的模块
在模块中定义类
通过子类扩展类
定义异常来报告错误状态
为模块建立文档
测试模块
将模块作为程序运行
安装模块
5.1研究模块
模块只是一个python源文件,它可以包含变量,类,函数和python脚本中可用到的其他任何元素。
通过使用dir函数可以更好地理解模块,给dir函数传递某个python元素(例如模块)的名称,它将列出该元素的所有属性。例如,要查看_bulitins_的属性,包括内置函数,类和变量,可以使用下面语句
dir(_builtins_)
这将得到类似于下面的输出
对于python这样具有许多特性的语言,它的内置元素非常少。同样可以对导入的模块运行dir函数,例如:
使用dir有助于研究模块,包括自己创建的模块。
5.1.1导入模块
import module
可以对python自带或者您创建的模块使用这种语法,也可以使用如下所示的另一种语法:
from module import item
这样语法仅导入一个所需的一个item类或者item函数。
如果模块被修改,可以使用imp.reload(module)重新加载模块的新定义。
import module
import imp
imp.reload(module)
使用希望重新加载的模块替换module。
5.1.2查找模块
为了导入一个模块,python解释器首先需要找到他。对于一个模块,python解释器会先找到一个成为module.py的文件,其中module是传递给import语句的模块名称。当找到该模块时,python解释器会编译一个.pyc文件。
python解释器查找模块搜寻路径中的那部分目录。这些目录在sys模块中sys.path变量中列出。
要列出python解析器查找模块的位置,可以在python解释器中打印sys.path变量的值。
5.1.3理解模块
因为python是一个开源包,所以可以得到python解释器和所有模块的源代码。
首先,sys.path变量列出的所有目录中查找到.py结尾的文件。这些文件就是python模块,一些模块只包含函数,一些则包含类和函数,例如,python3.0种parser模块定义一个类:
这个小模块主要由引导用户如何使用该模块的文档组成。这也有助于理解如何创建自己模块。
5.2创建模块和包
创建一个具有函数的模块
输入下面的python代码,并将文件命名为food.py
这就是一个模块,接下来可以使用python解释器导入该模块,例如:
事例说明:
python使用非常简单的方法定义模块。可以使用任何python源文件作为一个模块,如这个简单的例子所示。
如果不加前缀food会出现问题,使用另一种语法导入模块能够解决这个问题。
5.3使用类
大多数模块定义了一个相关函数或类的集合,python默认能够访问类中的数据,这违反了一些面向对象编程的概念,当好处在于实用。
5.3.1定义面向对象编程
5.3.2创建类
创建一个meal类
meal类的每个实例保存3个数据值:meal类的名称,食物和饮料,meal类默认设置的名称为generic meal等等
5.3.3拓展已有的类
breakfast类通过如下所示的定义拓展meal类
还有
通过lunch类,可以看到setter方法的一些应用。
5.4完成模块
在定义模块的类和函数后,下一步就是完成模块,以使它更合适python用户和python解释器的约定。
完成模块包括很多工作,当至少需要完成以下操作
定义应用模块的错误和异常
定义模块中要输出的项,这定义了模块的公共API
为模块编写文档
测试模块
在模块作为程序执行的情况下提供一个回退函数
5.4.1定义模块特定的错误
大多数情况下,异常类不需要定义任何方法或者初始化任何数据,exception基类所提供的已经足够了。
注意:并非总是如此,例如一个XML解析异常也许应该包括发生初五的行号,以及对错物的描述
5.4.2选择导出哪些内容
使用from形式导入模块时,可以指定导入模块中的哪一项,例如,下面的语句从meal模块导入angrycheexception。
from meal AngryCheException
要从模块导入所有的公有项,可以使用下面格式:
from module_name import *
*告诉python解释器导入模块的全部公有方法。什么是公有方法?作为模块的设计者,您可以选择定义那些项作为能过导出的公有方法。
python解释器有两种方法
如果模块中定义了变量_all_
如果模块中没有定义变量_all_,解释器导入除了名称以 下划线_开头的项目之外的项目。如printIt是公有的,而_printIt不是公有的。
作为最佳实践,总是应该在模块中定义_all_.这样显式控制其他python脚本可以导入的项。为了完成这项工作,可以简单地创建一个文档字符串序列,每个字符串分别对应想要从模块导出的每个项的名称。
在meal模块中:
这个序列中的每个名称都是一个需从模块导出一个类或者函数
选择要导出的内容很重要,当创建一个模块时,就创建了一个执行一些有用的功能的api。从模块中导出的api定义了模块的用户能实现哪些功能。你希望导出模块的用户能够得到完成工作所需的全部功能,但是不需要导出一切,可能因为一些原因希望排除一些项。
可能要修改的项应该保持私有性,
模块时常有意隐藏复杂的代码(封装)
5.4.3为模块建立文档
为模块建立文档非常重要,否则没有人会知道模块能做哪些事情
浏览模块的文档
在交互模式下启动python解释器,然后像下面import和help命令:
help是您的助手,它可以显示模块的文档。
5.4.4测试模块
创建测试使您可以在修改模块后验证功能仍然有效
任何负责的模块都应该包含执行模块功能的测试函数,测试应该创建模块中定义的类的实例,例如,下面的方法提供了meal模块的一个测试:
将测试函数集成在模块中,这样测试将一直可用。
5.4.5将模块作为程序运行
通常,模块不应自己运行。其他python脚本会从模块中导入项并使用它们。然而,由于任何包含python代码的文件都可以看作一个模块,您可以运行一个模块。
因为不希望模块自己运行,python为模块定义了一个约定。当一个模块自己运行时它应该执行模块测试。这提供了测试模块的一个简单方式:将python模块作为一个脚本运行。
为了支持这个约定,python提供了一种简单的形式来检测模块是否作为一个程序运行。利用前面给出的test函数,可以使用下面的代码执行对模块的测试:
if _name_=='_main_': test()
如果查看标准python模块的源代码,将会反复碰到这样形式。
运行模块
可以通过使用如下命令行,将模块作为程序运行:
该实例将模块作为一个python程序运行,使用前面给出的形式检查这种情况,可以知道模块只运行test函数,您所看到的输出是测试的输出。
注意输出中运行了模块中定义的每个类的实例,并测试angryChefException异常的产生。
如果遵循本节中讲述的设计类的全部指导原则,模块将符合其他python开发人员的期望。而且,模块将在脚本中工作的更好。在下一节的实际应用中可以看这一切,它演示了一个完整的python模块。
5.5创建一个完整的模块
meal模块是根据本章讲述的技术创建一个完整的模块,包含测试,文档,异常,类和函数。注意测试几乎与其他代码一样长。您以后将经常看到这种情况。
构建模块之后,可以将它导入到python脚本中,例如,下面的脚本调用了meal模块中的类和函数:
这个例子使用了标准方法导入模块:
import meal
运行这个脚本时,间看到如下输出:
下一个脚本演示了导入模块的另一种方法:
from meal import *
全部脚本如下:
注意,使用这种导入形式时,不必使用模块名称meal作为前缀就可以调用makeLunch和makeBreakfast函数。
这个脚本的输出与上个脚本输出应该是类似的。
要十分小心使用的变量名称,示例模块的名称是meal,这意味着不能在其他任何上下文中使用这个名称,例如作为一个变量名称。如果那样做,就覆盖了作为模块的meal的定义,下面的例子演示了这个方法的缺陷。
5.6安装模块
python解释器在sys.path变量中列出的目录中查找模块,sys.path变量包括当前目录,所以总是可以使用当前路径中的模块。
大多数情况下,需要将python模块放到site-packages目录中,这个包不是python标准库的一部分。
可以使用三种机制安装模块:
a可以手动创建一个安装脚本或者程序
b可以创建一个针对您的操作系统的安装程序,例如windows上的MSI文件。
c可以使用方便的python distutils包,来创建基于python的安装文件。