• 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

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

  • 相关阅读:
    Markdown 语法说明 (简体中文版)
    Markdown Reference
    BZOJ 2229 最小割
    BZOJ 3569 DZY Loves Chinese II
    BZOJ 3563 DZY Loves Chinese
    BZOJ 2956 模积和
    BZOJ 2957 楼房重建
    查漏补缺:面向对象设计原则
    添砖加瓦:设计模式(简单工厂模式)
    添砖加瓦:设计模式(总述)
  • 原文地址:https://www.cnblogs.com/xiaoyaotx/p/12459957.html
Copyright © 2020-2023  润新知