python进阶之 ——常用模块
序列化:将内存中数据类型转成另一种格式
优点:I.持久保存程序运行状态 II.数据的跨平台性
json
import json # 方法1 dict1 = {"name": '张'} js_dict1=json.dumps(dict1) with open('dict1.json','wt',encoding='utf8') as f: f.write(js_dict1) with open('dict1.json','rt',encoding='utf8') as f1: res=f1.read() dict1=json.loads(res) print(type(dict1)) # <class 'dict'> # 方法2 with open('dict1.json','wt',encoding='utf8') as f: json.dump(dict1,f) with open('dict1.json','rt',encoding='utf8') as f1: dict2=json.load(f1) print(dict2)
优:其为通用格式,所有编程语言都可识别,跨平台性好
缺:不能识别所有python类型(如' ',其全为" ")
pickle(序列化)
import pickle with open('dict1.picke','wb',) as f: pickle.dump(dict1,f) with open('dict1.picke','rb',) as f2: dict2=pickle.load(f2) print(dict2) # ---------------------- dict1_p = pickle.dumps(dict1) with open('dict1.pkl', 'wb', ) as f: f.write(dict1_p) with open('dict1.pkl', 'rb', ) as f1: dict2 = pickle.loads(f1.read()) print(dict2)
优:可识别所有python类型
缺:只能被python识别(可序列化set类型)
shelve序列化 ,只有一个open函数,其使用方式与字典一致
import shelve s = shelve.open("shelve附件") # 打开一个文件 windows里是三个文件 unix linux 是一个 不能跨平台 # s现在可以看作一个文件形式的字典 s["字典的key"] = "value" # vaule 可以是python3的任意类型 print(s["字典的key"]) # print(s["不存在的key"]) # 会报错 s["继续写入"] = "新增值" ## 追加写入 自动换行 文件不用打开 打开也看不懂 s.close() # 记得关闭
time、datatime
time.time 时间戳
time.sleep 让程序休眠指定时间
import time print(time.time()) # 时间戳(timestamp),表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。 print(time.strftime("%Y-%m-%d %X")) #格式化时间 print(time.localtime()) #本地时区的struct_time print(time.gmtime()) #UTC时区的struct_time sleep(secs) :线程推迟指定的时间运行,单位为秒。 格式化的时间字符串(Format String) struct_time:结构化的时间,struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时) 格式化的时间字符:提供时间和自定义格式
%a Locale’s abbreviated weekday name. %A Locale’s full weekday name. %b Locale’s abbreviated month name. %B Locale’s full month name. %c Locale’s appropriate date and time representation. %d Day of the month as a decimal number [01,31]. %H Hour (24-hour clock) as a decimal number [00,23]. %I Hour (12-hour clock) as a decimal number [01,12]. %j Day of the year as a decimal number [001,366]. %m Month as a decimal number [01,12]. %M Minute as a decimal number [00,59]. %p Locale’s equivalent of either AM or PM. (1) %S Second as a decimal number [00,61]. (2) %U Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0. (3) %w Weekday as a decimal number [0(Sunday),6]. %W Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0. (3) %x Locale’s appropriate date representation. %X Locale’s appropriate time representation. %y Year without century as a decimal number [00,99]. %Y Year with century as a decimal number. %z Time zone offset indicating a positive or negative time difference from UTC/GMT of the form +HHMM or -HHMM, where H represents decimal hour digits and M represents decimal minute digits [-23:59, +23:59]. %Z Time zone name (no characters if no time zone exists). %% A literal '%' character.
转换关系:
localtime([secs]) # 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。 time.localtime() time.localtime(1473525444.037215) #gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。 # mktime(t) : 将一个struct_time转化为时间戳。 print(time.mktime(time.localtime()))#1473525749.0 # strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个 # 元素越界,ValueError的错误将会被抛出。 print(time.strftime("%Y-%m-%d %X", time.localtime()))#2016-09-11 00:49:56 # time.strptime(string[, format]) # 把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。 print(time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X')) #time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6, # tm_wday=3, tm_yday=125, tm_isdst=-1) # 在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。
datatime
import datetime # print(datetime.datetime.now()) #print(datetime.date.fromtimestamp(time.time()) ) # 时间戳直接转成日期格式 2016-08-19 # print(datetime.datetime.now() ) # print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间+3天 # print(datetime.datetime.now() + datetime.timedelta(-3)) #当前时间-3天 # print(datetime.datetime.now() + datetime.timedelta(hours=3)) #当前时间+3小时 # print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #当前时间+30分 # # c_time = datetime.datetime.now() # print(c_time.replace(minute=3,hour=2)) #时间替换
random随机数相关
import random print(random.random())#(0,1)----float 大于0且小于1之间的小数 print(random.randint(1,3)) #[1,3] 大于等于1且小于等于3之间的整数 print(random.randrange(1,3)) #[1,3) 大于等于1且小于3之间的整数 print(random.choice([1,'23',[4,5]]))#1或者23或者[4,5] print(random.sample([1,'23',[4,5]],2))#列表元素任意2个组合 print(random.uniform(1,3))#大于1小于3的小数,如1.927109612082716 item=[1,3,5,7,9] random.shuffle(item) #打乱顺序 print(item)
import random def code(num=4): str1 = "" for i in range(num): digit0 = str(random.randint(0, 9)) # 生成数字 alpha0 = chr(random.randint(65, 90)) # 生成字母 str0 = random.choice([digit0, alpha0]) str1 += str0 return str1 print(code(8)) # DU20302K
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 返回操作系统平台名称
#=========知识储备========== #进度条的效果 [# ] [## ] [### ] [#### ] #指定宽度 print('[%-15s]' %'#') print('[%-15s]' %'##') print('[%-15s]' %'###') print('[%-15s]' %'####') #打印% print('%s%%' %(100)) #第二个%号代表取消第一个%的特殊意义 #可传参来控制宽度 print('[%%-%ds]' %50) #[%-50s] print(('[%%-%ds]' %50) %'#') print(('[%%-%ds]' %50) %'##') print(('[%%-%ds]' %50) %'###') #=========实现打印进度条函数========== import sys import time def progress(percent,width=50): if percent >= 1: percent=1 show_str=('[%%-%ds]' %width) %(int(width*percent)*'#') print('\r%s %d%%' %(show_str,int(100*percent)),file=sys.stdout,flush=True,end='') #=========应用========== data_size=1025 recv_size=0 while recv_size < data_size: time.sleep(0.1) #模拟数据的传输延迟 recv_size+=1024 #每次收1024 percent=recv_size/data_size #接收的比例 progress(percent,width=70) #进度条的宽度70
re&正则表达式
用于处理字符串(查找匹配、验证)
正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法;正则就是用来描述一类事物的规则。
常用匹配模式
import re # \w与\W 字母数字下划线----取反 print(re.findall('\w', 'hello world 123')) # ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', '1', '2', '3'] print(re.findall('\W', 'hello world 123')) # [' ', ' '] # \s与\S 空白字符----取反 print(re.findall('\s', 'hello world 123')) # [' ', ' ', ' ', ' '] print(re.findall('\S', 'hello world 123')) # ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', '1', '2', '3'] # \n \t都是空,都可以被\s匹配 print(re.findall('\s', 'hello \n world \t 123')) # [' ', '\n', ' ', ' ', '\t', ' '] # \n与\t print(re.findall(r'\n', 'hello world \n123')) # ['\n'] print(re.findall(r'\t', 'hello world\t123')) # ['\t'] # \d与\D 数字----非数字 print(re.findall('\d', 'hello world 123')) # ['1', '2', '3'] print(re.findall('\D', 'hello world 123')) # ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', ' '] # \A与\Z 从字符串起始位置 print(re.findall('\Ahe', 'hello world 123')) # ['he'] print(re.findall('^h', 'hello world 123')) # ['h'] # 从字符串末尾开始匹配 print(re.findall('123$', 'hello world 123')) # ['123'] # 从字符串末尾开始匹配直到首次换行 print(re.findall('123\Z', 'hello world 123')) # ['123'] # 重复匹配:| . | * | ? | .* | .*? | + | {n,m} | # . 匹配除换行符外任意字符, print(re.findall('a.b', 'a1b a*b a b aaab')) # ['a1b', 'a*b', 'a b', 'aab'] print(re.findall('a.b', 'a\nb')) # [] # 末尾指定 . 表示任意字符 print(re.findall('a.b', 'a\nb', re.S)) # ['a\nb'] print(re.findall('a.b', 'a\nb', re.DOTALL)) # ['a\nb'] # * 星号左边的一个字符出现n次,n>=0 print(re.findall('ab*', 'abbbbbbb')) # ['abbbbbbb'] print(re.findall('ab*', 'a')) # ['a'] # ? 问号左边的一个字符出现0或1次 print(re.findall('ab?', 'a')) # ['a'] print(re.findall('ab?', 'abbb')) # ['ab'] # + 加号左边的一个字符出现n次 n>=1 print(re.findall('ab+', 'a')) # [] print(re.findall('ab+', 'abbb')) # ['abbb'] # 匹配所有包含小数在内的数字 print(re.findall('\d+\.?\d*', "asdfasdf123as1.13dfa12adsf1asdf3")) # ['123', '1.13', '12', '1', '3'] # .*默认为贪婪匹配 返回一个满足表达式的最长字符串 print(re.findall('a.*b', 'a1b22222222b')) # ['a1b22222222b'] # .*?为非贪婪匹配:推荐使用 返回多个满足表达式的字符串,注意匹配顺序是从左至右依次 print(re.findall('a.*?b', 'a1b22222222b')) # ['a1b'] # {n,m} { }左边的一个字符串出现[n,m]次 print(re.findall('ab{2}', 'abbb')) # ['abb'] 指定2次 print(re.findall('ab{2,4}', 'abbb')) # ['abb'] print(re.findall('ab{1,}', 'abbb')) # 'ab{1,}' ===> 'ab+' 第二位不指定为∞ print(re.findall('ab{0,}', 'a')) # 'ab{0,}' ===> 'ab*' # [] print(re.findall('a[1*-]b', 'a1b a*b a-b')) # ab间是[ ]内的任意一个字符 ['a1b', 'a*b', 'a-b'] print(re.findall('a[^1*-]b', 'a1b a*b a-b a=b')) # ab间没有[ ]内的任何一个字符 ['a=b'] # a b 间是0-9 的任意一个数字 短横在[ ]内两边都有字符时表示范围,按照acsii码顺序,需要表示短横时,转义或者把它放到两端 print(re.findall('a[0-9]b', 'a1b a*b a-b a=b')) # ['a1b'] print(re.findall('a[a-z]b', 'a1b a*b a-b a=b aeb')) # a b 间是a-z 的任意一个数字 print(re.findall('a[a-zA-Z]b', 'a1b a*b a-b a=b aeb aEb')) # a b 间是任意字母,大小写均可 # 转义 # python字符串中,a\\c表示a\c,但是解释器会将字符串交给C语言的re模块去执行,还会识别一次转义\c,所以抛出异常 print(re.findall(r'a\\c', 'a\c')) # r代表告诉解释器使用rawstring,即原生字符串,把我们正则内的所有符号都当普通字符处理,不要转义 print(re.findall('a\\\\c', 'a\c')) # 达到和上面一样的效果 # ():分组 print(re.findall('ab+', 'ababab123')) # ['ab', 'ab', 'ab'] print(re.findall('(ab)+123', 'ababab123')) # ['ab'],匹配到末尾的ab123中的ab print(re.findall('(?:ab)+123', 'ababab123')) # findall的结果不是匹配的全部内容,而是组内的内容,?:可以让结果为匹配的全部内容 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('compan(?:y|ies)', 'Too many companies have gone bankrupt, and the next one is my company')) # ['companies', 'company']
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'] # \n 一个换行符与 \t 一个制表符 print(re.findall(r'\n','hello egon \n123')) #['\n'] print(re.findall(r'\t','hello egon\t123')) #['\n'] # \n \t 都是空,都可以被\s匹配 print(re.findall('\s','hello \n egon \t 123')) #[' ', '\n', ' ', ' ', '\t', ' '] # \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'],\A==>^ print(re.findall('123\Z','hello egon 123')) #['he'],\Z==>$ # ^ 字符串开头与$字符串末尾 print(re.findall('^h','hello egon 123')) #['h'] print(re.findall('3$','hello egon 123')) #['3'] # 重复匹配:| . | * | ? | .* | .*? | + | {n,m} | # . 任意字符,除换行符。当指定DOTALL标记时,可以匹配包括换行符 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\nb')) #[] print(re.findall('a.b','a\nb',re.S)) #['a\nb'] print(re.findall('a.b','a\nb',re.DOTALL)) #['a\nb']同上一条意思一样 # * 0个或多个表达式 print(re.findall('ab*','bbbbbbb')) #[] print(re.findall('ab*','a')) #['a'] print(re.findall('ab*','abbbb')) #['abbbb'] # ? 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'] # .* 默认为贪婪匹配 print(re.findall('a.*b','a1b22222222b')) #['a1b22222222b'] # .*? 为非贪婪匹配:推荐使用 print(re.findall('a.*?b','a1b22222222b')) #['a1b'] # + 1个或多个表达式 print(re.findall('ab+','a')) #[] print(re.findall('ab+','abbb')) #['abbb'] # {n,m} n到m次由前面的正则表达式定义的片段,非贪婪 print(re.findall('ab{2}','abbb')) #['abb'] print(re.findall('ab{2,4}','abbb')) #['abb'] 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'] print(re.findall('a[0-9]b','a1b a*b a-b a=b')) #[]内的^代表的意思是取反,所以结果为['a=b'] print(re.findall('a[a-z]b','a1b a*b a-b a=b aeb')) #[]内的^代表的意思是取反,所以结果为['a=b'] print(re.findall('a[a-zA-Z]b','a1b a*b a-b a=b aeb aEb')) #[]内的^代表的意思是取反,所以结果为['a=b'] # \# print(re.findall('a\\c','a\c')) #对于正则来说a\\c确实可以匹配到a\c,但是在python解释器读取a\\c时,会发生转义,然后交给re去执行,所以抛出异常 print(re.findall(r'a\\c','a\c')) #r代表告诉解释器使用rawstring,即原生字符串,把我们正则内的所有符号都当普通字符处理,不要转义 print(re.findall('a\\\\c','a\c')) #同上面的意思一样,和上面的结果一样都是['a\\c'] # ():分组 print(re.findall('ab+','ababab123')) #['ab', 'ab', 'ab'] print(re.findall('(ab)+123','ababab123')) #['ab'],匹配到末尾的ab123中的ab print(re.findall('(?:ab)+123','ababab123')) #findall的结果不是匹配的全部内容,而是组内的内容,?:可以让结果为匹配的全部内容 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('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company'))
import re #1 print(re.findall('e','happy new year') ) # ['e', 'e'],返回所有满足匹配条件的结果,放在列表里 #2 print(re.search('e','happy new year').group()) # e,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 #3 print(re.match('e','happy new year')) # None,同search,不过在字符串开始处进行匹配,完全可以用search+^代替match #4 print(re.split('[ab]','abcd')) # ['', '', 'cd'],先按'a'分割得到''和'bcd',再对''和'bcd'分别按'b'分割 #5 print('===>',re.sub('a','A','happy new year')) # ===> hAppy new yeAr,不指定n,默认替换所有 print('===>',re.sub('a','A','happy new year',1)) # ===> hAppy new year print('===>',re.subn('a','A','happy new year')) # ===> ('hAppy new yeAr', 2),结果带有总共替换的个数e love print('===>',re.sub('a','A','happy new year',2)) # ===> hAppy new yeAr print('===>',re.sub('^(\w+)(.*?\s)(\w+)(.*?\s)(\w+)(.*?)$',r'\5\2\3\4\1','happy new year')) # ===> year new happy print('===>',re.subn('a','A','happy new year')) # ===> ('hAppy new yeAr', 2),结果带有总共替换的个数 #6 obj=re.compile('\d{2}') print(obj.search('abc123eeee').group()) # 12 print(obj.findall('abc123eeee')) # ['12'],重用了obj
import re msg = 'hello,python3,goodbye,python2.7! hello,python3,goodbye,python2.7!' print(re.findall('\d', msg)) # ['3', '2', '7', '3', '2', '7'] 返回所有满足匹配条件的结果,放在列表里 # 查找 print(re.search('2.7', msg)) #只到找到第一个匹配然后返回一个包含匹配信息的对象,格式为 #<_sre.SRE_Match object; span=(28, 31), match='2.7'> #该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 print(re.match('n3',msg))#从 字符串开始处进行匹配,等同于 search+^ print(re.match('he',msg))# <_sre.SRE_Match object; span=(0, 2), match='he'> # 切分 print(re.split('[\s,]',msg)) # 先以空白字符切分,再以逗号切分 # ['hello', 'python3', 'goodbye', 'python2.7!', 'hello', 'python3', 'goodbye', 'python2.7!'] # 替换 print(re.sub('p','P',msg,2)) # 字符串中前两个 'p' 替换成'P' print(re.subn('p','P',msg)) # 字符串中所有 'p' 替换成'P' + 替换次数 # 保留表达式 fmt=re.compile('\d+\.?\d*') print(fmt.findall(msg)) # ['3', '2.7', '3', '2.7'] 可以多次使用一个表达式 print(fmt.search(msg)) # <_sre.SRE_Match object; span=(12, 13), match='3'> # 组 print(re.search('(h.*?3,)(g.*?!)',msg).group())# ( )将正则表达式分成两组,group() 内不指定或指定0将会返回满足两组匹配规则的一个字符串 print(re.search('(h.*?3,)(g.*?!)',msg).group(1)) # 括号内指定n>0,返回满足2个规则的字符串中,只满足第n组规则的字符串 print(re.search('(h.*?3,)(g.*?!)',msg).group(2))
hashlib加密
1.什么是hash:hash是一种算法,其接受(x.update())传入的内容,经过运算得到一串hash值
2.hash值的特点:
I.只要传入内容一样,得到的hash值必然一样 ---------____
II.只要采用的hash算法一样,无论传入内容多大,得到的hash值长度固定----------》要用明文传输密码文件完整性校验
III.hash值不可逆,不能通过hash逆推出内容=======》把密码做出hash值,不应该在网络传输明文密码
import hashlib m=hashlib.md5() m.update('hello'.encode('utf8')) print(m.hexdigest()) # 5d41402abc4b2a76b9719d911017c592 # m=hashlib.sha256时 # 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 m.update('alvin'.encode('utf8')) print(m.hexdigest()) # 92a7e713c30abbb0319fa07da2a5c4af # m=hashlib.sha256时 #39547d6a0101921b5255322343ba482c018f4dd313f3a70942998c69862df2cc m2=hashlib.md5() m2.update('helloalvin'.encode('utf8')) print(m2.hexdigest()) # 92a7e713c30abbb0319fa07da2a5c4af
logging 用字典配置
logging 意思是记录,这个模块定义了一些函数和类,它们能够为应用程序和库提供一个灵活的事件记录系统。
根据事件的重要程度,logging设定了日志级别:
Level | Numeric value |
---|---|
CRITICAL |
50 |
ERROR |
40 |
WARNING |
30 |
INFO |
20 |
DEBUG |
10 |
NOTSET |
0 |
debug 10 任何觉得有利于在调试时更详细的了解系统运行状态的东东,比如变量的值等等,都可以输出来查看 info 20 用来反馈系统的当前状态给最终用户 warning 30 所谓警告,是这个时候进行一些修复性的工作,应该还可以把系统恢复到正常状态系统应该可以继续运行下去。 error 40 可以进行一些修复性的工作,但无法确定系统会正常的工作下去,系统在以后的某个阶段 很可能会因为当前的这个问题, 导致一个无法修复的错误(例如宕机),但也可能一直工作到停止也不出现严重问题。 critical 50 可以肯定这种错误已经无法修复,并且如果系统继续运行下去的话可以肯定必然会越来越乱。这时候采取的最好的措施不 是试图将系统状态恢复到正常,而是尽可能地保留系统有效数据并停止运行。
在生成日志时,只有达到了触发等级,才会产生日志,默认等级是30,并且输出到控制台。
日志的产生,是四个类(函数)共同作用的结果,他们分别是:
- Logger 负责生成日志,为应用程序提供一个接口
- Handler 将logger产生的日志送到指定的位置,比如文件或控制台屏幕
- Filter 提供一种更精细的划分方式,决定将哪些日志输出
-
Formatter 指定日志最终输出的格式
import logging # 修改设置 logging.basicConfig( filename="mylog.txt", filemode='at', level=20, format='%(filename)s%(levelname)s%(asctime)s%(message)s' ) # ---------------------------------------开始自定义 可以按不同的格式输出到不同文件 my_loger = logging.getLogger("my_loger") #看完回来看这句: 其实此时并没有定义过生成器, # 获取的是默认的生成器 # 设计日志级别 my_loger.setLevel(20) # 四个核心角色 # ----filter 需要用到面向对象的继承 现在不讲 # 处理器 handler0 = logging.FileHandler("日志.txt",encoding='utf8') handler1 = logging.StreamHandler() # 格式化 formater0 = logging.Formatter(fmt="%(filename)s%(levelname)s%(asctime)s%(message)s%(threadName)s") formater1 = logging.Formatter(fmt="%(levelname)s%(asctime)s%(message)s") # 将处理器绑定给生成器 add说明可以添加多个处理器 my_loger.addHandler(handler0) # Formatter 给handler handler0.setFormatter(formater0) handler1.setFormatter(formater1) logging.info("一个普通信息") logging.debug("dsdasda") logging.warning("sfffsf") logging.error("dafaf") logging.critical("safafa o ver") # ------------------------------结束,实现了打印到文件和控制台屏幕
#格式 %(name)s:Logger的名字,并非用户名,详细查看 %(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:用户输出的消息
整个过程我们没有定义logger,也生成了日志,是因为logging模块给我们提供了默认的logger,包括格式,等级... ...如果需要自己负责配置全部信息,是个复杂且重复的工作,所以logging提供了一个子模块,可以接收配置文件中配置好的信息。这样就能获得配置字典里的logger。配置字典里的内容如下,以后需要用到就可以来这里复制,加以修改。
""" logging的配置文件 """ import os # 定义三种日志输出格式 开始 # 格式名字可以改 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ '[%(levelname)s][%(message)s]' # 其中name为getlogger指定的名字 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' # 定义日志输出格式 结束 logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录 logfile_name = 'all2.log' # log文件名 # 如果不存在定义的日志目录就创建一个 if not os.path.isdir(logfile_dir): os.mkdir(logfile_dir) # log文件的全路径 logfile_path = os.path.join(logfile_dir, logfile_name) # log配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, # formatters filters handlers loggers 四个 key 名字不要改 'formatters': { 'standard': { # 这个字典的key固定 'format': standard_format }, 'simple': { 'format': simple_format }, }, 'filters': {}, 'handlers': { # 两个handler console default 名称可以更改 # 打印到终端的日志 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到屏幕 'formatter': 'simple' }, # 打印到文件的日志,收集info及以上的日志 'default': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'standard', 'filename': logfile_path, # 日志文件 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 'backupCount': 5, # 日志最大个数 到五个后 Rotating。。会删掉旧的 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, }, 'loggers': { # logging.getLogger(__name__)拿到的logger配置 # aa 生成器名 可以更改 'aa': { # handlers 不止一个 aa生成日志 交给 default 和console处理 'handlers': ['default'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)传递 和继承有关 }, 'bb': { # handlers 不止一个 aa生成日志 交给 default 和console处理 'handlers': ['console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)传递 和继承有关 }, }, }
如果这个配置文件单独存放,别的文件就可以导入
import logging.config import logging_module2 # 在logging_module2里写好了一个配置字典 logging.config.dictConfig(logging_module2.LOGGING_DIC) # 传一个字典 字典是从配置文件logging_module2.py文件里导入的 my_logger_a = logging.getLogger("aa") my_logger_b = logging.getLogger("bb") my_logger_a.error("一条测试信息---1") my_logger_b.critical(" 一条测试信息---2")
os模块
操作系统,多数是文件操作
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd os.curdir 返回当前目录: ('.') os.pardir 获取当前目录的父目录字符串名:('..') os.makedirs('dirname1/dirname2') 可生成多层递归目录 os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 os.remove() 删除一个文件 os.rename("oldname","newname") 重命名文件/目录 os.stat('path/filename') 获取文件/目录信息 os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/" os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n" os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为: os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix' os.system("bash command") 运行shell命令,直接显示 os.environ 获取系统环境变量
os.path模块
处理文件路径
我们知道python是一门跨平台的语言,每种操作系统,文件路径是截然不同的,为了使程序可以在不同平台生正确运行,python提供了该模块,使用该模块可以实现路径在不同品台下的自动转换,从而实现跨平台,今后只要涉及到文件或文件夹路径,就应该使用该模块
os.path.abspath(path) 返回path规范化的绝对路径
os.path.split(path) 将path分割成目录和文件名二元组返回
os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path) 如果path是绝对路径,返回True
os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略,即若含有多个盘符,取最后一个
os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间
os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小
主要用来处理路径,不会关心路径是否存在,只做拼接剪切转换等操作
normcase函数 在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。 >>> os.path.normcase('c:/windows\\system32\\') 'c:\\windows\\system32\\' normpath函数 规范化路径,如..和/ >>> os.path.normpath('c://windows\\System32\\../Temp/') 'c:\\windows\\Temp' >>> a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..' >>> print(os.path.normpath(a)) /Users/jieli/test1
shutil 高级文件处理模块
shutil提供了一系列高级的文件和文件夹的处理操作如复制、删除、解压缩
# copy内容 # 复制到的文件必须存在 且复制后原内容丢失 # shutil.copyfileobj(open(r"源文件路径","r"), open(r"复制到的文件路径","w")) # copy文件 # 新文件无需存在 如存在 覆蓋 # shutil.copyfile(r"源文件路径",r"复制到的文件路径") # 仅拷贝权限。内容、组、用户均不变 #目标文件必须存在 # shutil.copymode(r"源文件路径",r"复制到的文件路径") # 拷贝状态的信息,包括:mode bits, atime, mtime, flags # shutil.copystat(r"源文件路径",r"复制到的文件路径") #目标文件必须存在 # 拷贝文件和权限 # shutil.copy(r"源文件路径",r"复制到的文件路径") # 拷贝文件和状态信息 # shutil.copy2(r"源文件路径",r"复制到的文件路径")
# 复制文件夹 对文件夹进行操作大多内层使用了递归 # shutil.ignore_patterns(*patterns) # shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) # shutil.ignore_patterns(*patterns) 用于生成一个被忽略的对象 #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是忽略 # 删除文件夹 # shutil.rmtree('folder1') # 移动文件夹 不能移动文件 # shutil.move(r'原文件夹路径', r'移动到..某个文件夹里,某文件夹路径')
# 解压缩 shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的 # 创建压缩包并返回文件路径 压缩格式:zip tar # 参数名: # base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径, # 如 # data_bak=> 保存至当前路径 如: / tmp / data_bak = > 保存至 / tmp / # format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar” # root_dir: 要压缩的文件夹路径(默认当前目录) # owner: 用户,默认当前用户 # group: 组,默认当前组 # logger: 用于记录日志,通常是logging.Logger对象 # 将 /data 下的文件压缩至当前程序目录 # ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data') # 将 /data下的文件压缩至 /tmp/目录下 # ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')
压缩和解压后的返回值是路径,base_dir 压缩会将指定路径的文件夹压缩成新文件,root_dir压缩会包含从根目录到该文件之间的层级关系
subprocess模块:子进程
进程是一个正在运行的程序,子进程就是由另一个正在运行程序启动的程序。当前程序无法处理用户请求,但另一个程序可以处理
当要在python程序中执行系统指令时,就应该使用subprocess(自动化运维经常使用)
subprocess 主要用于执行系统命令,对比sys.system 区别在于可以在进程间交换数据
#测试 res = os.system("python") print(res) # res结果为执行状态
subprocess模块中的常用函数
函数 | 描述 |
---|---|
subprocess.run() | Python 3.5中新增的函数。执行指定的命令,等待命令执行完成后返回一个包含执行结果的CompletedProcess类的实例。 |
subprocess.call() | 执行指定的命令,返回命令执行状态,其功能类似于os.system(cmd)。 |
subprocess.check_call() | Python 2.5中新增的函数。 执行指定的命令,如果执行成功则返回状态码,否则抛出异常。其功能等价于subprocess.run(..., check=True)。 |
subprocess.check_output() | Python 2.7中新增的的函数。执行指定的命令,如果执行状态码为0则返回命令执行结果,否则抛出异常。 |
subprocess.getoutput(cmd) | 接收字符串格式的命令,执行命令并返回执行结果,其功能类似于os.popen(cmd).read()和commands.getoutput(cmd)。 |
subprocess.getstatusoutput(cmd) | 执行cmd命令,返回一个元组(命令执行状态, 命令执行结果输出),其功能类似于commands.getstatusoutput()。 |
import subprocess p = subprocess.Popen("ls",shell=True) #shell=True 告诉系统这是一个系统指令 而不是某个文件名 #此时效果与sys.system()没有任何区别,都是将结果输出到控制台 # 那如何与这个进程交互数据呢,这需要用到三个参数 1.stdin 表示输入交给子进程的数据 2.stdout 表示子进程返回的数据 3.stderr 表示子进程发送的错误信息 #这三个参数,的类型都是管道,(管道本质就是一个文件,可以进行读写操作),使用subprocess.PIPE来获取一个管道
一个子进程执行tasklist命令获取所有的任务信息,然后将结果交给另一个进程进行查找,另一个子进程执行findstr 查找某个任务信息 p1 = subprocess.Popen("tasklist",shell=True,stdout=subprocess.PIPE) p2 = subprocess.Popen("findstr smss",shell=True,stdin=p1.stdout,stdout=subprocess.PIPE) print(p2.stdout.read())
configparser模块
解析配置文件,配置文件中只能有分区选项
作为配置信息的数据,应满足:I.数据值不是固定的 II.可由用户来指定的
配置文件中只允许出现两种类型的数据:I.section分区 方括号中是分区的名称 II.option选项 名称=值
需注意:
- I.不能出现重复的分区名
- II.同一个分区下不能有相同的选项名
- III.值可以是任何类型,且字符串不去要加引号
import configparser #获取解析器对象 config=configparser.ConfigParser() # 读取某个配置文件 config.read('a.cfg') #查看所有的标题 res=config.sections() #['section1', 'section2'] print(res) #查看标题section1下所有key=value的key options=config.options('section1') print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary'] #查看标题section1下所有key=value的(key,value)格式 item_list=config.items('section1') print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')] #查看标题section1下user的值=>字符串格式 val=config.get('section1','user') print(val) #egon #由于使用前需要进行转换,所以模块封装了转换类型的功能,只需要调用对应的函数即可,如下: val1=config.getint('section1','age') val2=config.getboolean('section1','is_admin') val3=config.getfloat('section1','salary')
import configparser config=configparser.ConfigParser() config.read('a.cfg',encoding='utf-8') #删除整个标题section2 config.remove_section('section2') #删除标题section1下的某个k1和k2 config.remove_option('section1','k1') config.remove_option('section1','k2') #判断是否存在某个标题 print(config.has_section('section1')) #判断标题section1下是否有user print(config.has_option('section1','')) #添加一个标题 config.add_section('jack') #在标题egon下添加name=egon,age=18的配置 config.set('jack','name','egon') # 如果已存则覆盖原来的值 #config.set('jack','age',18) #报错,必须是字符串 #最后将修改的内容写入文件,完成最终的修改 config.write(open('a.cfg','w'))
import configparser config = configparser.ConfigParser() config.add_section("setion1") config.set("setion1","name","zhangsn") with open("test.config","w") as f: config.write(f)
configparser 用于解析配置文件,虽然可以修改和,创建,配置文件,但是并不常用,解析才是其核心功能!
xml模块
可扩展标记语言,可自定义文档结构,定义电子文档结构和描述的语言,可以用来标记数据、定义数据类型
学习重点:如何读取文档,并找到需要的标签
用户可以对自己的标记语言进行定义和扩展,由W3C(万维网标准组织)推出,几乎所有的编程语言都支持该格式。标记翻译为标签,标签指的是某种特殊符号,简单的是XML就是用标签来定义文档结构
xml文档格式
<person name="jack">hello i am a person</person> 一个完整的标签分为三个部分 标签名(tagname): person 属性(attribute): name(值为jack) 文本(text): hello i am a person 其中属性和文本都是可选的,所以可以定义一个空标签 <person></person>
格式:
- I、任何的起始标签都必须有一个结束标签。
- II、可以采用另一种简化语法,可以在一个标签中同时表示起始和结束标签。这种语法是在大于符号之前紧跟一个斜线(/),例如。XML解析器会将其翻译成。
- III、标签必须按顺序进行嵌套,所以结束标签必须按镜像顺序匹配起始标签,这好比是将起始和结束标签看作是数学中的左右括号:在没有关闭所有的内部括号之前,是不能关闭外面的括号的。
- IV、所有的属性都必须有值。
- V、所有的特性都必须在值的周围加上双引号。
- VI、最外层必须有且只能有一个标签,称为根标签
2.与json对比
json是JavaScript语言的对象表示法,仅支持js中的数据类型,(虽然大多数情况下是足够使用的),之所以出现是因为在开发中,通常都需要后台像前台传输数据,所以传输前台能看懂的数据格式,json就是这样一种数据格式,可以轻松的被js语言解析,使用场景多为前后台交互
xml支持的数据类型理论上是不受限制的,因为可以完全自定义标签的结构和含义,使用场景也非常广泛,不局限于前后台的数据交互,在一些语言中还经常作为配置文件来使用。HTML也属于xml
3.使用xml模块解析
<?xml version="1.0"?> <data> <country name="Liechtenstein"> <rank updated="yes">2</rank> <year>2008</year> <gdppc>141100</gdppc> <neighbor name="Austria" direction="E"/> <neighbor name="Switzerland" direction="W"/> </country> <country name="Singapore"> <rank updated="yes">5</rank> <year>2011</year> <gdppc>59900</gdppc> <neighbor name="Malaysia" direction="N"/> </country> <country name="Panama"> <rank updated="yes">69</rank> <year>2011</year> <gdppc>13600</gdppc> <neighbor name="Costa Rica" direction="W"/> <neighbor name="Colombia" direction="E"/> </country> </data>
import xml.etree.ElementTree as ET tree = ET.parse("xmltest.xml") root = tree.getroot() print(root.tag) #遍历xml文档 for child in root: print('========>',child.tag,child.attrib,child.attrib['name']) for i in child: print(i.tag,i.attrib,i.text) #只遍历year 节点 for node in root.iter('year'): print(node.tag,node.text) #--------------------------------------- import xml.etree.ElementTree as ET tree = ET.parse("xmltest.xml") root = tree.getroot() #修改 for node in root.iter('year'): new_year=int(node.text)+1 node.text=str(new_year) node.set('updated','yes') node.set('version','1.0') tree.write('test.xml') #删除node for country in root.findall('country'): rank = int(country.find('rank').text) if rank > 50: root.remove(country) tree.write('output.xml')
1.三个用于查找标签函数 iter("标签名") #全文查找 find("标签名") #查找子节点匹配的第一个 findall("标签名") #查找字节点匹配的所有 2.访问标签的内容 element.tag 获取标签名 element.attrib 获取属性 element.text 获取文本 3.修改文档内容 elment.tag = "标签名" element.text = "文本" element.set("属性名","属性值") 4.删除节点 root.remove(标签对象) 5.添加子标签 #创建标签对象 year2=ET.Element('year2') # 指定名称 year2.text='新年' year2.attrib={'update':'yes'} #添加 country.append(year2) #往country节点下添加子节点 删除添加修改后都需要调用write写入到文件 tree.write("文件名"),#注意文档对象才能执行写入操作
import xml.etree.ElementTree as ET new_xml = ET.Element("namelist") name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"}) age = ET.SubElement(name,"age",attrib={"checked":"no"}) sex = ET.SubElement(name,"sex") sex.text = 'man' name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"}) age = ET.SubElement(name2,"age") age.text = '19' et = ET.ElementTree(new_xml) #生成文档对象 et.write("test.xml", encoding="utf-8",xml_declaration=True) ET.dump(new_xml) #打印生成的格式
xml的解析比起json而言非常复杂 因为其扩展性远比json高,在java中常作为配置文件,当你在前后台进行数据交互时,优先是用json格式