# 常用模块
什么是模块:模块就是一组功能的集合,我们的程序可以导入模块来复用模块里的功能
python 模块分为3种:
内置模块:python安装时自带的
扩展模块: 比如第三方模块
自定义模块: 自己写的模块
# collections模块
在内置数据类型(dict、list、set、tuple
)的基础上,collections模块还提供了几个额外的数据类型:Counter
、deque
、defaultdict
、namedtuple
和OrderedDict
等
#1.namedtuple: 生成可以使用名字来访问元素内容的tuple
from collections import namedtuple
Point = namedtuple('Point',['x','y'])
p=Point(1,2)
print(p.x,p.y) # 1,2
#2.deque: 双端队列,可以快速的从另外一侧追加和推出对象
from collections import deque
q=deque(['a','b','c'])
q.append('x')
q.appendleft('y')
print(q) # deque(['y', 'a', 'b', 'c', 'x'])
#3.Counter: 计数器,主要用来计数
c = Counter('abcdeabcdabcaba')
print(c) # Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})
#4.OrderedDict: 有序字典
#5.defaultdict: 带有默认值的字典
from collections import defaultdict
values = [11, 22, 33,44,55,66,77,88,99,90]
my_dict = defaultdict(list) # 设置字典的默认值
for value in values:
if value>66:
my_dict['k1'].append(value)
else:
my_dict['k2'].append(value)
print(my_dict) # defaultdict(<class 'list'>, {'k2': [11, 22, 33, 44, 55, 66], 'k1': [77, 88, 99, 90]}) # print(list(my_dict.values()))
from collections import defaultdict
dd = defaultdict(lambda: 'N/A')
dd['key1'] = 'abc'
print(dd['key1']) # key1存在 'abc'
print(dd['key2']) # key2不存在,返回默认值 'N/A'
from collections import defaultdict
dic = defaultdict(list) # 如果没有给一个key赋值,就会返回一个list
dic['name'] ='wang'
dic['list'].append([1,3,4])
print(dic) #defaultdict(<class 'list'>, {'name': 'wang', 'list': [[1, 3, 4]]})
print(dict(dic)) #{'name': 'wang', 'list': [[1, 3, 4]]}
# dic1=dict()
# print(dic1) #{}
- 使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低,deque是为了高效插入和删除
# decimal模块
内置的精确计算的饿模块
import decimal
d1 =decimal.Decimal('0.1') #注意必须是字符串
d2=decimal.Decimal('0.01')
print(d1*d2) #0.001
print(decimal.Decimal(0.1)) #0.100000000000000005555……
# time、datetime
时间模块
表示时间的三种方式表示时间:时间戳、元组(结构化时间)、格式化时间(字符串):
时间戳:通常来说,时间戳表示的是从1970.1.1开始的计算偏移量
格式化时间字符串:‘1999-12-06‘
结构化时间元组:struct_time元组共有9个元素共九个元素:(年月日时分秒,一年中第几周,一年中 第几天等)
#时间戳 >>>time.time() 1500875844.800804 #时间字符串 >>>time.strftime("%Y-%m-%d %X") '2017-07-24 13:54:37' >>>time.strftime("%Y-%m-%d %H-%M-%S") '2017-07-24 13-55-04' #时间元组:localtime将一个时间戳转换为当前时区的struct_time time.localtime() time.struct_time(tm_year=2017, tm_mon=7, tm_mday=24, tm_hour=13, tm_min=59, tm_sec=37, tm_wday=0, tm_yday=205, tm_isdst=0) # 时间戳时间-localtime/gmtime-> 结构化时间 -strftime-> 格式化时间 # 时间戳时间<-mktime- 结构化时间 <-strptime- 格式化时间 time.strptime("2017-03-16","%Y-%m-%d") #返回一个元组结构化时间 time.strftime("%Y-%m-%d",time.localtime(1500000000)) # 转化为格式化时间 time.mktime(time.localtime(1500000000)) # 结构化转时间戳 time.localtime(1500000000) # 时间戳转结构化
# random模块
随机数模块
random.random() # 大于0且小于1之间的小数
random.uniform(1,3) # 大于1小于3的小数
random.randint(1,5) # 大于1小于等于5
random.randrange(1,10,2) # 大于等于1且小于10之间的奇数
random.choice([1,'23',[4,5]]) # 随机返回一个
random.sample([1,'23',[4,5]],2) #随机不重复匹配2个
random.shuffle([1,3,4,5]) # 打乱次序,洗牌
random.choices([1,'23',[4,5],'3','4'],k=3) # 随机选3个
# 验证码随机
import random
def make_code(n):
res = ''
for i in range(n):
s1 = chr(random.randint(65,90)) # 生成字母chr
s2 = str(random.randint(0,9))
res += random.choice([s1,s2])
return res
print(make_code(9)) # H53FVG8K4
#红包代码,几率相等
import random
def func(money,pople):
lst=[0,2000] # 为了去小数,首尾
lst.extend(random.sample(list(range(1,money*10)),pople-1))
lst.sort()
lst =list(map(lambda x:x/10,lst)) # 除以10
g=(round(lst[i+1]-lst[i],3) for i in range(len(lst)-1))
return g
ret=list(func(200,10))
print(ret)
# os模块
与操作系统交互的一个接口
os.makedirs('dirname1/dirname2') #可生成多层递归目录
os.removedirs('dirname1') #若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') #生成单级目录;相当于shell中mkdir dirname
os.listdir('dirname') #列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.rename("oldname","newname") #重命名文件/目录
os.stat('path/filename') #获取文件/目录信息
os.system("bash command") #运行shell命令,直接显示
os.getcwd() #获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") #改变当前脚本工作目录;相当于shell下cd
os.path.split(path) #将path分割成目录和文件名二元组返回
os.path.dirname(path) #返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) #返回path最后的文件名。如何path以/或\结尾,那么就会返回空值
os.path.exists(path) #如果path存在,返回True;如果path不存在,返回False
os.path.isfile(path) #如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) #如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) #将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getsize(path) #返回path的大小
# sys模块
是与Python解释器交互的一个接口
sys.argv # 命令行参数List,第一个元素是程序本身路径
sys.exit(n) #退出程序,正常退出时exit(0),错误退出sys.exit(1)
sys.version #获取Python解释程序的版本信息
sys.path #返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform #返回操作系统平台名称
序列化模块: 将原本的字典、列表等数据类型内容转化成一个字符串的过程。反序列化概念相反。
# json
模块
提供四个功能:dumps、dump、loads、load
#dump和load是直接将对象序列化之后写入文件,且依赖一个文件句柄。而dumps和loads是直接在文件(内存)中进行操作,当然可以可以通过文件的‘w'模式写入。
#内存中操作
import json
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = json.dumps(dic) #序列化:将一个字典转换成一个字符串,
print(type(str_dic),str_dic) #<class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"}
dic2 = json.loads(str_dic) #反序列化:将一个字符串格式的字典转换成一个字典
#注意,要用json的loads功能处理的字符串类型的字典中的字符串必须由""表示,''都不行
print(type(dic2),dic2) #<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
#文件中操作
import json
f = open('json_file','w')
dic = {'k1':'v1','k2':'v2','k3':'v3'}
json.dump(dic,f) #dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件
f.close()
f = open('json_file')
dic2 = json.load(f) #load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
f.close()
print(type(dic2),dic2)
# pickle
模块
用于python特有的数据类型和python数据类型进行转换
# 与json模块类似 需要注意的是在写入文件的时候,要用'wb','rb'
# 内存中操作
import pickle
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = pickle.dumps(dic)
print(str_dic) #一串二进制内容
dic2 = pickle.loads(str_dic)
print(dic2) #字典
#文件中操作
import time
struct_time = time.localtime(1000000000)
print(struct_time)
f = open('pickle_file','wb')
pickle.dump(struct_time,f)
f.close()
f = open('pickle_file','rb')
struct_time2 = pickle.load(f)
print(struct_time2.tm_year)
#补充:读取多s个文件内容时,需要使用while True
while True:
try:
obj =pickle.load(f2) # 注意这个load是一个一个的加载需要用循环
li.append(obj)
except:break
else:return (True,None,None)
# shelve模块
是对象持久化保存,同时生成三个文件,可以把生成的对象当成字典操作。
#shelve模块中的key键必须是字符串形式,value可以是任意值
# 1.创建一个shelf对象,直接使用open函数即可
import shelve
s = shelve.open('test_shelf.db') #
try:
s['kk'] = {'int': 10, 'float': 9.5, 'String': 'Sample data'}
s['MM'] = [1, 2, 3]
finally:
s.close()
#2.对shelf对象,增、删、改操作
s = shelve.open('test_shelf.db', flag='w', writeback=True)
try:
# 增加
s['QQQ'] = 2333
# 删除
del s['MM']
# 修改
s['kk'] = {'String': 'day day up'}
finally:
s.close()
# 3,回写
d=shelve.open(r'a.txt',writeback=True) #writeback=True,对子字典修改完后要写回,否则不会看到修改后的结果
d['egon']={'age':18,'sex':'male'} #存的时候会生成三个文件,不用管,是python的一种处理机制
d['egon']['age']=20 #将年龄修改为20
print(d['egon']['age']) #此时拿到的是修改后的年龄
print(d['egon']['sex'])
d.close()
# hashlib模块
提供常见的摘要算法 1. 摘要算法: 又称哈希算法,散列算法,通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制表示),目的是为了发现原始数据是否被人篡改过。原因是单向函数,反推很难但是现在已经有人反推成功。 2. 两种加密方式:可在md5() 中加密;还可以再update中提前加密。
import hashlib
md5 = hashlib.md5('a'.encode('utf-8')) # 生成加密对象,这里可以加盐
md5.update('how to use md5 in python hashlib?'.encode('utf-8')) #上传加密数据
print md5.hexdigest() # 生成密文
# 如果数据量大时,比如校验视频文件时,可以多次update(),最后生成密文比较
#MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全类似
#校验两个文件时候一致
import os
import hashlib
def file_md5(path):
filesize = os.path.getsize(path) # 先获取文件大小
md5 = hashlib.md5() # 获取对象
with open(path,'rb') as f:
while filesize >= 4096: # 判断大小,以便相减
content = f.read(4096)
md5.update(content) # 每次更新对象内容
filesize -= 4096
else:
content = f.read(filesize)
if content:
md5.update(content)
return md5.hexdigest() # 生成密文
def cmp_file(path1,path2):
return file_md5(path1) == file_md5(path2)
path1 = r'D:\s20\day18\视频\4.面向对象整理.mp4'
path2 = r'D:\s20\day18\视频\tmp.mp4'
ret = cmp_file(path1,path2)
print(ret)
# logging模块
用途:主要用于输出运行日志,可以设置输出日志的等级,日志保存,日志文件回滚等;相当于print,但它是标准输出,不能设置级别,影响开发者查看其他数据,可以把它理解为,设了等级才输出的print。
logging 模块的使用:
- 简单配置法: 存在编码问题,但代码简单
- logger对象法: 使用方便,但配置复杂
logging的基本使用方法:
- 默认情况下Python的logging模块将日志打印到了标准输出中
- 只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING
- 日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG
函数式简单配置法
import logging logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message') #配置日志等级,以及日志格式、输出位置: import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='/tmp/test.log', #写入文件地址 filemode='w') logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message') #配置参数 logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有: filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 format:指定handler使用的日志显示格式。 datefmt:指定日期时间格式。 level:设置rootlogger(后边会讲解具体概念)的日志级别 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 format参数中可能用到的格式化串: %(name)s Logger的名字 %(levelno)s 数字形式的日志级别 %(levelname)s 文本形式的日志级别 %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 %(filename)s 调用日志输出函数的模块的文件名 %(module)s 调用日志输出函数的模块名 %(funcName)s 调用日志输出函数的函数名 %(lineno)d 调用日志输出函数的语句所在的代码行 %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 %(asctime)s 字符串形式的当前时间默认格式是“2003-07-08 16:49:45,896”逗号后面的是毫秒 %(thread)d 线程ID。可能没有 %(threadName)s 线程名。可能没有 %(process)d 进程ID。可能没有 %(message)s用户输出的消息
logger对象配置法
#相应组建介绍: 1、日志器:logger,提供了应用程序可一致使用的接口 2、处理器: Handler, 将logger创建的日志记录发送到合适的目的地输出或则记录 3、过滤器:Filter,提供更细粒读的控制工具决定输出哪条日志记录 4、格式器:Formater,决定日志记录的最终输出格式 日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。 #方法: 1、Logger.setLevel() # 设置日志器将处理的日志消息的最低级别 2、Logger.addHander() Logger.removeHander() #添加或删除一个hander 3、Logger.addFilter() Logger.removeFilter() #为该logger对象添加 和 移除一个filter对象 # 基本格式: import logging logger = logging.getLogger() # 创建个logger对象 # 创建一个handler,用于写入日志文件,文件操作符 fh = logging.FileHandler('test.log',encoding='utf-8') # 再创建一个handler,用于输出到控制台 ,屏幕输出流,操作符 ch = logging.StreamHandler() #创建一个格式 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setLevel(logging.DEBUG) #设置查看等级 fh.setFormatter(formatter) # 绑定文件操作符,和格式 ch.setFormatter(formatter) #绑定屏幕操作符,和格式 logger.addHandler(fh) #logger对象可以添加多个fh和ch对象 logger.addHandler(ch) logger.debug('logger debug message') logger.info('logger info message') logger.warning('logger warning message') logger.error('logger error message') logger.critical('logger critical message') #坑点:用Python的logging模块记录日志时,可能会遇到重复记录日志的问题,第一条记录写一次,第二条记录写两次,第三条记录写三次原因:没有移除handler 解决:在日志记录完之后removeHandler,还可以使用单例模式,还可以使用模块导入的形式,因为在一个主程序中相同模块只会导入一次,所以只能初始化一次。 import logging def log(msg): #创建logger,如果参数为空则返回root logger logger = logging.getLogger("nick") logger.setLevel(logging.DEBUG) #设置logger日志等级 #创建handler fh = logging.FileHandler("test.log",encoding="utf-8") ch = logging.StreamHandler() #设置输出日志格式 formatter = logging.Formatter( fmt="%(asctime)s %(name)s %(filename)s %(message)s", datefmt="%Y/%m/%d %X", ) #为handler指定输出格式 fh.setFormatter(formatter) ch.setFormatter(formatter) #为logger添加的日志处理器 logger.addHandler(fh) logger.addHandler(ch) # 输出不同级别的log logger.info(msg) #解决方案1,添加removeHandler语句,每次用完之后移除Handler logger.removeHandler(fh) logger.removeHandler(ch) log("警告") log("提示") log("错误") ------------------------------------------------------------------ #添加过滤器的例子**** import logging def _create_log_handlers(stream=None): error_handler = logging.StreamHandler(stream) # 获取logger对象 error_handler.setLevel(logging.WARNING) #设置等级 formatter = logging.Formatter("%(levelname)s: %(message)s") error_handler.setFormatter(formatter) #绑定格式 non_error_filter = logging.Filter() #实例个过滤器 non_error_filter.filter = lambda record: record.levelno < logging.WARNING #实现过滤器 non_error_handler = logging.StreamHandler(stream) non_error_handler.addFilter(non_error_filter) formatter = logging.Formatter("%(message)s") # 打印错误信息 non_error_handler.setFormatter(formatter) return [error_handler, non_error_handler] # 返回两个处理器 ret =_create_log_handlers() def func(): logger = logging.getLogger() logger.addHandler(ret[0]) #ret[0] 会报错后面两个,在ret[1]时报错前一个 logger.debug('警告') # 使用ret[0]调用,小于warning logger.warning('大于警告') # 2019-04-04 21:52:55,654 - root - WARNING - 大于警告 logger.error('错误') #2019-04-04 21:53:21,054 - root - ERROR - 错误 func() #这里的stream,只在streamHander(stream=None),这里默认是None,对应的输出对象是sys.stderr;当然可以设置为sys.stdout(标准输出,不飘红) ------------------------------------------------------------------- #拓展 def _default_handlers(stream): def should_log(record): if record.name.startswith("webkitpy.thirdparty.autoinstall"): return False return True logging_filter = logging.Filter() logging_filter.filter = should_log #调用过滤器 handler = logging.StreamHandler(stream) formatter = logging.Formatter("%(name)s: [%(levelname)s] %(message)s") handler.setFormatter(formatter) handler.addFilter(logging_filter) return [handler] #返回一个处理器 ------------------------------------------------------------------- #终极日志(添加单例模式) class Log(object): __instance = None def __new__(cls, *args, **kwargs): if not cls.__instance: cls.__instance = super().__new__(cls) return cls.__instance def __init__(self,level = logging.DEBUG): if 'logger' not in self.__dict__: logger = logging.getLogger() logger.setLevel(level) fh = logging.FileHandler('test.log', encoding='utf-8') ch = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setFormatter(formatter) ch.setFormatter(formatter) logger.addHandler(fh) logger.addHandler(ch) self.logger = logger log = Log()
log.logger.warning('选择序号输入的内容有误') ```
logging模块的补充
logging模块是线程安全的,不需要客户做任何特殊的工作。它通过使用线程锁实现了这一点; 有一个锁来序列化访问模块的共享数据,每个处理程序还创建一个锁来序列化访问其底层 I/O。
日志记录级别:
日志记录格式化字符串
使用basicConfig方法配置logging记录格式:
使用logging打印进程
import threading import logging FORMAT = "%(asctime)s %(thread)d %(message)s" logging.basicConfig(level=logging.INFO,format=FORMAT) def add(x,y): logging.warning("{} {}".format(threading.enumerate(),x+y)) t = threading.Timer(1,add,args=(4,5)) t.start() 运行结果: 2017-12-17 15:40:34,226 123145367023616 [<_MainThread(MainThread, stopped 4320629568)>, <Timer(Thread-1, started 123145367023616)>] 9
logger类:使用工厂方法返回一个Logger实例。
logging.``getLogger
([name=None])指定name,返回一个名称为name的Logger实例。如果再次使用相同的名字,是实例化一个对象。未指定name,返回Logger实例,名称是root,即根Logger。Logger是层次结构的,使用 '.' 点号分割,如'a'、'a.b'或'a.b.c.d','a'是'a.b'的父parent,a.b是a的子child。对于foo来说,名字为foo.bar、foo.bar.baz、foo.bam都是foo的后代。
举例
import logging DATEFMT ="[%Y-%m-%d %H:%M:%S]" FORMAT = "%(asctime)s %(thread)d %(message)s" logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT,filename='class_test.log') root = logging.getLogger() print(root.name,type(root),root.parent,id(root)) #root <class 'logging.RootLogger'> None 4367575248 logger = logging.getLogger(__name__) print(logger.name, type(logger), id(logger), id((logger.parent))) #__main__ <class 'logging.Logger'> 4367575864 4367575248 logger1 = logging.getLogger(__name__ + ".ok") print(logger1.name, type(logger1), id(logger1), id((logger1.parent))) #__main__.ok <class 'logging.Logger'> 4367575920 4367575864 print(logger1.parent,id(logger1.parent)) #<logging.Logger object at 0x10453eb38> 4367575864
子child的级别设置,不影响父parent的级别:
import logging FORMAT = "%(asctime)s %(thread)d %(message)s" logging.basicConfig(level=logging.WARNING,format=FORMAT,datefmt="[%Y-%m-%d %H:%M:%S]") root = logging.getLogger() print(1,root,id(root)) #RootLogger,根Logger #1 <logging.RootLogger object at 0x104534f28> 4367535912 root.info('my root') #低于定义的WARNING级别,所以不会记录 loga = logging.getLogger(__name__) #Logger继承自RootLogger print(2,loga,id(loga),id(loga.parent)) #2 <logging.Logger object at 0x1044ef630> 4367250992 4367535912 print(3,loga.getEffectiveLevel()) #数值形式的有效级别 #3 30 loga.warning('before') loga.setLevel(28) #设置级别为28 print(4,loga.getEffectiveLevel()) #4 28 loga.info('after')# loga.warning('after1')
Handler:Handler控制日志信息的输出目的地,可以是控制台、文件。
可以单独设置level;可以单独设置格式;可以设置过滤器
StreamHandler #不指定使用sys.strerr;FileHandler #文件;_StderrHandler #标准输出
NullHandler #什么都不做
level的继承
import logging FORMAT = "%(asctime)s %(thread)d %(message)s" logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="[%Y-%m-%d %H:%M:%S]") root = logging.getLogger() #根Logger级别为INFO 20 print('root:',root.getEffectiveLevel()) #root: 20 log1 = logging.getLogger('s') log1.setLevel(logging.ERROR) #级别为ERROR 40 print('log1:',log1.getEffectiveLevel()) #log1: 40 log1.error('log1 error') log2 = logging.getLogger('s.s1') #继承自log1 40,无法使用warning log2.setLevel(logging.WARNING) #设置为WARNING 30,才可以使用warning print('log2:',log2.getEffectiveLevel()) #log2: 30 log2.warning('log2 warning') #logger实例,如果设置了level,就用它和信息的级别比较,否则,继承最近的祖先的level
同样,handler也可以设置使用logging.Formatter()设置格式和Logging.Filter()设置过滤器
import logging FORMAT = "%(asctime)s %(thread)d %(message)s" logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="[%Y-%m-%d %H:%M:%S]") root = logging.getLogger() print(1,root.getEffectiveLevel()) #RootLogger,根Logger log1 = logging.getLogger('s')#模块化用__module__,函数化用__name__作为Logger名,Logger同名内存中也只有一个 print(2,log1.getEffectiveLevel()) h1 = logging.FileHandler('test.log') h1.setLevel(logging.WARNING) fmt1 = logging.Formatter('[%(asctime)s] %(thread)s %(threadName)s log1-handler1 %(message)s') h1.setFormatter(fmt1) #重新个性化定义记录的格式化字符串 log1.addHandler(h1) filter1 = logging.Filter('s') #过滤器 会记录s, s.s2的信息 log1.addFilter(filter1) print(3,log1.getEffectiveLevel()) log2 = logging.getLogger('s.s2') print(4,log2.getEffectiveLevel()) h2 = logging.FileHandler('test1.log') h2.setLevel(logging.WARNING) log1.addHandler(h2) filter1 = logging.Filter('s.s2') #过滤器不会记录s.s2的消息,只会记录自己的消息 log1.addFilter(filter1) print(3,log1.getEffectiveLevel()) log1.warning('log1 warning===') log2.warning('log2 warning---')
常用模块(二) →