一 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)