zoukankan      html  css  js  c++  java
  • 日志模块与 re 模块

    一 logging模块

    1、logging 模块介绍

    logging模块 :日志模块,记录日志

    import logging
    
    # 一:日志配置
    logging.basicConfig(
        # 1、日志输出位置:1、终端 2、文件
        filename='access.log', #显示到文件中(自己创建文件),此时不能同时在终端与文件中显示。  #如果不指定,默认打印到终端
    
        # 2、日志格式 :打印的日志格式
      '''
      module:哪个模块在记录日志
      '''
        format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
    
        # 3、时间格式
        datefmt='%Y-%m-%d %H:%M:%S %p',  #%p :显示上下午
    
        # 4、日志级别
        # critical => 50
        # error => 40
        # warning => 30
        # info => 20
        # debug => 10
        level=30,
    )
    
    # 二:输出日志
    logging.debug('调试debug')  #调试用的 #10
    logging.info('消息info') #20
    logging.warning('警告warn') #30
    logging.error('错误error') #40
    logging.critical('严重critical') #50
    
    
    #结果展示:
    '''
    # 注意下面的root是默认的日志名字
    WARNING:root:警告warn
    ERROR:root:错误error
    CRITICAL:root:严重critical
    '''
    
    #为什么结果显示的上面三条信息,前两条没有显示?
    '''
    设置了日志级别level为30(注:默认也是30),上面两条日志级别比较低,分别为10,20
    '''
    

    2、如何定制日志格式

    """
    logging配置
    """
    
    import os
    
    # 1、定义三种日志输出格式,日志中可能用到的格式化串如下
    # %(name)s Logger的名字,是记录信息的key
    # %(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用户输出的消息
    
    # 2、强调:其中的%(name)s为getlogger时指定的名字   如#task_id:测试日志 或者 用户交易
    
    #日志记录的格式1文件)
    standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' 
                      '[%(levelname)s][%(message)s]'
    #日志记录的格式2(终端)
    simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
    
    #日志记录的格式3(文件)
    test_format = '%(asctime)s] %(message)s'
    
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))  
    LOG_PATH = os.path.join(BASE_DIR, 'log') #log文件的目录
    ATM_LOG_PATH = os.path.join(LOG_PATH, 'ATM') 
    
    # 3、日志配置字典
    LOGGING_DIC = {
        'version': 1, #版本,自定义的
        'disable_existing_loggers': False, #关闭已存在日志 #自定义的
        'formatters': {   #formatters:日志记录的格式分类,名字是固定的
            'standard': { #文件采用的日志格式,名字是自定定义的
                'format': standard_format  #format:日志记录的格式,名字是固定的
            },
            'simple': { #终端采用的日志格式,名字是自定定义的
                'format': simple_format
            },
            'test': { #文件采用的日志格式,名字是自定定义的
                'format': test_format
            },
        },
     
        'filters': {}, #不用管
      
      	#handlers是日志的接收者,不同的 handler会将日志输出到不同的位置(如终端或文件)
        'handlers': {  
            #1) 终端接收日志
            'console': { #console是自定义的,它是接收日志的位置方式名字
                'level': 'DEBUG', #接收日志记录级别
              	#往哪里输,输出到哪个位置
                'class': 'logging.StreamHandler',  # 打印到屏幕
              	#日志记录格式
                'formatter': 'simple' 
            },
          
            #2) 文件接收日志,收集info及以上的日志(等级)
            'default': { #default是自定义的, 它是接收日志的位置方式名字
                'level': 'DEBUG', #接收日志记录级别
              	#往哪里输,输出到哪个位置
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,日志轮转
              	#日志记录格式
                'formatter': 'standard',
                # 可以定制日志文件路径
                # BASE_DIR = os.path.dirname(os.path.abspath(__file__))  # log文件的目录
               # LOG_PATH = os.path.join(BASE_DIR,'a1.log')
              	#保存的日志文件的文件名
              	 # LOG_PATH = os.path.join(BASE_DIR,'a1.log')
                'filename': LOG_PATH,  # 日志文件  #这里应该放绝对路径
              	#日志文件大小
                'maxBytes': 1024*1024*5,  # 日志大小5M, 超过就会新建一个日志文件,将老的日志转到新建的文件中
                'backupCount': 5, #日志备份最多保存几份,超过的就会被删除
                'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
            },
          
          	#3) 其他自定义日志,文件接收
            'other': {
                'level': 'DEBUG',#接收日志记录级别
              	#往哪里输
                'class': 'logging.FileHandler',  # 保存到文件
              	#日志记录格式
                'formatter': 'test',
              	#os.path.join(os.path.dirname(os.path.dirname(__file__)), 'a2.log')
                'filename': 'a2.log',   #这里应该放绝对路径
                'encoding': 'utf-8',
            },
        },
      
      	#loggers 是日志的产生者,产生的日志会传递给 handler 然后控制输出
        'loggers': {
            #logging.getLogger(__name__)拿到的logger配置,即以下:
          	#日志产生配置 1
            '测试日志': { # 日志的产生者 1 (测试日志:是记录信息的 key)
                'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
              	#记录日志级别
                'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制),
                'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
            },
          
          	#日志产生配置 2
            '用户交易': { # 日志的产生者 2 (用户交易:是记录信息的key)
                'handlers': ['other',], #只将日志打印到文件
              	#记录日志级别
                'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
                'propagate': False,# 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
            },
          
           #日志产生配置 3 (针对不同场景,输出不同的记录关键字:这是在logging.getLogger(__name__)找不到__anme__ 时,会使用这个日志产生配置)
           '': { #日志的产生者3  记录信息的key为:logging.getLogger(__name__)的__name__
                'handlers': ['default',], 
             		#记录日志级别
                'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
                'propagate': False,# 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
            },
        },
    }
    
    
    

    3 使用

    import settings
    
    # !!!强调!!!
    # 1、logging是一个包,需要使用其下的config、getLogger,可以如下导入
    # from logging import config    #只要是导入,就会导入 logging
    # from logging import getLogger
    
    # 2、也可以使用如下导入 
    import logging.config # 因为导入了 logging,所以包下面的模块都会被导入
    #这样连同logging.getLogger都一起导入了,然后使用前缀logging.config.   
    
    # 3、加载配置
    logging.config.dictConfig(settings.LOGGING_DIC)
    
    # 4、拿到日志的产生者,即 loggers 来产生日志
    #第一个日志产生者:'测试日志'
    #第二个日志产生者:'用户交易'
    #第三个日志产生者: ''
    logger1=logging.getLogger('测试日志') #日志的方式(信息往哪里输入)
    logger1.debug('这debug级的日志')
    logger1.info('info级的日志')
    logger1.error('error级的日志')
    
    # logger2=logging.getLogger('11') # 传入日志产生者,因为'11'不存在,所以调用第三个日志产生者: ''
    # logger2.debug('debug 级的日志')
    # logger2.info('正常信息级的日志')
    # logger2.critical('critical级别的日志')
    
    # logger1=logging.getLogger('用户交易') #记录日志的方式(往哪里输入)
    # logger1.info('这是二条日志')
    
    common.py
    

    4 两个重要的知识

    1、日志名的命名

    日志名是区别日志业务归属的一种非常重要的标识

    2、日志轮转

    日志记录着程序员运行过程中的关键信息

    当日志文件达到一定大小时,会进行日志轮转

    二 re模块

    re 模块是 python 的内置模块,提供了正则匹配方法

    1、什么是正则

     正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。****(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。

    生活中处处都是正则:

    ​ 四条腿:桌子,椅子,马,猪等

    ​ 四条腿,活的:马,猪等

    2、 re 模块有什么作用

    ​ 在文本或者字符串内获取你所需要的东西

    s = '我爱中国'
    import re
    
    res = re.findall('我爱(.{2})',s)
    print(res) #['中国']
    

    ​ re模块基础使用

    s = '我爱中国, 中国'
    import re
    
    res = re.findall('中国',s)
    print(res) #['中国', '中国']
    

    3、元字符

    元字符会有特殊的意义

    常用的元字符有:

        1. ^  从开头进行匹配
        2. $  从结尾进行匹配
        3. |  相当于or,或者的意思
        4. [] 找到[]内的任意一个元素的所有元素,^放在里面就是反取
        5. .  任意一个字符
        6. {3}大括号前面的字符匹配3次,{m,n}匹配前一个字符m至n次,{m,}则匹配m至无限次
        7. *  前面的字符匹配0-无穷个
        8. +  前面的字符匹配1-无穷个
        9. ?  前面的字符匹配0-1个
        10. d 匹配数字[0-9]                D  匹配非数字
        11. s 匹配空白字符(包括	
    fv) S  匹配非空白字符
        12. w 匹配字符,字母,数字,下划线     W  匹配非字母数字下划线
        13. .*?:视情况而定
    

    1 例题

    # =================================匹配模式=================================
    #一对一的匹配
    # 'hello'.replace(old,new)
    # 'hello'.find('pattern')
    
    #正则匹配
    import re
    '''findall:找所有字符,返回值是列表'''
    #w:字母数字下划线
    print(re.findall('w','hello egon 123')) #['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3']
    #W:非字母数字下划线
    print(re.findall('W','hello egon 123')) #[' ', ' ']
    
    #s:空白字符
    print(re.findall('s','hello  egon  123')) #[' ', ' ']
    #S:非空字符
    print(re.findall('S','hello  egon  123')) #['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3']
    
    #
     	都是空,都可以被s匹配
    print(re.findall('s','hello 
     egon 	 123')) #[' ', '
    ', ' ', ' ', '	', ' ']
    
    #
    与	
    print(re.findall(r'
    ','hello egon 
    123')) #['
    ']
    print(re.findall(r'	','hello egon	123')) #['
    ']
    
    #d :数字
    print(re.findall('d','hello egon 123')) #['1', '2', '3']
    #D :非数字
    print(re.findall('D','hello egon 123')) #['h', 'e', 'l', 'l', 'o', ' ', 'e', 'g', 'o', 'n', ' ']
    
    #A :从头开始匹配(只匹配开头) A==>^
    print(re.findall('Ahe','hello egon 123')) #['he'],A==>^
    #: 从尾部开始匹配(只匹配结尾) ==>$
    print(re.findall('123','hello egon 123')) #['123'],==>$
    
    #^:
    print(re.findall('^h','hello egon 123')) #['h']
    #$:
    print(re.findall('3$','hello egon 123')) #['3']
    
    # 重复匹配:| . | * | ? | .* | .*? | + | {n,m} |
    #.:匹配除了 
     之外的任意一个字符
    print(re.findall('a.b','a1b')) #['a1b']
    print(re.findall('a.b','a1b a*b a b aaab')) #['a1b', 'a*b', 'a b', 'aab']
    print(re.findall('a.b','a
    b')) #[]
    print(re.findall('a.b','a
    b',re.S)) #['a
    b']
    #re.DOTALL:指定re.DOTALL之后才能匹配换行符(
    )
    print(re.findall('a.b','a
    b',re.DOTALL)) #['a
    b']同上一条意思一样
    
    #*:左侧字符重复0次或无穷次,性格贪婪,不单独使用
    print(re.findall('ab*','bbbbbbb')) #[]
    print(re.findall('ab*','a')) #['a']
    print(re.findall('ab*','abbbb')) #['abbbb']
    print(re.findall('ab*', 'abcbbbb')) #['ab']
    print(re.findall('ab.*', 'abcbbb')) #[['abcbbb']
    print(re.findall('ab*', 'aaaaa')) #['a', 'a', 'a', 'a', 'a']
    
    
    #?:左侧字符重复 0 次或 1 次,性格非贪婪 不单独使用
    print(re.findall('ab?','a')) #['a']
    print(re.findall('ab?','abbb')) #['ab']
    
    
    #匹配所有包含小数在内的数字,即整数或者小数 (.: 代表转义,让符号 . 表示为一个点)
    print(re.findall('d+.?d*',"asdfasdf123as1.13dfa12adsf1asdf3")) #['123', '1.13', '12', '1', '3']
    
    #.*默认为贪婪匹b
    #'a.*b':匹配拿到[a,b](a为要匹配的字符串中第一个a, b为字符串中最后一个b)之间所有的非
     字符,贪婪匹配
    print(re.findall('a.*b','a1b22222222b')) #['a1b22222222b']
    print(re.findall('a.*b','a
    b22222222b')) #[] #有
    ,所以为空
    print(re.findall('a.*b','a22222222b')) #['a22222222b']
    
    #.*?为非贪婪匹配:推荐使用
    #a.*?b:匹配拿到[a,b](a为要匹配的字符串中的第一个 a, b为字符串中找到的第一个b)之间所有的非
     字符
    print(re.findall('a.*?b','a1b22222222b22')) #['a1b']
    print(re.findall('a.*?b','ab22222222b22')) #['ab']
    print(re.findall('a.*?b','a22222222b22')) #['a22222222b']
    
    
    #.?:非贪婪匹配
    print(re.findall('a.?b','a22222222b')) #[]
    print(re.findall('a.?b','ab22222222b')) #['ab']
    print(re.findall('a.?b','a1b22222222b')) #['a1b']
    
    #+:左侧字符重复 1 次或者无穷次,性格贪婪
    print(re.findall('ab+','a')) #[]
    print(re.findall('ab+','abbb')) #['abbb']
    
    #{n,m}:左侧字符重复 n 次到 m 次,性格贪婪
    #{0,} => *
    #{1,} => +
    #{0,1}=> ?
    #{n}:单独一个 n 代表重复 n 次,多一次也不行
    print(re.findall('ab{2}','abbb')) #['abb']
    print(re.findall('ab{2,4}','abbb')) #['abbb']
    print(re.findall('ab{1,}','abbb')) #'ab{1,}' ===> 'ab+'
    print(re.findall('ab{0,}','abbb')) #'ab{0,}' ===> 'ab*'
    
    #[]:匹配指定字符范围中的一个字符,[]括号内为匹配字符范围
    print(re.findall('a[1*-]b','a1b a*b a-b')) #[]内的都为普通字符了,且如果-没有被转意的话,应该放到[]的开头或结尾
    #[^]:[]内的^代表的意思是取反
    print(re.findall('a[^1*-]b','a1b a*b a-b a=b')) #['a=b'],  []内的^代表的意思是取反,即不是 1,*,-
    print(re.findall('a[0-9]b','a1b a*b a-b a=b, a5b')) #['a1b', 'a5b'] , [0-9]:[]内的-左右两边都是数字或者字母,代表区间范围[0,9]
    print(re.findall('a[a-z]b','a1b a*b a-b a=b aeb, abb')) #['aeb', 'abb'] ,[a-z]:[]内的-左右两边都是数字或者字母,代表区间范围[a,z]
    print(re.findall('a[a-zA-Z]b','a1b a*b a-b a=b aeb aEb')) #['aeb', 'aEb']
    
    ## print(re.findall('a\c','ac')) #对于正则来说a\c确实可以匹配到ac,但是在python解释器读取a\c时,会发生转义,然后交给re去执行,所以抛出异常
    print(re.findall(r'a\c','ac')) #r代表告诉解释器使用rawstring,即原生字符串,把我们正则内的所有符号都当普通字符处理,不要转义
    print(re.findall('a\\c','ac')) #同上面的意思一样,和上面的结果一样都是['a\c']
    
    #():分组 ,findall的结果不是匹配的全部内容,而是组内()的内容
    #()内的 ?: ,可以让结果为匹配的全部内容
    print(re.findall('ab+','ababab123')) #['ab', 'ab', 'ab']
    print(re.findall('(ab)+123','ababab123')) #['ab'],匹配到末尾的ab123中的ab
    print(re.findall('(?:ab)+123','ababab123')) #['ababab123'] findall的结果不是匹配的全部内容,而是组内的内容,?:可以让结果为匹配的全部内容:'ab+123'
    print(re.findall('(?:ab)+123','b123'))  #[]
    print(re.findall('(?:ab)+123','aaaab123'))  #['ab123']
    
    print(re.findall("ab+(.*?)","ab22222222ab123")) #[''] ['']
    print(re.findall('(ab)+123','ab123abab123')) #['ab', 'ab']
    print(re.findall("ab'(.*?)'","ab'22222222b123'")) #['22222222b123']
    
    #具体示例:
    print(re.findall('href="(.*?)"','<a href="http://www.baidu.com">点击</a>'))#['http://www.baidu.com']  返回值为匹配内容中的分组内的内容
    print(re.findall('href="(?:.*?)"','<a href="http://www.baidu.com">点击</a>'))#['href="http://www.baidu.com"'] 返回值为匹配内容
    print(re.findall('href="(.*?)"','<a href="http://www.baidu.com   http://www.baidu.com">点击</a>'))#['http://www.baidu.com   http://www.baidu.com']
    
    #| 或
    #a|b:匹配 a 或 b
    print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company')) #['companies', 'company']
    
    

    2、re模块提供的方法

    # ===========================re模块提供的方法介绍===========================
    import re
    #1
    print(re.findall('e','alex make love') )   #['e', 'e', 'e'],返回所有满足匹配条件的结果,放在列表里
    #2
    print(re.search('e','alex make love').group()) #e,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
    
    #3
    print(re.match('e','alex make love'))    #None,同search,不过在字符串开始处进行匹配,完全可以用search+^代替match
    
    #4
    print(re.split('[ab]','abcd'))     #['', '', 'cd'],先按'a'分割得到''和'bcd',再对''和'bcd'分别按'b'分割
    
    #5
    print('===>',re.sub('a','A','alex make love')) #===> Alex mAke love,不指定n,默认替换所有
    print('===>',re.sub('a','A','alex make love',1)) #===> Alex make love
    print('===>',re.sub('a','A','alex make love',2)) #===> Alex mAke love
    print('===>',re.sub('^(w+)(.*?s)(w+)(.*?s)(w+)(.*?)$',r'52341','alex make love')) #===> love make alex
    
    print('===>',re.subn('a','A','alex make love')) #===> ('Alex mAke love', 2),结果带有总共替换的个数
    
    
    #6
    obj=re.compile('d{2}')
    
    print(obj.search('abc123eeee').group()) #12
    print(obj.findall('abc123eeee')) #['12'],重用了obj
    

    3 补充

    补充一

    import re
    print(re.findall("<(?P<tag_name>w+)>w+</(?P=tag_name)>","<h1>hello</h1>")) #['h1']
    print(re.search("<(?P<tag_name>w+)>w+</(?P=tag_name)>","<h1>hello</h1>").group()) #<h1>hello</h1>
    print(re.search("<(?P<tag_name>w+)>w+</(?P=tag_name)>","<h1>hello</h1>").groupdict()) #<h1>hello</h1>
    
    print(re.search(r"<(w+)>w+</(w+)>","<h1>hello</h1>").group())
    print(re.search(r"<(w+)>w+</1>","<h1>hello</h1>").group())
    

    补充二

    #补充二
    import re
    
    #使用|,先匹配的先生效,|左边是匹配小数,而findall最终结果是查看分组,所有即使匹配成功小数也不会存入结果
    #而不是小数时,就去匹配(-?d+),匹配到的自然就是,非小数的数,在此处即整数
    #
    print(re.findall(r"-?d+.d*|(-?d+)","1-2*(60+(-40.35/5)-(-4*3))")) #找出所有整数['1', '-2', '60', '', '5', '-4', '3']
    
    #找到所有数字:
    print(re.findall('D?(-?d+.?d*)',"1-2*(60+(-40.35/5)-(-4*3))")) # ['1','2','60','-40.35','5','-4','3']
    
    
    #计算器作业参考:http://www.cnblogs.com/wupeiqi/articles/4949995.html
    expression='1-2*((60+2*(-3-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'
    
    content=re.search('(([-+*/]*d+.?d*)+)',expression).group() #(-3-40.0/5)
    
  • 相关阅读:
    jvisualm 结合 visualGC 进行jvm监控,并分析垃圾回收
    linux 查看服务器cpu 与内存配置
    arthas 使用总结
    selinux contexts 安全上下文的临时更改
    Android 8.1 Doze模式分析(五) Doze白名单及Debug方式
    Window 任意窗口置顶软件Window TopMost Control
    Android ApkToolPlus一个可视化的跨平台 apk 分析工具
    SVN Please execute the 'Cleanup' command.
    Android 如何在64位安卓系统中使用32位SO库
    Android cmd命令查看apk是32位还是64位?
  • 原文地址:https://www.cnblogs.com/xy-han/p/12615285.html
Copyright © 2011-2022 走看看