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)) #时间替换
datetime模块

 

 

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)
eg
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
用random写一个可以生成指定位数验证码的功能,验证码由大写字母和数字组成。

 

 

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))
re模块功能

 

 

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设定了日志级别:

 

LevelNumeric 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:用户输出的消息
formatter格式

 

整个过程我们没有定义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模块相关操作

 

 

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的大小
os.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
normcase、normpath

 

 

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')
解析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文档

 

 

xml的解析比起json而言非常复杂 因为其扩展性远比json高,在java中常作为配置文件,当你在前后台进行数据交互时,优先是用json格式

posted @ 2019-05-21 20:46  呔!妖精。。。  阅读(98)  评论(0编辑  收藏  举报