zoukankan      html  css  js  c++  java
  • 疫情环境下的网络学习笔记 python 4.1

    4.1

    今日内容

    1. 日志模块的使用
    2. re模块:正则表达式
    3. 软件开发目录规范
    4. 内置函数

    日志模块

    import logging
    
    logging.debug('调试debug')
    # 10
    logging.info('消息info')
    # 20
    logging.warning('警告warn')
    # 30
    # 有风险,但是还能运行
    logging.error('错误error')
    # 40
    # 出现错误,程序无法运行
    logging.critical('严重critical')
    # 50
    # 严重的错误,崩溃
    
    '''
    WARNING:root:警告warn
    ERROR:root:错误error
    CRITICAL:root:严重critical
    '''
    

    日志自下而上匹配

    可以使用level指定日志级别,在到达设置的级别以上才会输出,默认级别是warning

    logging.basicConfig()在里面可以使用多种参数,自定义纪录日志

    配置日志格式

    # 日志格式
    logging.basicConfig(
        format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
    
        # 时间格式
        datefmt='%Y-%m-%d %H:%M:%S %p',
        level = 10,
    )
    
    logging.debug('调试debug') # 10
    logging.info('消息info')   # 20
    
    # 2020-04-01 09:30:40 AM - root - DEBUG -4.1:  调试debug
    # 2020-04-01 09:30:40 AM - root - INFO -4.1:  消息info
    

    日志输出位置

    日志可以指定输出位置,输出到终端或纪录到文件,不指定则默认输出到终端

    filename='access.log', # 不指定,默认打印到终端
    

    往文件里面写内容默认是操作系统的字符编码,默认打开可能乱码

    日志配置字典

    standard_format = '%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s'
    
    LOGGING_DIC = {
    	# 多个日志的格式
    	'formatters':{
    		'standard':{
                'format':standard_format
            },
            'simple':{...},
            'test':{...},
    	},
    	'handlers':{
            'console':{
                'level': 10,
            },
            'default':{},
            'others':{},
        }
    	'loggers':{
            'kkk':{
                'handlers':['consle','other'],
                'level':'DEBUG',  # y用于过滤错误级别,
                'propagate':False,  # 通常情况不需要的功能,改成False就好
            },
            'bbb':{
                'handlers':['consle','other'],
                'level':'ERROR',  # y用于过滤错误级别,
                'propagate':False,  # 通常情况不需要的功能,改成False就好
            },
        },
    }
    

    自定义日志的格式,把格式赋值给变量名,变量名存在字典里

    handlers:日志的接收者,可以定义不同的接收者:文件1,文件2,终端。。。

    loggers:日志的产生者,产生的日志传递给handler

    接下来,拿到日志的生产者,即loggers来产生日志,先导入日志配置字典

    import settings
    import loggings
    from loggings import config
    config.dicConfig(settings.LOGGING_DIC)
    logger1 = getLogger('kkk')
    logger1.info('info日志')
    logger1.debug('debug日志')
    

    日志名的命名

    日志名是区分日志业务归属的一种非常重要的标识,把loggers中的日志名改成 终端提示,用户交易一类的日志名

    对于像使用同一个logger的日志方法,但是不想使用logger指定的日志名:使用空名字字典

    • 建一个空名字的字典,在使用get.Logger() 里传入一个logger里不存在的名字,则会以这个传入的名字跟空名字的日志绑定,作为空名字的日志名写入日志

    日志轮转

    当日志文件增大,运行效率会降低,因此要定期对日志文件进行切分:指定大小,当文件到达一定的大小时自动切分

    设置maxBytesbackupCount的大小

    软件编写目录

    强调:getlogger应该写在common.py,在src里拿来用

    把start.py放在根目录下,环境变量会自动加载当前文件夹,也就是根目录,就不用用os.path.dirname 找到根目录了,bin文件夹可以删掉了

    re模块

    正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则

    使用 w 等参数,小写表示取,大写表示取反

    import re
    print(re.findall('w','abc123_*()/*-'))
    # w :字母,数字,下划线
    # ['a', 'b', 'c', '1', '2', '3', '_']
    print(re.findall('W','abc123_*()/*-'))
    # 大写W,取反,匹配非数字字母下划线
    
    print(re.findall('s','abc
     123_*()/*-'))
    # 匹配空白字符
    
    print(re.findall('d','abc123_*()/*-'))
    # 匹配所有数字
    
    print(re.findall('Aabc','abc123_*()/*-'))
    # 从头开始匹配,匹配到abc,就马上返回abc,如果开头不是abc,结果为空
    
    print(re.findall('/*-','abc123_*()/*-'))
    # 从结尾开始匹配
    
    print(re.findall('abc','abc123abc_*()/*-'))
    # 匹配所有的abc,返回一个列表
    
    #################################
    print(re.findall('^abc','abc123_*()/*-'))
    # 匹配开头
    print(re.findall('$abc','abc123_*()/*-'))
    # 匹配结尾
    
    # 重复匹配,与上面的w,d等搭配使用
    # .点:匹配任意一个字符,除了
    之外
    print(re.findall('a.b','a1
    bc123_*()/aaab*-'))
    # ['aab']
    
    # * 星 左侧字符重复0次或无穷次,性格贪婪
    
    # + 加号 左侧字符重复1次或无穷次,性格贪婪
    
    # ? 问号 左侧字符重复0次或1次,性格贪婪
    
    # {n,m} :左侧字符重复n次到m次,{n}单独一个n表示只出现一次
    
    

    重复匹配 * + ? {}

    匹配指定字符

    print(re.findall('a[012345]b',str,re.DOTALL))
    

    神游整理

    日志

    四个角色

    日志分为四个角色:logger,filter,handler,format

    • logger:产生日志,操作的对象
    • filter:基本不用
    • handler:接收logger传来的日志,可以打印到终端或文件
    • format:日志的格式

    logger产生日志后可以交给多个handler,每个handler需要捆绑一个格式,按照这个格式打印

    基本流程

    最普通的用法:使用logging模块生成一个日志,要有以下几步骤:

    1. 导入模块

    2. 造logger:logger1 = logging.getLogger('日志名字') 获取一个logger对象,可以为这个日志指定一个名字

    3. 造handler:

      • sh = logging.StreamHandler() 打印到终端
      • fh = logging.FileHandler('access.log',encoding='utf-8')打印到文件,可以指定字符编码
    4. 生成日志格式

      formatter1 = logging.Formatter(
      	fmt = '%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
      	datefmt='%Y-%m-%d %H:%M:%S %p',
      )
      
    5. 为handler绑定日志格式

      • sh.setFormatter(formatter1 = logging.Formatter()
    6. 为logger绑定handler

      • logger1.addHandler(sh)
    7. 测试日志

      logger1.debug('debug')
      logger1.info('info')
      # 先判断日志级别是否能通过logger的关卡,通过了则传给handler,handler关卡也通过了,则debug和info作为levelname,sh和fh作为name,括号内的字符串作为message,在终端和文件中纪录日志
      

    日志级别

    在使用logger的debug方法时,不同的方法有不同的级别,并非所有的信息都会被录入日志

    • 默认为30
    • 可以通过logger.setLevel(20)handler.setLevel(20)改变
    • 可以通过日志配置字典或logging.BasicConfig() 中指定 level 改变

    配置字典

    非常重要

    创造logger,handler等等都是在做初始化操作。可以通过把操作写进字典,自动加载

    import os
    
    # 定义三种日志格式
    standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' 
                      '[%(levelname)s][%(message)s]'
    
    simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
    
    test_format = '%(asctime)s] %(message)s'
    
    
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    # log文件的目录
    LOG_PATH = os.path.join(BASE_DIR,'a1.log')
    # 拼接路径,得到日志文件的地址,下面一会要用到
    
    # 日志配置字典
    LOGGING_DIC = {
        'version': 1,
        'disable_existing_loggers': False,
        # 不用管上面的
        
        # 四种角色之 格式:已经在上面写好了,这里直接使用变量名
        # formatters 名字是固定的,standard,simple这些是自己起的名字
        'formatters': {
            'standard': {
                'format': standard_format
            },
            'simple': {
                'format': simple_format
            },
            'test': {
                'format': test_format
            },
        },
        'filters': {},  # 不用管
        
        # 四大角色之 handler,控制接收的日志级别,往哪里打印
        # handlers名字固定,consle名字是自己起的
        'handlers': {
            #打印到终端的日志
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',  # 打印到屏幕
                'formatter': 'simple'
            },
            #打印到文件的日志,收集info及以上的日志
            'default': {
                'level': 'DEBUG',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,日志轮转
                'formatter': 'standard',
                # 可以定制日志文件路径
                'filename': 'a1.log',  # 日志文件
                'maxBytes': 1024*1024*5,  # 日志大小 5M
                'backupCount': 5,
                'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
            },
            'other': {
                'level': 'DEBUG',
                'class': 'logging.FileHandler',  # 保存到文件
                'formatter': 'test',
                'filename': 'a2.log',
                'encoding': 'utf-8',
            },
        },
        'loggers': {
            #logging.getLogger(__name__)拿到的logger配置
            '': {
                'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
                'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
                'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
            },
            '专门的采集': {
                'handlers': ['other',],
                'level': 'DEBUG',
                'propagate': False,
            },
        },
    }
    
    日志配置字典LOGGING_DIC
    

    其中loggers不指定名字,那么使用时没有找到指定名字的日志都使用这个空名字的logger

    在项目中使用配置字典

    • 配置字典写在settings.py

    • 使用日志字典的方法放在lib下的common.py里

    # common.py
    import os
    import logging
    from conf import settings
    
    def logger_handle(logger_name):
    	logging.config.dictConfig(settings.LOGING_DIC)  # 从settings加载配置字典
    	logger = logging.getLogger(logger_name)  # 生成一个logger对象,使用传入的参数作为logger的名字:配置字典里有这个名字则使用这个名字的logger,没有则使用空名字的logger
    	return logger
    
    
    # 使用的场景,src.py...
    import logging.config
    from lib import common
    
    def transfer():
        logger = common.logger_handle('转账')
        logger.debug('debug_msg')
    	
    

    正则

    特殊的符号组合在一起来描述字符串的方法,正则要做的事是通过字符的方法去匹配字符

    特殊符号

    re.findall(符号,要匹配的字符串) 方法为例

    import re
    #w与W 
    print(re.findall('w','hello egon 123')) # 匹配字母数字下划线 ['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3']
    print(re.findall('W','hello egon 123')) # 非字母数字下划线 [' ', ' ']
    
    #s与S
    print(re.findall('s','hello  egon  123')) # 匹配空白字符和 
    ,	[' ', ' ', ' ', ' ']
    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与D
    print(re.findall('d','hello egon 123')) # 数字['1', '2', '3']
    print(re.findall('D','hello egon 123')) # 非数字['h', 'e', 'l', 'l', 'o', ' ', 'e', 'g', 'o', 'n', ' ']
    
    #A与
    print(re.findall('Ahe','hello egon 123')) 
    # 从字符串第一个字符开始匹配 ['he']
    # 使用 ^ 代替
    
    print(re.findall('123','hello egon 123')) 
    # 从字符串最后开始倒着匹配 ['he'],
    # 可以使用 $ 代替
    
    #^与$
    print(re.findall('^h','hello egon 123')) #['h']
    print(re.findall('3$','hello egon 123')) #['3']
    
    

    重复匹配

    .,*,+,?,一般与上面的特殊字符配合使用

    真的绕

    1. . 点号,用于以一个格式匹配任意单个字符,斜杠n除外

      print(re.findall('a.','avxx sss1 as'))
      # 以a.格式匹配,得到a和a后面的一个字符 ['av', 'as']
      print(re.findall('a.b','a=bxx sss1 asb'))
      # 以a b 格式匹配,得到a b和中间的字符 ['a=b', 'asb']
      
      # a.b 不会输出 a
      b,除非在后面再加一个参数re.DOTALL 让re模块识别所有字符
      
    2. ?号,匹配?左边的字符串,一个一个与被匹配的字符串中的字符做比较,只要第一个字符匹配上,就输出第一个字符,后面的字符如果也一样匹配上了,就一起输出,没有匹配上就不会输出。

      最后输出的只能是?问好左边的字符

      print(re.findall('axx?','ax=bxx adxsss1 axxxasb'))
      # 后面的字符串与axx比对,遇到'ax=',前两个比对上了,则输出'ax',以此类推 
      # ['ax', 'axx']
      
    3. 左边的字符可以是0或着无穷多个

      print(re.findall('ax*','ax=axx adxsss1 axxxasb'))
      # ax用来和后面的字符串匹配,匹配上a,就输出a,再匹配后面是不是x,如果是x,那就一起输出,如果后面是一连串的x,那一连串的x都一起输出
      # 必须有a,x可以是0个或任意多个
      # ['ax', 'axx', 'a', 'axxx', 'a']
      
    4. +号,+左边的字符至少出现一次

      与*相比,+左边必须匹配上所有的字符,在此基础上,如果被匹配的字符串后面还有+号左边的字符,则继续输出

      print(re.findall('axx+','ax=axx adxsss1 axxxasb'))
      # 与axx匹配,遇到axx之后看axx后面还有没有更多的x,有则全都要
      # ['axx', 'axxx']
      
    5. {m,n} 花括号 ,花括号表示左边的字符出现m到n次,可以用来模仿 +,?一类

      print(re.findall('axx{0,1}','ax=bxx adxsss1 axxxasb'))
      # 花括号左边的字符出现0到1次,相当于?问好
      
      print(re.findall('ax{0,}','ax=bxx adxsss1 axxxasb'))
      # 左边的字符出现0到无穷次,相当于 *
      
      print(re.findall('ax{1,}','ax=bxx adxsss1 axxxasb'))
      # 左边的字符出现1到无穷次,相当于 *
      

      而且,还可以指定取的字符出现几次到几次

    组合使用

    1. 贪婪匹配 *. ** 点星

      print(re.findall('a.*b','a1b22222b222b')) 
      # 接收a,b之间的所有字符
      # ['a1b22222b222b']
      
    2. 非贪婪匹配 .*? 点星问号

      print(re.findall('a.*?b','a11111b22222222b'))
      # 返回第一次匹配成功得到的所有字符
      # ['a11111b']
      

    中括号 [ ]

    print(re.findall('[12365]','ax=axx ad1234xsss1 axxx981452asb'))
    # 表示只取中括号里面的字符
    
    # 加上 ^ 符号,表示取反,只取不在中括号内的字符
    print(re.findall('[^12365]','ax=axx ad1234xsss1 ax52'))
    # ['a', 'x', '=', 'a', 'x', 'x', ' ', 'a', 'd', '4', 'x', 's', 's', 's', ' ', 'a', 'x']
    
  • 相关阅读:
    RPC笔记之初探RPC:DIY简单RPC框架
    zookeeper笔记之基于zk实现分布式锁
    scala笔记之惰性赋值(lazy)
    Hive笔记之宏(macro)
    Zookeeper笔记之使用zk实现集群选主
    Zookeeper笔记之基于zk的分布式配置中心
    Zookeeper笔记之四字命令
    Zookeeper笔记之命令行操作
    复盘2018,展望2019
    爬虫笔记之w3cschool注册页面滑块验证码破解(巨简单滑块位置识别,非鼠标模拟轨迹)
  • 原文地址:https://www.cnblogs.com/telecasterfanclub/p/12615085.html
Copyright © 2011-2022 走看看