疫情环境下的网络学习笔记 python 4.1
4.1
今日内容
- 日志模块的使用
- re模块:正则表达式
- 软件开发目录规范
- 内置函数
日志模块
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里不存在的名字,则会以这个传入的名字跟空名字的日志绑定,作为空名字的日志名写入日志
日志轮转
当日志文件增大,运行效率会降低,因此要定期对日志文件进行切分:指定大小,当文件到达一定的大小时自动切分
设置maxBytes和backupCount的大小
软件编写目录
强调: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模块生成一个日志,要有以下几步骤:
- 
导入模块 
- 
造logger: logger1 = logging.getLogger('日志名字')获取一个logger对象,可以为这个日志指定一个名字
- 
造handler: - sh = logging.StreamHandler()打印到终端
- fh = logging.FileHandler('access.log',encoding='utf-8')打印到文件,可以指定字符编码
 
- 
生成日志格式 formatter1 = logging.Formatter( fmt = '%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', )
- 
为handler绑定日志格式 - sh.setFormatter(formatter1 = logging.Formatter()
 
- 
为logger绑定handler - logger1.addHandler(sh)
 
- 
测试日志 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']
重复匹配
.,*,+,?,一般与上面的特殊字符配合使用
真的绕
- 
. 点号,用于以一个格式匹配任意单个字符,斜杠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模块识别所有字符
- 
?号,匹配?左边的字符串,一个一个与被匹配的字符串中的字符做比较,只要第一个字符匹配上,就输出第一个字符,后面的字符如果也一样匹配上了,就一起输出,没有匹配上就不会输出。 最后输出的只能是?问好左边的字符 print(re.findall('axx?','ax=bxx adxsss1 axxxasb')) # 后面的字符串与axx比对,遇到'ax=',前两个比对上了,则输出'ax',以此类推 # ['ax', 'axx']
- 
号 ,左边的字符可以是0或着无穷多个 print(re.findall('ax*','ax=axx adxsss1 axxxasb')) # ax用来和后面的字符串匹配,匹配上a,就输出a,再匹配后面是不是x,如果是x,那就一起输出,如果后面是一连串的x,那一连串的x都一起输出 # 必须有a,x可以是0个或任意多个 # ['ax', 'axx', 'a', 'axxx', 'a']
- 
+号,+左边的字符至少出现一次 与*相比,+左边必须匹配上所有的字符,在此基础上,如果被匹配的字符串后面还有+号左边的字符,则继续输出 print(re.findall('axx+','ax=axx adxsss1 axxxasb')) # 与axx匹配,遇到axx之后看axx后面还有没有更多的x,有则全都要 # ['axx', 'axxx']
- 
{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到无穷次,相当于 *而且,还可以指定取的字符出现几次到几次 
组合使用
- 
贪婪匹配 *. ** 点星 print(re.findall('a.*b','a1b22222b222b')) # 接收a,b之间的所有字符 # ['a1b22222b222b']
- 
非贪婪匹配 .*? 点星问号 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']

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号