Python之旅的第17天(re模块logging模块)

Posted 崆峒山肖大侠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python之旅的第17天(re模块logging模块)相关的知识,希望对你有一定的参考价值。

越来越有意思了,绕弯弯的转义符听得爽的飞起,这感觉真的很爽

re模块补充了很多内容,后期应该会很强大,但是现在就是个皮毛啊,明天这个计算器得好好整理一下思路,联系一下

一、re模块补充

import re
#  关于转义符的补充
# 首先要明确,一个转义符要进入Python中的re模块中,需要经过两次转义
# 首先是Python解释器的转义,随后是re模块中的转义
# 下面举例说明

# print(re.findall(‘I\b‘, ‘I am LIST‘))
# 这里首先的需求是我们要得到后面的第一个大写I,使用了表示空格和特殊字符
# 为什么需要两个 进行表示呢,首先在解释器中也是具有转义含义的,所以解释器在读取时会消耗掉一个,为了保证传输个re模块时仍然是
# 我们必须要将第二个转换为没有意义的字符,那么此时在解释器运行时,第一个就将第二个转换成为一个没有意义的字符
# 进入re模块读取时,前面的规则内容就成为了‘I‘,此时re模块就能识别是I 加上空格的意思
# 或者还可以使用r,表示原生字符,没有任何意义
# print(re.findall(r‘I‘, ‘I am LIST‘))

# 如果需要匹配字符串‘abcd‘中的cd我们该如何对应呢
# 首先,我们确定一下在进入re模块时,我们的查询规则应该是c\d,这样才能确保re模块能够读取到cd
# 所以再向上推论解释器,解释器需要给re模块传递两个字符c\d,那么他就需要对两个进行转义,这么一来就需要在最外面输入四个转义符
# print(re.findall(‘c\\d‘, ‘abcd‘))    #输出结果:[‘c\d‘]
# 之所以输出结果有两个,表示的就是解释器读取状态,必须两个才能传入正确的cd
# 请记住进入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

好了,要早睡了,神经都在跳动了

以上是关于Python之旅的第17天(re模块logging模块)的主要内容,如果未能解决你的问题,请参考以下文章

Python之旅的第15天(osjsonsys模块,模块引入补充)

Python学习之旅---模块介绍(re模块,正则表达式)

Python的学习之旅———re 模块正则表达式

Python之旅的第19天(类的初识)

Python之旅的第30天(过程记录,选课系统的基本实现)

Python之旅的第3²天(内置函数文件基本打开关闭)