目录
Python基础(七)--模块和包
1 模块
1.1 什么是模块
1.2 模块的使用
1.3 模块的搜索路径
1.4 模块的缓存
2 包
2.1 什么是包
2.2 包的使用
3 常用模块
3.1 math
3.2 random
3.3 time
3.4 datetime
3.5 sys
Python基础(七)--模块和包
1 模块
1.1 什么是模块
模块是一个Python文件,该文件包含相关的定义与语句(类,函数,变量)。模块具有名称,名称与文件的名称一致。
使用模块的好处:
①通过划分若干个模块,将项目程序进行明确的划分,从而将复杂问题简单化,同时,也能够进行更加合理的分工,有利于协作式开发程序。
②模块提供独立的命名空间,可以解决命名上的冲突。不同的模块中,定义相同名称的变量,不会产生命名冲突
③模块可以实现良好的重用性,在多人间实现共享。
1.2 模块的使用
每个项目可以划分为多个模块。但模块与模块之间,不可能都是完全孤立的。一个模块很可能需要与其他的一个(或多个)模块进行交互,因此,当需要在一个模块中使用其他模块定义的名称(函数,类,变量等),则需要首先导入该模块,然后通过模块名.名称进行访问。
(1)导入模块
使用import对模块进行导入:import 模块
我们还可以一次导入多个模块:import 模块1,模块2……
当导入模块时,该模块内的语句就会得到执行,但只会执行一次,即重复导入模块不会多次执行。当模块作为脚本执行时(使用python命令在命令行执行),模块中的语句也会得到执行。按照惯例,模块导入语句写在模块的最上方。
当导入模块后,我们就可以使用模块中所定义的名称,格式为:模块名.名称
①访问模块:可以将其他模块中定义的名称(全局命名空间中的名称)直接导入到当前模块的命名空间,这样,我们就可以直接通过名称访问,而无需使用模块名限定。格式如下:from 模块 import 名称1,名称2……
注意:这种导入方式要稍加留意,因为如果当前模块中也存在同样名称的定义,就会造成名称的冲突,也就是名称会重新绑定后来的对象。
②模块冲突:假设不考虑名称的冲突,只考虑访问的便捷性,使用from import的方式确实是不错的选择。但是,如果我们要使用该模块中定义的很多名称,一个个的导入可能会有些繁琐,此时,我们可以使用批量导入:from 模块 import *
这样就会将模块中除了以_开头的所有名称导入到当前模块的命名空间。然而,这种方式会导入很多名称,容易造成命名冲突,尽可能少用。
注意:在Python中一切都是对象,模块也是一个对象 。使用import导入模块的时候,模块定义的语句就会执行
(2)模块别名
当导入模块(或模块中的名称)时,我们可以使用as为模块(或模块中的名称)指定别名。语法如下:
import 模块名 as 模块别名
from 模块名 import 名称 as 名称别名
这样,我们就可以通过别名来访问模块(或模块中的名称)。但是,一旦指定别名后,原模块名(或原模块中的名称)将不再可用。
别名的好处:①解决名称冲突,②使用简短的别名,减少输入量。
(3)隐藏模块数据
因为使用import *的语法会在当前命名空间增加很多名称,为了减少import *所造成的影响(名称冲突),我们可以有选择性的隐藏模块的数据,进而限制使用import *时,名称的导入。
隐藏模块数据可以采用两种方式:①将名称以下划线(_)开头。②定义__all__变量。
上面两种隐藏方式仅是限制使用import *语法导入的名称,并不是表示该名称无法在模块外访问。使用import其他方式导入,还是能够在模块外进行访问的。他们的顺序为,会首先检查__all__变量,如果存在,会将__all__中指定的名称导入到当前的命名空间。如果不存在,则会将除下划线(_)开头的名称导入到当前的命名空间。即__all__中即使指定以下划线(_)开头的名称,该名称依然可以成功导入到当前的命名空间中。
①将名称以下划线(_)开头:如果模块中定义的名称以_开头,则在使用import *语法时,这些名称不会导入到当前模块的命名空间中,即当前模块无法直接访问该名称。
②定义__all__变量:如果使用from 模块 import *的语法,则默认情况下会导入模块中除_开头的所有名称,这容易与当前模块的命名造成冲突。我们可以定义__all__变量来限制导出名称的数量。当在模块中定义__all__变量时,该变量的值为一个字符串列表,只有列表中指定的名称才会导入到当前命名空间。
# 为了减少命名冲突,可以限制from 模块名 import * 的导入模块
# 显示的方式有两种:1.名称前使用_ 2.在模块内定义__all__关联一个str类型的列表(列表中指定所有能用*导入的名称)
# 它们的顺序为:先查看__all__名称,如果该名称存在,则导入列表中所有的元素指定的名称,如果不存在,则导入
# 该模块下所有未使用_开头的名称,这意味着如果__all__中指定了_开头的名称,一样可以导入
from lead import *
print(a,b,_c)
print(__name__)
print("lead模块执行了")
# 指定可以由from import * 导入的名称
__all__ = ["a","b","_c"]
a = "在lead模块中定义的变量"
def b():print("在lead模块中定义的函数")
_c = "不会被from import * 语法导入"
d = "不在__all__列表内"print("lead模块的__name__名称:" + __name__)
(4)__name__
在编写模块时,我们可能需要对当前模块的功能进行测试。当我们在其他模块中导入当前模块时,测试内容就会得到执行,这并不是期望的。因此,我们不得不将其去掉或者注释。可是,以后还需要再写入新的测试代码来验证新增功能的正确性,如此反复,非常不方便。
解决方法是:我们可以通过__name__属性来获取模块的名称。模块会在两种情况下执行:①当模块由其他模块导入时;②当模块作为脚本,在命令行使用python 文件名.py执行时。两种执行方式,通过__name__获取的模块名称是不一致的。当模块由其他模块导入时,模块的名称就是文件的名称,而模块作为脚本执行时,模块的名称为__main__。因此,我们可以据此获取模块执行的方式。
# __name__名称
# 作为脚本运行的模块,__name__固定返回__name__
# 作为被其他模块导入而运行时,__name__返回的就是当前模块的名称
# 为了方便测试,我们可以将测试语句写在:if __name__ == "__name__"中
def is_even_number(number):return number % 2 == 0
# 如果当前模块是作为脚本而执行没说明在测试该模块的功能,测试语句得到执行
if __name__ == "__name__":print(is_even_number(5))print(is_even_number(6))
1.3 模块的搜索路径
当我们导入模块时,解释器会按照如下顺序搜索:
①内置与解释器中的模块,如sys,math等;
②作为脚本执行的模块所在路径;
③PYTHONPATH环境变量指定的路径,如果该环境没有设置则忽略;
④Python安装相关路径,这包含Python语言的内建模块(os, random模块),以及安装的第三方模块(beautifulsoup,numpy模块)所在的路径等。
可以通过sys模块的path属性获得路径信息。path的值(列表类型)就是由后三项按顺序组成的(后三项路径的并集)。解释器会在这些路径中寻找模块名.py文件。
解释器会按顺序进行查找,以先找到的为准。因此,如果在不同的路径中都存在满足条件的模块,会以先找到的为准。
1.4 模块的缓存
导入模块时,Python会缓存所加载模块编译后的版本。从实现的角度,就是将导入模块的文件(*.py)编程成字节码文件(*.pyc)。这样在下次运行时,就会检查字节码所对应的源文件在编译过后是否经过修改,即字节码文件是否是对应源文件的最新版本。如果不是最新版本,则会对源文件重新进行编译。如果已经是最新版本,则会从字节码文件中读取信息,这样可以加快模块的加载速度。
编译的字节码(*.pyc)文件是平台无关的,即不管在什么平台,只要Python源文件的内容相同,编译过后的字节码文件也相同。字节码文件会保存在与作为脚本运行文件相同路径下的__pycache__目录中。格式为“模块名.解释器-版本.pyc”,例如,假设导入的模块为test,解释器为CPython3.6,则字节码文件名为“test.cpython-36.pyc”。
注意:①缓存字节码文件只是可以提供模块加载的速度,并不会提高模块运行的速度。
②只有导入的模块才会生成字节码文件,作为脚本运行的文件不会生成字节码文件。
③字节码文件可以脱离源文件而运行。
2 包
2.1 什么是包
包类似于操作系统中的文件夹(目录,路径)
包的作用:①提供对模块的分类管理
②提供独立的命名空间,可以解决模块的命名冲突
2.2 包的使用
(1)导入包
目录与子目录,目录与文件之间,使用特定的分隔符进行分隔。例如,Windows操作系统使用“\”,Linux系统使用“/”。同样,包也可以含有子包,包与包,包与模块之间使用“.”来分隔。可以通过import来导入包,或者是导入包中的模块。与之前导入模块的语法是相同的,例如:
import 包名
import 包名.模块名
from 包名 import 模块名
from 包名.模块名 import 名称
上面导入包的方式,我们称为绝对导入,此外,我们也可以进行相对导入。我们使用“.”来表示当前模块所在的包,使用“..”来表示当前模块所在包的父包(上级包)。例如:
from . import 名称
(2)__init__.py
在每一个包中,应该同时配有一个__init__.py文件(模块)。它的作用如下:
①该文件用来标记,当前的路径是一个包,而不是普通的目录,以避免目录名与模块名造成混淆
②该文件为包的初始化模块,当导入包,或者导入包的子包(子模块)时,该模块会自动执行。因此,我们可以在__init__.py中编写一些包的初始化语句;
③在__init__.py中定义的,具有全局作用域的名称,可以使用包名.名称进行访问(这些名称就会成为包(对象)的属性)
(3)__all__
我们可以在__init__.py中定义__all__变量,来控制导入哪些名称,这与模块中的定义的__all__变量意义相同,也是一个字符串的列表类型,指定能够导入的名称。
3 常用模块
3.1 math
math模块提供了与数学计算相关的功能。常用的功能如下:
名称 | 描述 |
pi | 返回圆周率的值 |
e | 返回数学常数 |
ceil(x) | 返回大于等于x的最小整数(向上取整) |
floor(x) | 返回小于等于x的最大整数(向下取整) |
exp(x) | 返回e的x次幂,相当于math.e**x |
pow(x,y) | 返回x的y次幂,相当于x**y |
log(x[,base]) | 返回基于base为底,x的对数。base默认为e |
fabs(x) | 返回x(视为float类型)的绝对值 |
factorial(x) | 返回x的阶乘,x需要是int类型,或者是小数点为0的浮点类型,并且不能为负。 |
fmod(x,y) | 返回x与y取余的结果。注意:x % y是取模,二者结果可能是不同的。 |
fsum(itreable) | 返回可迭代对象中每个值累计求和后的结果。 |
gcd(x,y) | 返回x与y的最大公约数。x与y需要是整数类型 |
sqrt(x) | 返回x的平方根 |
3.2 random
random模块提供生成随机数的功能(伪随机数)。常用功能如下:
名称 | 描述 |
random() | 返回一个0~1之间的浮点数,包括0不包括1 |
randint(a,b) | 返回一个a~b之间的整数,包括a与b |
randrange(stop)/ randrange(start,stop[.step]) | 参数与range函数的意义相同,相当于从相同参数的range函数可能产生的值中,随便选择一个 |
uniform(a,b) | 返回a与b之间的浮点数,包括端点 |
choice(seq) | 从seq(可迭代对象)中随机选择一个元素,如果序列为空,则产生错误 |
choices(population, weights=None, *, cum_weights=None, k=1) | 从population(可迭代对象)中选择k个元素,放入一个列表并返回。如果提供了weights(权重)或cum_weights(累积权重),则元素的选择概率会根据权重(累积权重)决定。权重与累积权重不能同时指定,因为权重内部会转换成累积权重,这样会造成不一致。如果没有指定权重与累积权重,则各个元素的选择概率相同。 |
sample(population, k) | 从population(可迭代对象)中选择k个不同的元素,返回元素组成的列表。 |
shuffle(x[, random]) | 对x(序列)进行洗牌(随机分配每个元素的位置)。random是一个可选的生成随机数的函数,函数的返回值为[0, 1),默认使用random模块的random函数。 |
3.3 time
time模块提供关于时间的操作
名称 | 描述 |
timezone | 返回与UTC时间(世界标准时间)相差的秒数。正数表示晚于UTC时间,负数表示早于UTC时间。 |
time() | 返回从新纪元(1970-01-01 00:00:00)到当前时间走过的秒数。 |
localtime([seconds]) | 返回从新纪元走过seconds(秒数)后的时间。返回类型为time.struct_time类型(tuple的子类),如果seconds没有指定,则默认表示当前时间。该时间显示的是本地时间,要考虑对应的时区。例如,北京时间为东八区,比UTC时间早8小时,因此,需要在最后转换的时间上加上8小时。struct_time是一个命名元组(可以通过属性名访问,也可以通过索引访问) |
gmtime([seconds]) | 与localtime([seconds])的用法相同,只是返回的是UTC时间,而不是本地时间。 |
mktime(tuple) | 将tuple(本地时间的元组)转换为从新纪元到元组指定时间走过的秒数。与localtime([seconds])函数正好是相反的 |
asctime([tuple]) | 将tuple(时间元组)转换成字符串(str)的表示形式。如果没有提供tuple参数,则使用localtime()函数返回的元组(当前的本地时间)。 |
ctime([tuple]) | 将从新纪元走过的毫秒数转换为本地时间。该函数相当于这样调用:asctime(localtime(seconds))。如果seconds参数没有指定,则使用time()函数返回的秒数。 |
sleep(seconds) | 使当前程序暂停执行参数指定的时间。seconds可以是小数。 |
clock() | 在Unix / Linux系统,该函数返回CPU的计算时间。在Windows操作系统,该函数第一次调用,返回CPU的计算时间,从第二次调用开始,返回距离第一次调用该函数所经历的时间。CPU的计算时间不包括调用sleep暂停的时间,因为在暂停时,CPU没有工作。因为该函数在不同操作系统上行为的不一致性,从Python3.3起,已经不建议使用,取而代之的是使用perf_counter()函数或者是 process_time()函数。 |
perf_counter() | 返回精准的性能计数器,可以用来测试短时间的时间差。该时间包含调用sleep函数暂停的时间。该函数返回值所基于的时间点是不确定的,我们不能当成系统时钟来使用,但是可以多次调用该函数,计算一段程序执行的时间差。 |
process_time() | 返回当前进程下,系统以及用户的CPU计算时间。该时间不包含调用sleep函数暂停的时间。 |
strftime(format[, tuple]) -> string | 将tuple(时间元组)转换成format参数指定的格式的字符串。如果tuple没有指定,则使用localtime()函数返回的元组。format中可以含有特殊占位符,将使用元组中特定值进行替换,非特殊占位符会原样显示。 |
strptime(string, format) -> struct_time | 按照format指定的格式,将string(时间格式字符串)解析为时间的元组。format的格式与strftime函数的format格式相同 |
struct_time类的格式
索引 | 属性名 | 说明 |
0 | tm_year | 年(四位数表示)。 |
1 | tm_mon | 月份(1 ~ 12)。 |
2 | tm_mday | 日(1 ~ 31)。 |
3 | tm_hour | 小时(0 ~ 23)。 |
4 | tm_min | 分(0 ~ 59)。 |
5 | tm_sec | 秒(0 ~ 61),60用来表示闰秒(跳秒),是对世界时间的一种调整。61因为历史原因所保留。 |
6 | tm_wday | 星期(0 ~ 6),周一为0,周日为6。 |
7 | tm_yday | 年度的第几天(1 ~ 366)。 |
8 | tm_isdst | 是否支持DST(daylight saving time),即夏令时(日光节约时间)。部分国家在天亮早的夏季,将时钟向前调整一小时,从而可以节约照明资源。可能值为0(不生效)、1(生效)或-1(未知)。 |
占位符
占位符 | 说明 |
%Y | 年份(四位数字)。 |
%y | 年份(两位数字)。 |
%m | 月份(01 ~ 12)。 |
%d | 日(01 ~ 31)。 |
%H | 24小时制(00 ~ 23) |
%I | 12小时制(00 ~ 12) |
%M | 分钟(00 ~ 59)。 |
%S | 秒(00 ~ 61)。 |
%w | 周期几(0 ~ 6),周日为0。注意,与tm_wday的表示不一致。 |
%j | 年度的第几天(001 ~ 366)。 |
%W | 年度的第几周(00 ~ 53),星期一视为一周的第一天。在年度第一个周一之前的天视为第0周。 |
%U | 年度的第几周(00 ~ 53),星期日视为一周的第一天。在年度第一个周日之前的天视为第0周。 |
%z | 当前时区与UTC的时间差。格式为+HHMM(当前时区早于UTC)或-HHMM(当前时区晚于UTC)。 |
%Z | 时区名称。 |
%a | 本地星期的简写名。 |
%A | 本地星期的全名。 |
%b | 本地月份的简写名。 |
%B | 本地月份的全名。 |
%c | 本地日期与时间的恰当表示。 |
%x | 本地日期的恰当表示。 |
%X | 本地时间的恰当表示。 |
%p | 显示AM或PM(或其本地等效的其他表示方式)。 |
%% | %的转义。 |
3.4 datetime
datetime模块提供date,time,datetime,timedelta等类,供我们对日期与时间进行操作。与time模块相比,datetime模块还额外增加了日期的加减与比较运算。
(1)date类
date类提供针对日期(不含时间)的操作。
构造器 | date(year, month, day):用来创建参数指定日期的date对象。year指定年,month指定月,day指定日。 |
实例属性 | year / month / day:返回年 / 月 / 日 |
类属性 | max / min:最早的 / 最晚的date对象; resolution:类属性两个不同date对象的最小差距值 |
实例方法 | ctime():返回特定格式的字符串来表示日期; replace(year=self.year, month=self.month, day=self.day):返回新的date对象,值为使用当前参数替换之后的结果。year指定要替换的年,month指定要替换的月,day指定要替换的日; timetuple ():返回time.struct_time对象,类似于time.localtime()返回的结果; weekday():返回当前日期是星期几(0 ~ 6)。星期一返回0,星期日返回6。 toordinal():返回当前日期的序数。1年1月1日序数为1,1年1月2日序数为2,以此类推; strftime(format):根据format指定的格式,显示当前的日期对象。 |
类方法 | today():类方法,返回当前的日期。 fromtimestamp(timestamp):从参数指定的timestamp(时间戳,即从新纪元走过的秒数)中创建date对象。 fromordinal(ordinal):根据参数指定的ordinal(序数)创建date对象。 |
(2)time类
time类提供针对时间的操作
构造器 | time(hour=0, minute=0, second=0, microsecond=0):创建参数指定的time对象。hour指定小时,minute指定分钟,second指定秒,micorsecond指定微秒。 |
实例属性 | hour / minute / second / microsecond:返回小时 / 分钟 / 秒 / 微秒 |
类属性 | max / min:最早的 / 最晚的time对象; resolution:类属性两个不同time对象的最小差距值 |
实例方法 | replace(hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond):创建一个新的time对象,值为参数指定的值替换之后的结果。hour指定要替换的小时,minute指定要替换的分钟,second指定要替换的秒,microsecond指定要替换的微秒。 strftime(format):根据format指定的格式,显示当前的时间对象。 |
(3)datetime类
datetime类提供针对日期与时间的操作,相当于是date与time两个类功能的并集。
构造器 | datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0):用来创建参数指定日期的datetime对象。year,month与day三个参数是必须的。 |
实例属性 | year / month / day:返回年 / 月 / 日 hour / minute / second / microsecond:返回小时 / 分钟 / 秒 / 微秒。 |
类属性 | max / min:最早的 / 最晚的datetime对象; resolution:类属性两个不同datetime对象的最小差距值 |
实例方法 | date():返回date对象,年,月,日与datetime对象的年,月,日相同。 time():返回time对象,时,分,秒,微秒与datetime对象的时,分,秒,微秒相同。 ctime():返回特定格式的字符串来表示日期时间。 replace(year=self.year, month=self.month, day=self.day, hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond):返回新的datetime对象,值为使用当前参数替换之后的结果。 timetuple ():返回time.struct_time对象,类似于time.localtime()返回的结果。 weekday():返回当前日期是星期几(0 ~ 6)。星期一返回0,星期日返回6。 toordinal():返回当前日期的序数。1年1月1日序数为1,1年1月2日序数为2,以此类推。 strftime(format):根据format指定的格式,显示当前的日期时间对象。
|
类方法 | today():返回当前的日期与时间。 now():返回当前的日期与时间,与today方法类似。 utcnow():返回当前的日期与时间转换为UTC之后的结果。 fromtimestamp(timestamp):从参数指定的timestamp(时间戳,即从新纪元走过的秒数)中创建datetime对象。 utcfromtimestamp(timestamp):从参数指定的timestamp(时间戳,即从新纪元走过的秒数)中创建UTC datetime对象。 fromordinal(ordinal):根据参数指定的ordinal(序数)创建datetime对象。 strptime(date_string, format):根据给定的date_string(日期时间字符串),按照format指定的格式进行解析,返回datetime对象。 |
(4)timedelta类
timedelta对象用来表示持续时间,可以用来进行日期与时间的加减。
构造器;timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0):根据给定的参数,创建timedelta对象,表示持续时间。持续时间为各参数累计相加。
两个datetime.datetime类型相减 或两个 datetime.date类型相减 的结果就是datetime.timedelta类型
3.5 sys
sys模块提供一些与解释器相关的功能。sys提供的属性很多,不过多数并不常用,常见属性如下:
名称 | 描述 |
argv | 返回一个列表,列表的第一个元素为命令行运行的文件名称,往后的每个元素为命令行在文件名称后面传递的每一个参数。当我们要进行一些全局性,系统相关的配置时,就可以使用命令行来传递参数。所传递的参数就可以通过argv来进行获取。 |
version | 返回Python的版本信息 |
copyright | 返回Python的版权信息 |
path | 返回模块的搜索路径 |
float_info | 返回浮点类型(float)的相关信息 |
platform | 返回操作系统信息 |
exit() | 退出Python解释器,终止程序的执行 |
getsizeof(object) | 返回object(对象)的大小(以字节为单位) |
setrecursionlimit(n) | 设置最大递归的深度 |