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)
    
  • 相关阅读:
    Oracle简介
    Python 新建程序
    HTML 标记 3 —— CSS
    Dreamweaver 2
    Dreamweaver 1 网页制作
    has-a关系——多重私有继承
    has-a关系——包含对象成员的类
    《使用wxWidgets进行跨平台程序开发》chap02——一个简单的应用程序
    抽象基类(ABC),纯虚函数
    普通类继承
  • 原文地址:https://www.cnblogs.com/xy-han/p/12615285.html
Copyright © 2011-2022 走看看