疫情环境下的网络学习笔记 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\n 123_*()/*-'))
# 匹配空白字符

print(re.findall('\d','abc123_*()/*-'))
# 匹配所有数字

print(re.findall('\Aabc','abc123_*()/*-'))
# 从头开始匹配,匹配到abc,就马上返回abc,如果开头不是abc,结果为空

print(re.findall('\Z/*-','abc123_*()/*-'))
# 从结尾开始匹配

print(re.findall('abc','abc123abc_*()/*-'))
# 匹配所有的abc,返回一个列表

#################################
print(re.findall('^abc','abc123_*()/*-'))
# 匹配开头
print(re.findall('$abc','abc123_*()/*-'))
# 匹配结尾

# 重复匹配,与上面的\w,\d等搭配使用
# .点:匹配任意一个字符,除了\n之外
print(re.findall('a.b','a1\nbc123_*()/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')) # 匹配空白字符和 \n,\t[' ', ' ', ' ', ' ']
print(re.findall('\S','hello  egon  123')) # 匹配非空白字符['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3']

#\n \t都是空,都可以被\s匹配
print(re.findall('\s','hello \n egon \t 123')) #[' ', '\n', ' ', ' ', '\t', ' ']

#\n与\t
print(re.findall(r'\n','hello egon \n123')) #['\n']
print(re.findall(r'\t','hello egon\t123')) #['\n']

#\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与\Z
print(re.findall('\Ahe','hello egon 123')) 
# 从字符串第一个字符开始匹配 ['he']
# 使用 ^ 代替

print(re.findall('123\Z','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\nb,除非在后面再加一个参数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']
上一篇:Python 小栈_14:Python os模块和正则定理


下一篇:php中隐形字符65279(utf-8的BOM头)问题和fwrite写入文件bom头导致的乱码问题解决