很多程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还可能有错误、警告等信息输出,python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志,
1 importlogging2 #日志的五个级别,分别由低到高
3 logging.debug('debug-hello')4 logging.info('info-lello') #日志默认level,级别比它高的才会在屏幕输出
5 logging.warning('hello-warning')6 logging.error("error-hello")7 logging.critical("critical-hello")8
9 #输出:
10
11 WARNING:root:hello-warning12 ERROR:root:error-hello13 CRITICAL:root:critical-hello
把日志存放到文件中:
其中下面这句中的level=loggin.INFO意思是,把日志纪录级别设置为INFO,也就是说,只有比日志是INFO或比INFO级别更高的日志才会被纪录到文件里,如果希望纪录debug的日志,那把日志级别改成DEBUG就行了:
logging.basicConfig(filename='example.log',level=logging.INFO)
logging.warning('is when this event was logged.')#加入时间
logging.basicConfig(filename='example.log', level=logging.INFO,format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.warning('is when this event was logged.')#加入时间运行效果
12/13/2016 04:04:50 PM is when this event was logged.
如果想同时把log打印在屏幕和文件日志里,就需要了解一点复杂的知识
Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适:
logger提供了应用程序可以直接使用的接口;
handler将(logger创建的)日志记录发送到合适的目的输出;
filter提供了细度设备来决定输出哪条日志记录(不常用);
formatter决定日志记录的最终输出格式。
logger
每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块可以这样获得它的Logger:
LOG=logging.getLogger(”chat.gui”)
而核心模块可以这样:
LOG=logging.getLogger(”chat.kernel”)
Logger.setLevel(lel):指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高
Logger.addFilter(filt)、Logger.removeFilter(filt):添加或删除指定的filter
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或删除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以设置的日志级别
handler
handler对象负责发送相关的信息到指定目的地。Python的日志系统有多种Handler可以使用。有些Handler可以把信息输出到控制台,有些Logger可以把信息输出到文件,还有些 Handler可以把信息发送到网络上。如果觉得不够用,还可以编写自己的Handler。可以通过addHandler()方法添加多个多handler
Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略
Handler.setFormatter():给这个handler选择一个格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象
每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:
1) logging.StreamHandler # 输出到屏幕
使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:
StreamHandler([strm])
其中strm参数是一个文件对象。默认是sys.stderr
2) logging.FileHandler(filename[,mode]) # 输出到文件
和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:
FileHandler(filename[,mode])
filename是文件名,必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。
3) logging.handlers.RotatingFileHandler
这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的构造函数是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode两个参数和FileHandler一样。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。
4) logging.handlers.TimedRotatingFileHandler
这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨
1 importlogging2
3 logg=logging.getLogger('TEST-LOG') #生成一个日志对象
4 logg.setLevel(logging.DEBUG)5
6 ch=logging.StreamHandler() #输出到屏幕的handler,用handler来指定日志输出到的对象
7 ch.setLevel(logging.WARNING)8
9 fh=logging.FileHandler('access.log') #指定输出到文件的handler
10 fh.setLevel(logging.ERROR)11
12 fomatter=logging.Formatter('%(asctime)s:%(lineno)s %(message)s') # 输出格式13 ch.setFormatter(fomatter)14 fh.setFormatter(fomatter)15
16 logg.addHandler(fh) #把handler添加到日志对象中去,告诉日志我应该输出到那里(文件/屏幕/邮件....)
17 logg.addHandler(ch)18
19 logg.warning("warning happend.......")20 logg.error("error happend...")
日志文件可以按时间和大小来分隔文件存放:
1 #每5S生成一个日志文件,保留3份
2 fh=handlers.TimedRotatingFileHandler(filename='log_file.log',when="S",interval=5,backupCount=3,encoding='utf-8')3 fomatter=logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')4 fh.setFormatter(fomatter)5 logge.addHandler(fh)6 logge.warning('test1')7 time.sleep(2)8 logge.warning('test2')9
10 #按文件大小自动截断日志文件
11 #fh=handlers.TimedRotatingFileHandler(filename='log_file.log',backupCount=3,maxBytes=10,encoding='utf-8')
4. os 和 sys 模块
OS模块常用方法
1 os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径2
3 os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd4 os.curdir 返回当前目录: ('.')5 os.pardir 获取当前目录的父目录字符串名:('..')6 os.makedirs('dirname1/dirname2') 可生成多层递归目录7 os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推8 os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname9 os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname10 os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印11 os.remove() 删除一个文件12 os.rename("oldname","newname") 重命名文件/目录13 os.stat('path/filename') 获取文件/目录信息14 os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
15 os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
16 os.pathsep 输出用于分割文件路径的字符串17 os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
18 os.system("bash command") 运行shell命令,直接显示19 os.environ 获取系统环境变量20 os.path.abspath(path) 返回path规范化的绝对路径21 os.path.split(path) 将path分割成目录和文件名二元组返回22 os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素23 os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素24 os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False25 os.path.isabs(path) 如果path是绝对路径,返回True26 os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False27 os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False28 os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略29 os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间30 os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
sys模块常用方法:
1 sys.argv 命令行参数List,第一个元素是程序本身路径2 sys.exit(n) 退出程序,正常退出时exit(0)3 sys.version 获取Python解释程序的版本信息4 sys.maxint 最大的Int值5 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值6 sys.platform 返回操作系统平台名称7 sys.stdout.write('please:')8 val = sys.stdin.readline()[:-1]
5.configparser 模块
用于对特定的配置进行操作。
1 #配置文件tt.ini
2 [section1]3 k1 = 123
4 k2 =tt15 [section2]6 k1 =v17
8 #配置文件格式有要求,section节点要用[],下面的元素信息要用k,v形式表达
9
10 #-*- coding:utf-8 -*-
11 #Author:pwj
12
13 importconfigparser14
15 config1=configparser.ConfigParser()16 config1.read("tt.ini")17 print(config1.sections()) #以列表形式输出配置文件里的所以section节点;['section1', 'section2']
18 option=config1.options('section1') #获取section1节点下的所有key;
19 print(option) #['k1', 'k2']
20 item_list=config1.items("section1") #获取section1节点下的所有k,v对;
21 print(item_list) #[('k1', 'v1'), ('k2', 'v2')]
22
23 val=config1.get('section1','k1') #获取section1节点k1的value值
24 print(val) #123
25 val2=config1.getint('section1','k1') #如果k1的value是int形式则可以直接转换成int数字
26 print(val2)27 #添加
28 ss2=config1.has_section("test") #判断配置文件里是否有test节点,有返回true,or false
29 config1.add_section("test") #添加节点
30 config1.set('test','k1','value123') #在test节点下添加k,v对
31 config1.write(open('tt.ini','w')) #修改写到配置文件中
32 #删除
33 ss=config1.remove_option('section1','k2') #删除section1下面的k2元素
34 config1.write(open('tt.ini','w')) #因为配置文件读在内存了,为了修改生效要写回原来配置文件中
35
36
37 #运行后的tt.ini :
38 [section1]39 k1 = 123
40 k2 =tt141 [section2]42 k1 =v143
44 [test]45 k1 = value123
6.re 正则模块
1 最常用的匹配语法:2 re.match 从头开始匹配3 re.search 匹配包含4 re.findall 把所有匹配到的字符放到以列表中的元素返回5 re.splitall 以匹配到的字符当做列表分隔符6 re.sub 匹配字符并替换
1 orr='hasaabc dfouenererehalaabc rer2e32434'
2 r1=re.match('h\w+',orr) # 从头开始匹配第一个满足条件的字符串3 r2=re.match('h(\w+)',orr) # 加()表示分组匹配4 r=re.match('h(?P\w+)',orr)5 print(r1.group()) #获取匹配到的结果 hasaabc
6 print(r2.groups()) #获取模型中匹配到的分组结果('asaabc',)
7 print(r.groupdict()) #获取模型中匹配到的分组结果,加入?p表示后面<>里是key ;{'name':'asaabc'}
8 rr=re.findall("h(\w+)",orr) #把所有匹配到的字符放到以列表中的元素返回
9 print(rr) #加括号表示分组,先匹配'h\w+',再在返回的结果中把满足分组的字符返回 ['asaabc', 'alaabc']
10 rr2=re.findall('h(\w+)a(ab)c',orr) #[('as', 'ab'), ('al', 'ab')]11 print(rr2)12
13 he="hello alex bcd alex lge alex acd 19"
14 r1=re.split('alex',he) #以匹配到的字符串作为列表分隔符 ['hello ', ' bcd ', ' lge ', ' acd 19']
15 r2=re.split("(alex)",he) #['hello ', 'alex', ' bcd ', 'alex', ' lge ', 'alex', ' acd 19']
16 r3=re.split('a(le)x',he) #['hello ', 'le', ' bcd ', 'le', ' lge ', 'le', ' acd 19']
17 r4=re.split('a(le)x',he,1) #后面的参数1表示只匹配一次,['hello ', 'le', ' bcd alex lge alex acd 19']
18 print(r1)19 print(r2)20 print(r3)
t1='22rerenr#trtpeenrerer'
print(re.search('\d',t1).group()) # \d 匹配一个数字0-9
print(re.search('2\w',t1).group()) # \w 匹配A-Za-z0-9之间的任意一个字符
print(re.search('\W',t1).group()) # 返回的是 #, \W 匹配的是非A-Za-z0-9之间的任意一个字符
print(re.search('\D',t1).group()) # \D 匹配非0-9
tt=re.search('\dr',t1).group() # 匹配数字\d
print(tt)
print(re.search("en",t1).group()) # 从头开始匹配,返回第一次匹配到的字符,后面不再继续匹配
print(re.findall("en",t1)) # 返回所有匹配到的字符串,返回结果是个列表
print(re.match("en",t1)) #从第一个字符位置开始匹配,后面即使有要找的字符串也不再进行匹配,如果没有就返回None
print(re.sub("en",'ppp',t1)) # 替换找到的字符串,找到几个就替换几个,第一参数是old字符串,第二参数是new字符串,第三个参数是需要操作的字符串
print(re.sub("en",'ppp',t1,1)) # 最后面一个数字表示最多只替换几次
print(re.subn('en','ppp',t1)) # 返回的是一个二元组,会返回总共替换了几次
print(re.split('en',t1)) # 把"en" 当作列表分隔符,返回的是列表
常用匹配规则:
1 '.'默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行2 '^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)3 '$' 匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以4 '*' 匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac") 结果为['abb', 'ab', 'a']5 '+' 匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']6 '?'匹配前一个字符1次或0次7 '{m}'匹配前一个字符m次8 '{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']9 '|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
10 '(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c11
12
13 '\A' 只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的14 '\Z'匹配字符结尾,同$15 '\d' 匹配数字0-9
16 '\D'匹配非数字17 '\w' 匹配[A-Za-z0-9]18 '\W' 匹配非[A-Za-z0-9]19 's' 匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'
20 [xyz] 字符集,匹配包含的任一字符。例如,“[abc]”匹配“plain”中的“a”21 [^xyz] 反向字符集。匹配未包含的任何字符。例如,“[^abc]”匹配“plain”中的“p”22 [a-z] 字符范围。匹配指定范围内的任何字符。例如,“[a-z]”匹配“a”到“z”范围内的任何小写字母
7. haslib 模块
用于加密相关的操作,代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
1 importhashlib2
3 ######### md5 ########
4
5 hash =hashlib.md5() # 不可逆的加密算法6 hash.update('admin')7 print(hash.hexdigest())8
9 ######### sha1 ########
10
11 hash =hashlib.sha1()12 hash.update('admin')13 print(hash.hexdigest())14
15 ######### sha256 ########
16
17 hash =hashlib.sha256()18 hash.update('admin')19 print(hash.hexdigest())20
21
22 ######### sha384 ########
23
24 hash =hashlib.sha384()25 hash.update('admin')26 print(hash.hexdigest())27
28 ######### sha512 ########
29
30 hash =hashlib.sha512()31 hash.update('admin')32 print(hash.hexdigest())
8.shutil 模块
shutil高级的 文件、文件夹、压缩包 处理模块
1 importshutil2
3 f=open('ww')4 f1=open('rr','w')5 shutil.copyfileobj(f,f1) #copy文件对象里的内容源到目的
6
7 #直接copy源文件到目的文件里
8 #shutil.copy(r'D:\myUI\index.html','test')
9
10 #把源文件夹copy到目的文件夹里
11 #shutil.copytree(r'C:\Users\pwj\PycharmProjects\S13day1\day1','day1_new')
12
13 #把root_dir目录打包压缩到C:\Users\pwj\目录下的day1.zip文件
14 shutil.make_archive(r"C:\Users\pwj\day1" ,format='zip',root_dir=r'C:\Users\pwj\PycharmProjects\S13day1\day1')15
16
17 importzipfile18 #压缩
19 #zip_obj=zipfile.ZipFile(r"D:\zip_test.zip",'w') # 可以压缩文件,不能压缩目录
20 #zip_obj.write('test') # 添加压缩文件里
21 #zip_obj.write('rr') # 添加压缩文件里
22
23
24 importtarfile25 #tar 只打包,不压缩
26 tar=tarfile.open(r"D:\ee.tar",'w')27 tar.add('rr') #可以把文件添加到打包文件里
28 tar.add(r"D:\zip_test.zip") #可以添加
29 #注意C:\Users\pwj\PycharmProjects\S13day1\day1这是个目录,下面有很多的文件
30
31 #把前面那个目录,以day1文件夹命名,添加到打包文件中
32 tar.add(r"C:\Users\pwj\PycharmProjects\S13day1\day1",arcname='day1')33
34 #可以打包目录,把绝对路径添加到打包文件里了,就是说要打开day1要逐层点进去
35 tar.add(r"C:\Users\pwj\PycharmProjects\S13day1\day1")
9. xml 模块
xml能解析2种类型的xml格式,分别为:xml的配置文件和xml格式的字符串
xml的元素统称为elment
1 #-*- coding:utf-8 -*-
2 #Author:pwj
3 importxml.etree.ElementTree as ET4 #5
6 #一.解析xml配置文件
7 #tree = ET.parse("tst.xml") # 打开一个xml文件
8 #root = tree.getroot() # 获取xml文件的根节点
9 #print(root.tag) # 打印根据的名称
10
11 #二.解析 xml格式编写的字符串文件
12 tree_str=open("xml_str.txt",'r').read()13 root= ET.XML(tree_str) #将字符串解析成特殊对象,root代指xml文件的根节点
14
15
16
17 #遍历xml文档
18 for child inroot:19 print(child.tag, child.attrib) #打印根节点下面的第一层子节点名和属性
20 for i inchild:21 print(i.tag,i.attrib,i.text) #再子一层,打印标签,标签属性,标签内容
22
23
24 #取出xml里面的所有年
25 for node in root.iter('year'):26 print(node.tag,node.text)27
28
29 #修改
30 for node in root.iter("year"):31 new_year=int(node.text)+1
32 node.text=str(new_year)33 node.set('ppp',"YES") #给含有year的标签加一个属性ppp=yes
34 tree.write("testxml") #修改写入新xml文件里
35 '''
36
37 # 删除node38 for country in root.findall('country'):39 print(country.find('rank').text)40 if int(country.find('rank').text) > 50:41 root.remove(country)
10. shelve 模块
shelve模块是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式:
1 ----------------------------s1.py -------写--------------------------
2
3 importshelve4
5 d=shelve.open('shelve_test') #打开一个文件
6
7 defstu_data(name,age):8 print("register stu",name,age)9
10 info={'name':'jony',"age":33}11 name=['alex','rain','coco']12 d['test']=name #存放列表数据
13 d['info']=info #存的是字典
14 d['func']=stu_data #存的是函数
15 d.close()16
17
18
19 ---------------------分割线,s2.py------读----------------------------------
20 importshelve21 defstu_data(name,age):22 print("stu",name,age)23
24 f=shelve.open("shelve_test") #打开一个文件
25 print(f['test']) #读s1.py文件存放的数据
26 print(f['func']) #这个存的是函数内存地址,s1.py里的读不到
27 print(f['info']) #读的是字典数据
28 print(f['func']("test",30)) #函数调用执行结果
11.反射和一些特殊变量
特殊变量及其含义:
1 __doc__
2
3 print(__doc__) #获取文件顶层的注释
4
5 __cached__
6 print(__cached__) #获取文件pyc文件所在的位置
7
8 __file__
9 print(__file__) #获取当前文件所在的路径
10
11 __package__
12 print(index.__package__) #获取index文件所在的包名
13
14 __name__
15 当__name__=__main__时,如果该文件是一个程序的入口,那么其他模块导入该文件时候不会启动程序的运行,只有在他自己文件里执行时才会运行
反射:
反射就是利用字符串的形式去对象(默认)中操作(寻找/检查/删除/设置)成员
方法:getattr(),hasattr(),setattr(),delattr()
1 #假设在index.py 模块里---------------------------
2 import commm #导入commm模块
3 defrun():4 inp=input("please input access url>>>")5 #func = getattr(commm,"login") # 去commm模块去找login成员,后面参数是字符串形式所以下面语句效果一样
6 #func=getattr(commm,inp) # 获取commm模块里的inp成员,不存在会出错
7 if hasattr(commm,inp): #查看commm模块里是否存在inp成员,存在返回true,or false
8 func=getattr(commm,inp)9 func()10 else:11 print('404')12 run()