4.5 模块和包
模块往往对应着Python的脚本文件(.py),包含了所有该模块定义的函数、变量和类。模块是最高级别的程序组织单元,它能够将程序代码和数据封装以便重用。模块可以被别的程序导入,以使用该模块的函数等功能,这也是使用Python标准库的方法。导入模块后,在该模块文件中定义的所有变量名都会以被导入模块对象成员的形式被调用。
包使用“.模块名”来组织Python模块名称空间。具体来讲包就是一个包含__init__.py文件的文件夹,创建包的目的就是用文件夹将文件和模块组织起来,将这些功能相似的模块使用包组成层次组织结构,以便使用和维护。包可以包含子包,没有层次限制。使用包可以有效地避免名称空间冲突。
4.5.1 模块与包的导入
1.模块的导入
模块是一个包含所有定义的函数和变量的文件,其后缀名是.py。使用import语句可以导入模块。模块导入的基本形式如下:
下面通过实例介绍模块的创建及导入使用的方法。
【例4-24】创建模块my_math,在模块中定义算术四则运算。
参考程序如下:
模块的导入是通过import语句实现的,在下面的测试程序中使用import导入my_math模块,然后通过模块名称调用模块中定义的每个函数。基本格式为“模块名.函数名”。
【例4-25】编写程序,在程序中使用my_math中定义的函数。
参考程序如下:
程序运行结果如下:
Python还可以使用“from模块名import函数名”的形式使用模块中定义的函数。例如,下面代码从上面创建的模块my_math中导入add函数,这样就可以直接使用add函数,而不用再使用“模块名.函数名”的方式使用add方法了。
运行结果如下:
2.包的导入
Python模块是.py文件,而包是文件夹。只要文件夹中包含一个特殊的文件__init__.py,Python解释器就将该文件夹作为包,其中的模块文件则属于包中的模块。包可以包含子包,没有层次限制。特殊文件__init__.py可以为空,也可以包含属于包的代码,当导入包或该包中的模块时执行__init__.py。
例如,若E:\Python\chapter4\目录中包含以下目录:
则package1是顶级包,包含子包subPackage1 和subPackage2,包subPackage1 包含模块mod-ule11. py、module12. py和module13. py,包subPackage2包含模块module21. py、module22. py和module23. py。
创建包就是在指定目录中创建对应包名称的目录(文件夹),然后在该目录下创建一个特殊文件__init__.py,最后在该目录下创建模块文件。
包的导入与模块的导入相似,使用import语句导入包中模块时,需要指定对应的包名。其基本格式如下:
其中包名是模块的上层组织包的名称,即模块所属文件夹的名称。
导入包中模块后,可以使用全限定名称访问包中模块定义的成员。其基本格式如下:
还可以使用from… import语句直接使用包中模块的成员。其基本格式如下:
如果希望同时导入一个包中的所有模块,可以采用下面方法:
同一个包/子包的模块可以直接使用import导入相同包/子包的模块,不需要指定包名。因为同一个包/子包的模块位于同一个目录。例如,subPackage1中包含模块module11和module12,则在module12中可通过import module11直接导入module11。
4.5.2 常用模块
Python语言中的常用模块主要包括:math模块、random模块、datetime模块、time模块、logging模块、sys模块和正则表达式re模块等。
1.math模块
math模块是一个封装了多个数学函数和变量的模块。表4-1列出了常见的函数和变量。
表4-1 模块math中一些常见的函数和变量
【例4-26】编写程序,展示math模块中函数的应用。
参考程序如下:
程序运行结果如下:
math模块中还有很多其他函数,比如sin(x)、cos(x)和tan(x)等函数,具体用法可以通过Python命令help查看帮助文档。例如,使用Python自带的IDLE,利用help(math)查看内置模块math中各种函数的用法。
2.random模块
random模块封装了多种随机函数,常见函数如表4-2所示。
表4-2 模块random中一些常见的函数和变量
(续)
【例4-27】编写程序,使用random模块中的函数随机生成5位字符。
参考程序如下:
程序运行结果如下:
3.datetime模块
datetime模块是date和time模块的合集,datetime有两个常量MAXYEAR和MINYEAR,分别是9999和1。datetime模块定义了5个类,表4-3描述了模块datatime中一些重要的类。
表4-3 模块datetime中一些重要的类
1)date类及其方法
date类中有用于获取当前时间、操作时间和日期、从字符串中读取日期、将日期格式化为字符串的方法。下面通过一个实例介绍date类及其方法的用法。
【例4-28】编写程序,使用date类及方法操作时间和日期。
参考程序如下:
程序运行结果如下:
2)datetime类及其方法
datetime类有很多参数,datetime(year, month, day[, hour[,minute[, second[, microsecond[,tzinfo]]]]]),返回年月日和时分秒。
例如:
程序运行结果如下:
3)time类及其方法
time类有5个参数,datetime.time(hour,minute,second,microsecond,tzoninfo)。time类及方法的使用方法如下所示:
运行结果如下:
4)timedelta类及其方法
datetime.datetime.timedelta类用于计算两个日期之间的差值。timedelta类及方法的使用方法如下所示:
运行结果如下:
4.time模块
模块time包含用于获取当前时间、操作时间和日期、从字符串中读取日期、将日期格式化为字符串的函数。表4-4描述了模块time中一些重要的函数。
表4-4 模块time中一些重要的函数
下面结合代码实例分别介绍每个函数的用法。
1)time()函数
以时间戳的形式显示当前时间:从新纪元开始后的秒数,以UTC为准从1970年1月1日00:00:00开始按秒计算的偏移量。“新纪元”是一个随平台而异的年份,在UNIX中为1970年。代码如下:
程序运行结果如下:
2)asctime([tuple])函数
将时间元组转换为字符串,没有时间元组参数时默认将当前时间转换为字符串。代码如下:
程序运行结果如下:
3)localtime([secs])函数
将秒数转换为表示当地时间的日期元组,没有参数时默认将当前时间表示为当地时间的日期元组。代码如下:
运行结果如下:
如果要显示格林尼治时间,可以用gmtime()将一个时间戳转换为UTC时区(0时区)的struct_time。
运行结果如下:
4)strptime(string[, format])函数
将字符串转换为时间元组。代码如下:
运行结果如下:
5)mktime(tuple)函数
mktime()函数执行与gmtime()和localtime()相反的操作,它接收struct_time对象作为参数,返回用秒数来表示时间的浮点数。如果输入的值不是一个合法的时间,将触发OverflowError或ValueError。代码如下:
运行结果如下:
6)sleep(secs)函数
sleep()函数推迟调用线程的运行,可通过参数secs(秒数)表示进程挂起的时间。代码如下:
运行结果如下:
5.logging模块
很多程序都有记录日志的需求,并且日志中包含的信息既有正常的程序访问日志,还可能有错误和警告等信息输出,Python的logging模块提供了标准的日志接口,可以通过它存储各种格式的日志,logging的日志可以分为debug()、info()、warning()、error()和critical()5个级别。
1)在控制台进行显示。使用logging.info('xxxxx')方法在控制台显示日志信息,简单用法如以下程序代码所示:
运行结果如下:
2)在日志中输出。使用logging.basicConfig()方法将日志信息保存在日志文件中,具体使用方法如以下程序代码所示:
运行结果为在程序源文件目录中生成一个日志文件access.log,文件具体内容为:
其中basicConfig方法对日志信息进行配置时必须以key-value形式使用,format=%(asctime)s为字符串形式的当前时间、%(message)s为用户输出的消息、datefmt='%m/%d/%Y%I:%M:%S%p'指时间格式为月/日/年 小时:分:秒 上下午。
3)日志与控制台同时输出。
Python使用logging模块记录日志涉及4个主要类。
● logger:提供应用程序可以直接使用的接口。
● handler:将logger创建的日志记录发送到合适的目的输出。
● filter:提供过滤条件,输出指定的日志记录。
● formatter:设置日志记录的输出格式。
控制台和日志文件同时输出的具体步骤为。
● 生成logger对象。
● 生成handler对象。
● 把handler对象绑定到logger对象。
● 生成formatter对象。
● 将formatter对象绑定到handler对象。
【例4-29】编写程序,使用logging模块同时实现控制台日志输出和生成日志文件。
参考程序如下:
程序运行结果如下:
同时在源文件目录下生成日志文件acess.log,日志文件内容同控制台输出的一样。
6.sys模块
sys模块负责程序与Python解释器的交互,提供了一系列的函数和变量,用于操控Python运行时的环境。表4-5列出了其中的一些函数。
表4-5 模块sys中一些重要的函数和变量
【例4-30】编写程序,使用sys模块动态接收命令行参数。
参考程序如下:
程序运行结果如下:
【例4-31】编写程序,使用sys.stdout实现标准输出。
参考程序如下:
程序运行结果如下:
7.正则表达式re模块
在进行文本处理时,常常需要查找符合某些复杂规则的字符串。正则表达式语言就是用于描述这些规则的语言。使用正则表达式可以匹配和查找特定的字符串,并对其进行相应的处理和修改。正则表达式广泛应用于各种字符串处理应用程序中,如HTML处理、日志文件分析和HTML表头分析等。
正则表达式是由普通字符(如字符a~z)及特殊字符(称为元字符,包括.、^、$、∗、+、?、{}、[]、\、|和())组成的文字模式。正则表达式的模式可以包含普通字符(包括转义字符)、字符类和预定义的字符类、边界匹配符、重复限定符、选择分支、分组和引用等。
Python语言使用re模块实现正则表达式处理的功能。导入re模块后,使用findall()和search()函数可以进行匹配。具体使用语法如下。
re.findall(pattern,string):如果匹配,返回匹配结果列表,否则返回空列表。
re.search(pattern,string):如果匹配,返回匹配对象,否则返回None。
re.match(pattern,string):如果匹配,返回匹配对象,否则返回None。
search和match只匹配一次,findall匹配所有。
re模块函数使用方法如下代码所示:
1)普通字符和转义字符
最基本的正则表达式由单个或多个普通字符组成,用以匹配字符串中对应的单个或多个普通字符串。普通字符包括ASCII字符、Unicode字符和转义字符。另外,正则表达式中的元字符(.、^、$、∗、+、?、{}、[]、\、|和( ))包含特殊含义,如果要作为普通字符使用需要进行转义。例如,\b在正则表达式中表示单词边界,而在字符串中的转义字符表示退格字符。因此在正则表达式中,这些与标准转义字符重复的特殊字符必须使用两个反斜杠字符('\\'),或使用原始字符串r' '或r'。下面代码示例为转义字符的使用方法:
2)字符类和预定义字符类
字符类是由一对方括号[]括起来的字符集,正则表达式引擎匹配字符集中的任意一个字符。字符类的定义方式包括以下几种。
●[xyz]:枚举字符集,匹配括号中的任意字符。例如,"g[oeu]t",匹配"got""get"和"gut"。
●[^xyz]:否定枚举字符集,匹配不在此括号中的任意字符。
●[a-z]:指定范围的字符,匹配指定范围内的任意字符。
●[^a-z]:指定范围以外的字符,匹配指定范围以外的任意字符。
字符类使用方法如下所示:
使用正则表达式时常常用到一些特定的字符类,如数字、字母。正则表达式语言包含若干预定义的字符类,这些预定义的字符集通常使用缩写形式,例如,\d等价于[0-9]。常用的预定义字符类见表4-6。
表4-6 常用的预定义字符类
3)边界匹配符
字符串匹配往往涉及从某个位置开始匹配,例如,行的开始或结尾、单词边界等。边界匹配符用于匹配字符串的位置。常用的边界匹配符见表4-7。
表4-7 常用的边界匹配符
4)重复限定符
使用重复限定符可以指定重复的次数。常用的重复限定符见表4-8。
表4-8 常用的重复限定符
5)正则表达式对象
使用re.compile函数可以将正则表达式编译为正则表达式对象regex,然后使用其对象方法处理字符串。其基本语法格式如下。
regex=re.compile(pattern,flags=0):编译模式,生成正则表达式对象。
regex.search(string[,pos[,endpos]]):若匹配,返回匹配对象,否则返回None。
regex.match(string[,pos[,endpos]]):若匹配,返回匹配对象,否则返回None。
regex.findall(string[,pos[,endpos]]):若匹配,返回匹配结果列表,若pattern中包含组,返回组的列表,否则返回[]。
regex.finditer(string[,pos[,endpos]]):返回多个匹配结果的迭代器。
其中,pattern为匹配模式;string为要匹配的字符串;flags为匹配选项;pos和endpos为搜索范围,从pos到endpos-1。正则表达式对象的使用方法如下所示。
【例4-32】编写程序,使用re模块验证一个字符串是否为有效的电子邮件格式。
参考程序如下:
程序运行结果如下: