python-模块,异常,环境管理器
模块 Module
什么是模块:
1、模块是一个包含有一系列数据,函数,类等组成的程序组
2、模块是一个文件,模块文件名通常以.py结尾
作用:
1、让一些相关数据,函数,类等有逻辑的组织在一起,使逻辑结构更加清晰
2、模块中的数据,函数和类等可提供给其它模块或程序使用
模块的分类:(同一个模块在不同的操作系统下可能数不同类型的模块)
1、内置模块(builtins),一般是用C语言来写的,在解析器的内部可以直接使用。模块说明中有builtins关键字
2、标准库模块,安装python时已经安装且可直接使用。
3、第三方模块(通常为开源),需要自己安装
4、用户自己完成的模块(可以作为其他人的第三方模块)
模块的导入语句
import语句
语法:import 模块名1 [as 模块新名1][,模块名2[ as 模块新名2]],....
作用:将某模块整体导入到当前模块
用法:模块.属性名
dir(obj)函数返回模块所有属性的字符串列表
help(obj)可以查看模块相关的文档字符串
from import语句
语法: from 模块名 import 模块属性名1[as 属性新名1] [,模块属性名2[as 属性新名2],....]
作用:将模块内的一个或多个属性导入到当前模块的作用域
说明:属性是模块内的所有全局变量
from import * 语句 (一般不用)
语法:from 模块名 import *
作用:将某模块的所有属性都导入到当前模块
dir函数:
dir([对象])返回一个字符串列表
作用:1、如果没有参数调用,则返回当前作用域内的所有变量的列表
2、如果给定一个对象作为参数,则返回这个对象的所有变量的列表
1)对于一个模块,返回这个模块的全部属性
2)对于一个类对象,返回这个类对象的所有变量,亲递归基类对象的所有变量
3)对于其它对象,返回所有的变量,类变量,基类变量
数学模块 math
变量:
math.e 自然对数的底e
math.pi 圆周率pi
函数:
math.ceil(x) 对x向上取整,比如x = 1.2 ,返回2
math.floor(x) 对x向下取整,比如x = 1.8 ,返回1
math.sqrt(x) 返回x的平方根
math.factorial(x) 求x的阶乘
math.log(x,[base]) 返回以base为底的x的对数,如果不给base,则以自然对数e为底
math.log10(x) 求以10为底x的对数
math.pow(x,y) 返回x**y
math.fabs(x) 返回浮点数x的绝对值,比如x = -1,返回1.0
角度degrees和弧度radians互换
math.degrees(x) 将弧度x转换为角度
math.radians(x) 将角度x转换为弧度
三角函数,下面的x都是以弧度为单位的
math.sin(x) 返回x的正弦
math.cos(x) 返回x的余弦
math.tan(x) 返回x的正切
math.asin(x) 返回x的反正弦(返回值为弧度)
math.acos(x) 返回x的反余弦(返回值为弧度)
math.atan(x) 返回x的反正切(返回值为弧度)
时间模块 time
此模块提供了时间相关的函数,且一直可用
时间简介
1、公元纪年是从公元0000年1月1日0时开始的
2、计算机元年是从1970年1月1日0时开始的,此时间为0,之后每过一秒时间+1
3、UTC时间(Coordinated Universal Time )是从Greenwich时间开始计算的,UTC时间不会因时区问题而产生错误
4、DST阳光节约时间(Daylight Saving Time ),又称夏玲时,是一个经过日照时间修正后的时间(中国已经不用了)
时间元组
时间元组是一个9个整型元素组成的,这九个元素自前至后一次为
1、四位的年(如:1992)
2、月(1-12)
3、日(1-31)
4、时(0-23)
5、分(0-59)
6、秒(0-59)
7、星期几(0-6,周一是0)
8、元旦开始日(1-366)
9、夏令时修时间(-1,0 or 1),对中国来说是0
注:如果年份小于100,则会自动转换为加上1900后的值
变量
time.altzone 夏令时时间与UTC时间差(秒为单位),-32400秒
time.daylight 夏令时校正时间,在中国为0
time.timezone 本地区时间与UTC时间差(秒为单位),-28800秒
time.tzname 时区名字的元组,第一个名字为未经夏令时修正的时区,第二个名字为经夏令时修正后的时间("CST","CST")
注:CST为中国标准时间(China Standard Time UTC+8:00)
函数:
time.time() 返回从计算机元年至当前时间的秒数的浮点数(UTC时间为准)
time.sleep(secs) 让程序按给定秒数的浮点数睡眠一段时间
time.gmtime([secs]) 用给定秒数转换为用UTC表达的时间元组(默认返回当前时间元组)
time.asctime([tuple]) 将时间元组转为日期时间字符串,默认为当前时间
time.ctime([secs]) 将时间戳转发为日期时间字符串,默认是当前时间
time.mktime(tuple) 将本地日期时间元组转为新纪元秒数时间(UTC为准)
time.localtime([secs]) 将UTC秒数时间转为日期元组(以本地时间为准),默认为当前时间
注:time.mktime(time.localtime()) - time.mktime(time.gmtime()) = 28800.0 说明当时时间比UTC时间早8个小时
time.clock() 返回处理器时间,3.0版本开始已经废弃,改成time.process_time()
time.strftime(formt[,tuple]) 返回可读字符串时间,格式有参数format决定。
time.strptime()
time.tzset()
python中时间日期格式化符号
%y 表示两位数的年份(00-99)
%Y 表示四位数的年份(0000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00-59)
%S 秒数(00-59)
%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化月份名称
%B 本地完整月份名称
%c 本地相应的的日期表示和时间表示
%j 年内的一天(001-366)
%p 本地A.M.或P.M.的等价符
%U 一年中的星期数(00-53)星期日为星期的开始
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示
%X 本地相应的时间表示
%Z 当前时区的名称
%% %号本身
import time print(time.localtime())#time.struct_time(tm_year=2018, tm_mon=7, tm_mday=19, tm_hour=0, tm_min=44, tm_sec=5, tm_wday=3, tm_yday=200, tm_isdst=0) print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))#2018-07-19 00:44:05 print(time.strftime("%y-%m-%d %I:%M:%S",time.localtime()))#18-07-19 12:44:05 print(time.strftime("%a-%A-%b-%B-%c-%j-%p-%U-%w-%W-%x-%X-%Z-%%",time.localtime())) # Thu-Thursday-Jul-July-Thu Jul 19 00:44:05 2018-200-AM-28-4-29-07/19/18-00:44:05-?D1¨²¡À¨º¡Á?¨º¡À??-% # a A b B c j p U w W x X Z %
系统模块sys
此模块全部是运行时系统相关的信息
作用:用于获取和设置与系统相关的信息
变量
sys.path 返回模块的搜索路径,path[0]是当前脚本程序的路径,初始化时使用pythonPath环境变量的值
sys.modules 返回已加载模块的字典,字典的键为模块名,值为已加载的模块
sys.version 返回python版本信息的字符串:'3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)]'
sys.version_info 返回python版本信息的命名元组:sys.version_info(major=3, minor=5, micro=4, releaselevel='final', serial=0)
sys.platform 操作系统平台的名称信息(Win32)
sys.argv 命令行参数argv[0]代表当前脚本程序的路径名,绑定用户启动程序时命令参数的列表
sys.copyright 获得python版权相关信息
sys.builtin_module_names 获得python内建模块的名称(字符串元组)
标准输入输出时会用到
sys.stdin 标准输入文件对象,多用于input()
sys.stdout 标准输出文件对象,多用于print()
sys.stderr 标准错误输出文件对象,用于输出错误信息
函数:
sys.exit([arg]) 退出程序,正常退出时sys.exit(0)
sys.getrecursionlimit() 得到递归嵌套层次限制(栈的深度)
sys.setrecursionlimit(n) 得到和修改递归嵌套层次限制(栈的深度),你代表递归的次数,脚本停止,则这个限制还原
自定义模块
自定义模块模块名必须符合“标识符”的命名规则(同变量名),模块有各自独立的作用域
模块化编程的优点:
1、有利于多人合作开发
2、使代码更易于维护
3、提高代码的复用率
4、有利于解决变量名冲突问题
import 语句 搜索模块的路径顺序
1、搜索程序运行时的路径(当前路径)
2、sys.path提供的路径
3、搜索内置模块
说明:sys.path是一个存储模块搜索路径的列表
1、可以把自定义的模块放在相应的路径下可以导入
2、可以把自己模块的路径添加在sys.path列表中
模块的加载过程:
1、在模块导入时,模块的所有语句会执行
2、如果一个模块已经导入,则再次导入时不会重新执行模块内的语句
模块的重新加载:
当已经被导入的模块内容被修改后,可以通过重新执行当前的程序重新加载,或者通过import imp;imp.reload(模块名)的方法重新加载
模块被导入和执行的过程
1、先搜索相关的路径找到模块(.py)
2、判断是否有此模块对应的.pyc文件,如果存在pyc文件且比.py文件新,则直接加载.pyc文件
3、否则用.py文件生成.pyc文件后再进行加载
pyc 模块的编译文件:
mymod1.py----编译(compile)------→mymod1.pyc------解释执行-----→python3
模块的属性
属性的实质是变量(是模块内的全局变量)
模块内预置的属性
__doc__属性
作用:用来绑定模块的文档字符串
模块内第一个没有赋值给任何变量的字符串为模块的文档字符串,(如果没有赋值的字符串出现在第二个语句,则文档字符串为空)
__file__属性
用来绑定模块对应的文档路径名
1、对于内建模块,不绑定路径(没有__file__属性)
2、对于其它模块,绑定路径名的字符串(相对路径:模块名.py)
__name__属性
此属性用来记录模块的自身名字
作用:1、记录模块名
2、用来判断是否为主模块(最先运行的模块)
说明:1、当此模块为主模块时,__name__绑定"__main__"
2、当此模块不是主模块时,此属性绑定模块名
模块的__all__列表(不属于模块的属性)
模块中的__all__列表是一个用来存放可导出属性的字符串列表
作用:当用from import * 语句导入时,只导入__all__列表内的属性,如果没有次列表则模块的所有属性都被导入
不会影响import 模块名 和 from 模块名 import 属性名 两个语句的导入
模块的隐藏属性:
模块中以"_"下划线(不仅仅是单下划线,多个下划线)开头的属性,在from import *语句导入时,将不被导入,通常称这些属性为隐藏属性。
如果该属性被放入__all__列表中,将会被导入
随机模块 random
作用:用于模拟或生成随机输出的模块
函数(import random as R)
R.random() 返回一个[0,1)之间的随机实数
R.randint(a,b) 返回一个 [a~b]之间的随机整数,包括a,b
R.uniform(a,b) 返回[a,b)区间内的随机实数
R.randrange([start,] stop[,step]) 返回range(start,stop,step)中的随机数
R.choice(seq) 从序列中返回随机数
R.shuffle(seq, [,random]) 随机指定序列的顺序(乱序序列),函数的第二个参数代表必须传入random模块中无参的函数目前只有random函数,可以使用 R.random代替,目前版本没有什么用
R.sample(seq,n) 从序列中选择n个随机且不重复的元素
import random L = [i for i in range(10)] L5 = random.sample(L,5) print(L) print(L5)
json&pick模块
序列化:
我们把对象(变量)从内存中变成可存储的或传输的过程称之为序列化,反过来,把变量内容从序列化后的对象重新读到内存中称为反序列化
说明:json不能讲高级的对象序列化,比如:函数、类,如果要序列化函数 或者 类时需要使用pickle模块
json中的函数:
1、dumps():序列化
2、loads():反序列化
import json dic = {'name':"xdl",'age':25} #将字典对象序列,使之变为可存储的对象 dic = json.dumps(dic) f = open('json_test','w') f.write(dic)
import json f = open('json_test','r') dic = f.read() #将读出的数据反序列化,并读入到内存中 dic = json.loads(dic) print(dic['name'])
pickle中的函数
1、dumps():序列化对象
2、loads():反序列化对象
import pickle def foo(): print('ok') #将字典对象序列,使之变为可存储的对象,是字节串,需要使用wb写入 foo = pickle.dumps(foo) f = open('json_test','wb') f.write(foo) f.close()
import pickle def foo(): print('ok') f = open('json_test','rb') data = f.read() #将读出的数据反序列化,并读入到内存中 #反序列化之前要创建一个与读取的函数名相同的函数 #否则会报错:AttributeError: Can't get attribute 'foo' on <module '__main__' from ' # /home/tarena/PycharmProjects/xdl/module/pickle_load.py'> data = pickle.loads(data) data()
logging模块(日志模块)
使用步骤:
1、获取logger实例对象,如果参数为空则返回root logger,
logger = logging.getLogger()
2、指定logger的格式
formatter = logging.Formatter('自定义格式')
3、创建具体的日志handler,并将日志格式添加到处理器上,包括文件日志和终端日志
1)文件日志:
file_handler = logging.FileHandler('文件名称.log')
file_handler.setFormatter(formatter)
2)终端日志(在终端上显示日志信息)
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(formatter)
4、设置日志级别
logger.setLevel(日志级别)
5、把日志的handler对象添加到日志对象logger中
logger.addHandler(file_handler)
logger.addHandler(console_handler)
6、写日志
7、移除日志处理器
logger.removeHandler(file_handler)
logger.removeHandler(console_handler)
import logging import sys #1、获取logger的实例,<Logger testlog (INFO)>,(INFO)是自己设置的日志级别,如果不给参数,<RootLogger root (INFO)> logger = logging.getLogger('testlog') #2、指定logger的格式 formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') #3、创建具体的日志handler,文件日志,终端日志 #3.1、文件日志 file_handler = logging.FileHandler('testLog.log') file_handler.setFormatter(formatter) #3.2、终端日志 console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(formatter) #4、设置日志的级别,高于等于这个默认级别才会被显示 logger.setLevel(logging.INFO) #5、把日志的handler添加到logger实例中 logger.addHandler(file_handler) logger.addHandler(console_handler) #6、写日志 logger.error("Test Error log") logger.info("Test info log") logger.debug("Test debug log") #7、清空日志 logger.removeHandler(file_handler) logger.removeHandler(console_handler)
将日志封装成一个模块
class LogerHelper: def __init__(self,name='LogerHelper',setLevel=logging.DEBUG): self.logger = logging.getLogger(name) self.formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s") self.file_handler = logging.FileHandler(name+'.log') self.file_handler.setFormatter(self.formatter) self.console_handler = logging.StreamHandler(sys.stdout) self.console_handler.setFormatter(self.formatter) self.logger.setLevel(setLevel) self.logger.addHandler(self.file_handler) self.logger.addHandler(self.console_handler) def writeLog(self,info,level='debug'): if level == 'critial': self.logger.critical(info) elif level == 'error': self.logger.error(info) elif level == 'warn': self.logger.warn(info) elif level == 'info': self.logger.info(info) elif level == 'debug': self.logger.debug(info) def removeLog(self): self.logger.removeHandler(self.file_handler) self.logger.removeHandler(self.console_handler) if __name__ == '__main__': logger = LogerHelper() logger.writeLog("hello world",'critial') logger.writeLog("hello world",'error') logger.writeLog("hello world",'warn') logger.writeLog("hello world",'info') logger.writeLog("hello world",'debug') logger.removeLog()
包(模块包)package
包是将模块以文件夹的组织形式进行分组管理的方法(包比其它普通文件夹多一个__init__.py)
作用:将一系列模块进行分类管理,有利于防止命名冲突,可以在需要时加载一个或一部分模块而不是全部模块
__init__.py文件
常规包内必须存在的文件
__init__.py会在包加载时被自动调用
作用:1、编写此包的内容
2、在内部填写文档字符串
3、在__init__.py内可以加载此包所依赖的一些其它模块
包的导入
用三条import语句可以导入包(同模块的导入规则)
import 包名 [as 包别名]
import 包名.模块名 [as 模块新名]
import 包名.子包名.模块名
from 包名 import 模块名 [as 模块新名]
from 包名.子包名 import 模块名 [as 模块新名]
from 包名.子包名.模块名 import 属性名 [as 属性新名]
from 包名 import *
from 包名.模块名 import *
包的__init__.py内的__all__列表
作用:用来记录此包中有哪些子包或模块在用from 包 import * 语句导入时是否被导入
说明:__all__列表只对from import * 语句起作用,如果没有此列表则,都不会被导入
包的相对导入
包的相对导入是指包内模块的相互导入
语法:1、from 相对路径包或模块 import 属性或模块名
2、from 相对路径或模块 import *
相对路径:
1、.代表当前目录 如:a/b/c.py 其中.c.py代表b路径
2、..代表上一级目录
3、...代表上二级目录
4、....依次类推
注:相对导入时不能超出包的外部,如果超出包的外部会报错ValueError: attempted relative import beyond top-level package
包的加载路径:
和模块的加载路径相同
1、当前文件夹
2、sys.path给出的路径
异常 exception
什么是错误:
错误是指由于逻辑或语法等导致一个程序无法正常执行的问题
特点:有些错误是无法预知的
什么是异常:
异常是程序出错时标识的一种状态,
当异常发生时,程序不会再向下执行,而转去调用此函数的地方待处理错误并恢复为正常状态
作用:
1、通知上层调用者有错误产生需要处理
2、用作信号通知
try 语句的两种语法
try - except 语句
语法:try:
可能触发异常的语句
except 错误类型1 [as 变量1]:
异常处理语句1
except 错误类型2 [as 变量2]:
异常处理语句2
except(错误类型3,错误类型4,...)[as 变量3]:#前面必须是异常类型元组
异常处理语句3
...
except: #捕获所有错误类型
异常处理语句other
else:
未发生异常时执行的语句,(try语句嵌套的try语句出现异常并被处理,也要执行,如果没有被处理将交给外部try语句进行处理)
finally:
最终执行语句(不管有没有发生异常都会执行该语句,发生异常没有被处理同样会执行该语句)
作用:尝试捕获异常,将程序转为正常状态并继续执行
说明:1、as 子句用于绑定错误对象的变量,可以省略不写
2、except子句可以有一个或多个,但至少要有一个
3、else子句最多只能有一个,也可以省略不写
4、finally子句最多只能有一个,也可以省略不写
try-finally语句
语法:try:
可能触发异常的语句
finally:
最终语句
说明:1、finally子句不可以省略
2、一定不存在except子句
作用:通常try-finally语句来做触发异常时必须要处理的事情,无论异常是否发生,finally子句都会执行
注:try-finally语句不会改变程序的(正常/异常)状态
raise语句
作用:触发一个错误,让程序进入异常状态
语法:1、raise 异常类型 :raise ZeroDivisionError
2、raise 异常对象:rasie ZeroDivisionError("被零除了...")
assert 语句(断言语句)
语法:assert 真值表达式,错误数据(通常是字符串)
作用:当真值表达式为False时,用错误数据创建一个AssertionError类型的错误,并进入异常状态
类似于:if 真值表达式 == False:
raise AssertionError(错误数据)
小结:
接收错误消息:try- except
做必须要处理的事情的语句:try-finally
发错误消息的语句:1、raise 语句
2、assert 语句
为什么要用异常处理处理机制:
在程序调用层数较深时,向主调用函数传递错误信息需要用return语句层层传递比较麻烦,所以用异常处理机制
异常(高级)
回顾异常相关的语句:
try-exept 用来捕获异常通知
try-finally 用来做一定要做的事情
raise 用来发生异常通知
assert 用来根据条件来发出AssertionError类型的异常通知
with语句:
语法:with 表达式1 [as 变量1],表达式2 [as 变量2]:
语句块
作用:使用于对资源进行访问的场合,确定使用过程中不管是否发生异常,都会执行必须的‘清理’操作,并释放资源
如:文件使用后自动关闭,线程中锁的自动获取和释放等
说明:能够用于with语句进行管理的对象必须是环境管理器
'''此示例示意用try-except 和 try-finally 组合来对文件进行操作''' def read_from_file(filename="info.txt"): try: f = open(filename) try: print("正在读取文件") n = int(f.read()) print("n=",n) finally: f.close() print("文件已经关闭") except OSError: print("文件打开失败") read_from_file()
环境管理器:
1、类内有__enter__ 和 __exit__实例方法的类被称为环境管理器
2、能用with语句管理的对象必须是环境管理器
3、__enter__方法将在进入with语句时被调用,并返回由as变量管理的对象
4、__exit__方法将在离开with语句时被调用,且可以用参数来判断在离开with语句时是否有异常发生并做出相应的处理
contextlib,给我们提供了一个装饰器,只要按照它的代码协议来实现函数内容,就可以将这个函数对象变成一个上下文管理器
使用环境管理器(上下文管理器)的好处
1.提高代码的复用率
2.提高代码的优雅度
3.提高代码的可读性
import contextlib @contextlib.contextmanager def open_func(file_name): #__enter__方法 print('openfile',file_name,'in __enter__') file_handler = open(file_name,'r') #在被装饰的函数中,必须是一个生成器,而yield之前的代码相当于__enter__,之后的代码相当于__exit__ try: yield file_handler except Exception as e: print(e) finally: print('closefile',file_name,'in __exit__') file_handler.close() if __name__ == "__main__": with open_func('aa.txt') as f: print(f) 1 / 0
def read_from_file(filename="info.txt"): try: with open(filename) as f: print("正在读取文件") n = int(f.read()) print("n=",n) print("文件已经关闭") except OSError: print("文件打开失败") read_from_file()
'''此示例示意环境管理器的定义及使用''' class A: def __enter__(self): print("已经进入with语句") return self #返回的对象将由as 绑定 def __exit__(self,exc_type,exc_val,exc_tb): '''此方法会在退出with语句时自动调用 exc_type在没有异常时为None,在出现异常时为绑定异常类型 exc_val在没有异常时为None,在出现异常时绑定错误对象 exc_tb在没有异常时为None,在出现异常时绑定traceback(跟踪)''' if exc_type is None: print("正常离开with语句!") else: print("异常离开with语句!") print("异常类型是:",exc_type) print("错误对象是",exc_val) print("traceback是:",exc_tb) with A() as a: print("我是with语句内的一条语句") int(input("输入一个数:")) # 已经进入with语句 # 我是with语句内的一条语句 # 输入一个数:aa # 异常离开with语句! # 异常类型是: <class 'ValueError'> # 错误对象是 invalid literal for int() with base 10: 'aa' # traceback是: <traceback object at 0x7f443a0e2748> # Traceback (most recent call last): # File "02_enter_exit.py", line 24, in <module> # int(input("输入一个数:")) # ValueError: invalid literal for int() with base 10: 'aa'