Python之旅的第17天(re模块、logging模块)
越来越有意思了,绕弯弯的转义符听得爽的飞起,这感觉真的很爽
re模块补充了很多内容,后期应该会很强大,但是现在就是个皮毛啊,明天这个计算器得好好整理一下思路,联系一下
一、re模块补充
import re # \ 关于转义符的补充 # 首先要明确,一个转义符要进入Python中的re模块中,需要经过两次转义 # 首先是Python解释器的转义,随后是re模块中的转义 # 下面举例说明 # print(re.findall('I\\b', 'I am LIST')) # 这里首先的需求是我们要得到后面的第一个大写I,使用了\b表示空格和特殊字符 # 为什么需要两个\ 进行表示呢,首先\在解释器中也是具有转义含义的,所以解释器在读取时会消耗掉一个,为了保证传输个re模块时仍然是\b # 我们必须要将第二个\转换为没有意义的字符,那么此时在解释器运行时,第一个\就将第二个\转换成为一个没有意义的字符 # 进入re模块读取时,前面的规则内容就成为了'I\b',此时re模块就能识别是I 加上空格的意思 # 或者还可以使用r,表示原生字符,没有任何意义 # print(re.findall(r'I\b', 'I am LIST')) # 如果需要匹配字符串'abc\d'中的c\d我们该如何对应呢 # 首先,我们确定一下在进入re模块时,我们的查询规则应该是c\\d,这样才能确保re模块能够读取到c\d # 所以再向上推论解释器,解释器需要给re模块传递两个字符c\\d,那么他就需要对两个\进行转义,这么一来就需要在最外面输入四个转义符 # print(re.findall('c\\\\d', 'abc\d')) #输出结果:['c\\d'] # 之所以输出结果有两个\,表示的就是解释器读取状态,必须两个才能传入正确的c\d # 请记住进入re模块之前是需要解释器先读取一次的,\转义符在各个地方都有转义的意思哦 # | 表示或的意思 # 表示|分割两边为或者关系 # print(re.findall('a|b', 'dsnjksasdwacb')) #['a', 'a', 'b'] # print(re.findall('ka|b', 'dsakadawb')) #['ka', 'b'] # re.search().group()方法 # 只查找第一个,找到之后就停止,没有找到返回None # 同时search可以进行命名分组 # ret = re.search("?p<name>[a-z]*",'alex23zjl33wuyuetian11') # print(ret.group('name')) # ret = re.search("(?p<name>[a-z])(?p<age>/d*)*",'alex23zjl33wuyuetian11') # print(ret.group('name')) #'alex' # print(ret.group('age')) #23 # ()分组,提高优先级 # . match().group()方法同于search,区别在与match只从匹配字符的最开始位置查找 # 计算器的作业,最底层的括号可能存在多个括号,所以应该是用search进行查找在进行替换,在进行下一个 # split 同于字符串中的方法,但略有不同 # print(re.split('ab','acbcdbc')) # 得到的结果和看到的不一样,可能是因为版本更新的原因吧 # 分别是先用a进行分割,再使用b进行分割,空字符串也会显示 # 但是最新测试出来的结果是不会进行分割了 # sub(旧,新,参数,(匹配次数,一般不用)) 用于元素替换 # print(re.sub('ab','SHUAI','abdasdwdbabdababdaab')) # subn,使用方法和sub完全相同,但是同时会输出一个匹配字数 # compile 用于存储匹配规则,方便后面进行调用 # com = re.compile('\d+') # print(com.findall('alex23zjl18wyt22')) # ['23', '18', '22'] # 后期可能会存在比较难写的匹配规则,这样便于调用 #finditer 实际作用和findall类似,但是finditer返回的是一个迭代器 # test = re.finditer('\d+','alex23zjl18wyt22') # print(test) #<callable_iterator object at 0x0000028FE251EE80> # print(test.__next__().group()) #23 # print(test.__next__().group()) #18 # print(test.__next__().group()) #22 # 数据处理量比较大时,使用finditer更有利于节省内存 # 关于匹配分组的优先级问题 # 匹配分组时,会优先显示分组内的内容 # print(re.findall('www\.(baidu|163)\.com','www.baidu.com')) # 输出结果为:['baidu'],默认会优先输出分组内的内容 # 通过?:组合降低括号内的优先级就可以显示你想要的全部 print(re.findall('www\.(?:baidu|163)\.com','www.baidu.com')) # 取消优先级后,会输出:['www.baidu.com']
二、logging模块
import logging # logging模块常用于做管理日志,管理日志由底到高分为以下五个层次 # dubeg、info、warning、error、critical # logging.debug('debug message') # logging.info('info message') # logging.warning('warning message') # logging.error('error message') # logging.critical('critical message') # 默认打印的界别是 warning以上的级别 # logging.basicConfig(),创建一个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='test.txt', filemode='w') logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message') # 查看输出: # cat /tmp/test.log # Mon, 05 May 2014 16:29:53 test_logging.py[line:9] DEBUG debug message # Mon, 05 May 2014 16:29:53 test_logging.py[line:10] INFO info message # Mon, 05 May 2014 16:29:53 test_logging.py[line:11] WARNING warning message # Mon, 05 May 2014 16:29:53 test_logging.py[line:12] ERROR error message # Mon, 05 May 2014 16:29:53 test_logging.py[line:13] CRITICAL critical message # # 可见在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有 # filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。 # 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用户输出的消息 # logging存在一个弊端,就是在窗口和文件内只能选择一个,所以下面引入logger对象 # logger # 俗称吸星大法的对象 # import logging # # logger = logging.getLogger() # 创建一个handler,用于写入日志文件 # fh = logging.FileHandler('test.log') # 再创建一个handler,用于输出到控制台 # ch = logging.StreamHandler() # # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # # fh.setFormatter(formatter) # ch.setFormatter(formatter) # logger.addHandler(fh) #logger对象可以添加多个fh和ch对象 # logger.addHandler(ch) # 就是这样最终都被logger所吸收 # 保证了两个方法,还保证了输出格式 # 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') # logging库提供了多个组件:Logger、Handler、Filter、Formatter。 # Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地, # Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。 # Logger是一个树形层级结构,输出信息之前都要获得一个Logger(如果没有显示的获取则自动创建并使用root Logger,如第一个例子所示)。 # logger = logging.getLogger()返回一个默认的Logger也即root Logger,并应用默认的日志级别、Handler和Formatter设置。 # 当然也可以通过Logger.setLevel(lel)指定最低的日志级别,可用的日志级别有logging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、logging.CRITICAL。 # Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()输出不同级别的日志,只有日志等级大于或等于设置的日志级别的日志才会被输出。 # 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') # 只输出了 # 2014-05-06 12:54:43,222 - root - WARNING - logger warning message # 2014-05-06 12:54:43,223 - root - ERROR - logger error message # 2014-05-06 12:54:43,224 - root - CRITICAL - logger critical message # 从这个输出可以看出logger = logging.getLogger() # 返回的Logger名为root。这里没有用logger.setLevel(logging.Debug) # 显示的为logger设置日志级别,所以使用默认的日志级别WARNIING,故结果只输出了大于等于WARNIING级别的信息。 # 如果我们再创建两个logger对象: logger1 = logging.getLogger('mylogger') logger1.setLevel(logging.DEBUG) logger2 = logging.getLogger('mylogger') logger2.setLevel(logging.INFO) fh = logging.FileHandler('test') ch = logging.StreamHandler() logger1.addHandler(fh) logger1.addHandler(ch) logger2.addHandler(fh) logger2.addHandler(ch) logger1.debug('logger1 debug message') logger1.info('logger1 info message') logger1.warning('logger1 warning message') logger1.error('logger1 error message') logger1.critical('logger1 critical message') logger2.debug('logger2 debug message') logger2.info('logger2 info message') logger2.warning('logger2 warning message') logger2.error('logger2 error message') logger2.critical('logger2 critical message') #输出结果 # logger1 info message # logger1 warning message # logger1 error message # logger1 critical message # logger2 info message # logger2 warning message # logger2 error message # logger2 critical message # <1>我们明明通过logger1.setLevel(logging.DEBUG)将logger1的日志级别设置为了DEBUG, # 为何显示的时候没有显示出DEBUG级别的日志信息,而是从INFO级别的日志开始显示呢? # 原来logger1和logger2对应的是同一个Logger实例,只要logging.getLogger(name)中名称参数name相同则返回的Logger实例就是同一个, # 且仅有一个,也即name与Logger实例一一对应。在logger2实例中通过logger2.setLevel(logging.INFO)设置mylogger的日志级别为logging.INFO, # 所以最后logger1的输出遵从了后来设置的日志级别。 # # <2>为什么logger1、logger2对应的每个输出分别显示两次? # 这是因为我们通过logger = logging.getLogger()显示的创建了root Logger,而logger1 = logging.getLogger('mylogger') # 创建了root Logger的孩子(root.)mylogger,logger2同样。而孩子,孙子,重孙……既会将消息分发给他的handler进行处理也会传递 # 给所有的祖先Logger处理。 # 实际应用 import os import time import logging from config import settings def get_logger(card_num, struct_time): if struct_time.tm_mday < 23: file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon, 22) else: file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon+1, 22) file_handler = logging.FileHandler( os.path.join(settings.USER_DIR_FOLDER, card_num, 'record', file_name), encoding='utf-8' ) fmt = logging.Formatter(fmt="%(asctime)s : %(message)s") file_handler.setFormatter(fmt) logger1 = logging.Logger('user_logger', level=logging.INFO) logger1.addHandler(file_handler) return logger1
好了,要早睡了,神经都在跳动了