pyday06

一、Python常用模块

 1.正则表达式与re模块:

  1)什么是正则:

  正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。

  2)常用匹配模式:

 

import re

print(re.findall('\w','abc123d_ef * | - ='))
print(re.findall('\W','abc123d_ef * | - ='))
print(re.findall('\s','abc12\n3d\t_ef * | - ='))
print(re.findall('\S','abc12\n3d\t_ef * | - ='))
print(re.findall('\d','abc12\n3d\t_ef * | - ='))
print(re.findall('\D','abc12\n3d\t_ef * | - ='))

# 运行结果:
['a', 'b', 'c', '1', '2', '3', 'd', '_', 'e', 'f']
[' ', '*', ' ', '|', ' ', '-', ' ', '=']
['\n', '\t', ' ', ' ', ' ', ' ']
['a', 'b', 'c', '1', '2', '3', 'd', '_', 'e', 'f', '*', '|', '-', '=']
['1', '2', '3']
['a', 'b', 'c', '\n', 'd', '\t', '_', 'e', 'f', ' ', '*', ' ', '|', ' ', '-', ' ', '=']
\w \W \s \S \d \D
import re
print(re.findall('\n','hello elaine \n123'))
print(re.findall('\t','hello elaine \t123'))
print(re.findall('^h','hello elaine \n123'))
print(re.findall('3$','hello elaine \n123'))

运行结果:
['\n']
['\t']
['h']
['3']
\n,\t,^,$
#.
print(re.findall('a.b','a1b')) #['a1b']
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']同上一条意思一样

#*
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}
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*'
重复匹配:. ,*, ?, .*,.*?,+,{n,m}
import re

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')) 
print(re.findall('a[a-z]b','a1b a*b a-b a=b aeb')) 
print(re.findall('a[a-zA-Z]b','a1b a*b a-b a=b aeb aEb'))

运行结果:
['a1b', 'a*b', 'a-b']
['a=b']
['a1b']
['aeb']
['aeb', 'aEb'] 
[]
#\# 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']
关于\转译符和r
import re

print(re.findall('ab+','ababab123')) #['ab', 'ab', 'ab']
print(re.findall('(ab)+123','ababab123')) #['ab'],匹配到末尾的ab123中的ab
print(re.findall('(?:ab)+123','ababab123')) #findall的结果不是匹配的全部内容,而是组内的内容,?:可以让结果为匹配的全部内容

运行结果:
['ab', 'ab', 'ab']
['ab']
['ababab123']
()分组
import re
print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company'))

运行结果:
['companies', 'company']

  3)re模块提供方法:

import re

print(re.findall('e','elaine make cake'))
print(re.search('e','elaine make cake')) #e,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
print(re.search('e','elaine make cake').group())
print(re.match('e','dylan elaine make cake')) # 在字符串开始匹配e,没有返回None
print(re.search('^e','dylan elaine make cake')) # 和match效果一样 

运行结果:
['e', 'e', 'e', 'e']
<_sre.SRE_Match object; span=(0, 1), match='e'>
e
None
None
search,match
import re
print(re.split('[bd]','abcdef')) # 先按b分割得到'a'和'cdef',再按d分割得到'c'和'ef'

print(re.sub('e','E','elaine make cake')) # 不指定n,默认替换所有
print(re.sub('e','E','elaine make cake',1))
print(re.sub('e','E','elaine make cake',2))
print(re.sub('^(\w+)(.*?\s)(\w+)(.*?\s)(\w+)(.*?)$',r'\5\2\3\4\1','elaine make cake')) # 将elaine和cake替换位置
print(re.subn('e','E','elaine make cake')) # 结果带有总共替换的个数

运行结果:
['a', 'c', 'ef']
ElainE makE cakE
Elaine make cake
ElainE make cake
cake make elaine
('ElainE makE cakE', 4)
split,sub,subn

  4)补充:

  在线调试工具:tool.oschina.net/regex/#

import re
s = '1-12*(60+(-40.35/5.3+1.2)-(-4*3))'
print(re.findall('\-?\d+\.?\d*',s))    # 找到所有数
print(re.findall('\-?\d+\.+\d+',s))    # 找到所有小数
print(re.findall('\-?\d+\.+\d+|(\-?\d+)',s))    # 找到所有整数

运行结果:
['1', '-12', '60', '-40.35', '5.3', '1.2', '-4', '3']
['-40.35', '5.3', '1.2']
['1', '-12', '60', '-40', '35', '5', '3', '1', '2', '-4', '3']

 2.time模块:

在Python中,通常有这几种方式来表示时间:

  • 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
  • 格式化的时间字符串(Format String)
  • 结构化的时间(struct_time):struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)
import time
#--------------------------三种形式的时间
print(time.time()) 
print(time.strftime("%Y-%m-%d %X")) 

print(time.localtime()) #本地时区的struct_time
print(time.gmtime())    #UTC时区的struct_time

# 运行结果:
1496641468.292337
2017-06-05 13:44:28
time.struct_time(tm_year=2017, tm_mon=6, tm_mday=5, tm_hour=13, tm_min=44, tm_sec=28, tm_wday=0, tm_yday=156, tm_isdst=0)
time.struct_time(tm_year=2017, tm_mon=6, tm_mday=5, tm_hour=5, tm_min=44, tm_sec=28, tm_wday=0, tm_yday=156, tm_isdst=0)

  其中计算机认识的时间只能是'时间戳'格式,而程序员可处理的或者说人类能看懂的时间有: '格式化的时间字符串','结构化的时间' ,于是有了下图的转换关系:

 

# localtime([secs])
# 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
print(time.localtime(time.time()))
# gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。
# mktime(t) : 将一个struct_time转化为时间戳。
print(time.mktime(time.localtime()))

运行结果:
time.struct_time(tm_year=2017, tm_mon=6, tm_mday=5, tm_hour=13, tm_min=53, tm_sec=39, tm_wday=0, tm_yday=156, tm_isdst=0)
1496642019.0
timestamp<==>struct_time
'''
strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和
time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个
元素越界,ValueError的错误将会被抛出。
'''
print(time.strftime("%Y-%m-%d %X", time.localtime()))    #"%Y-%m-%d %X"为固定格式,中间的-可以任意指定
# time.strptime(string[, format]):
# 把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作
print(time.strptime("2017-06-05 13:59:31","%Y-%m-%d %X"))
#在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。

运行结果:
2017-06-05 14:02:15
time.struct_time(tm_year=2017, tm_mon=6, tm_mday=5, tm_hour=13, tm_min=59, tm_sec=31, tm_wday=0, tm_yday=156, tm_isdst=-1)
Format String<===>struct_time

 

#--------------------------按图2转换时间
# asctime([t]) : 把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993'。
# 如果没有参数,将会将time.localtime()作为参数传入。
print(time.asctime())#Sun Sep 11 00:43:43 2016

# ctime([secs]) : 把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为
# None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。
print(time.ctime())  # Sun Sep 11 00:46:38 2016
print(time.ctime(time.time()))  # Sun Sep 11 00:46:38 2016
struct_time===> "%a %b %d %H:%M:%S %Y"<===timestamp
#--------------------------其他用法
# sleep(secs)
# 线程推迟指定的时间运行,单位为秒。

3.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) #打乱item的顺序,相当于"洗牌"
print(item)

  应用:

    生成随机验证码:

import random

def auth_code(n):
    code = ''
    for i in range(n):
        num = random.randint(0,9)
        alf = chr(random.randint(65,90))
        add = random.choice([num,alf])
        code += str(add)
    return code
print(auth_code(7))

4.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模块
import os
# os.path.abspath(path)  返回path规范化的绝对路径
print(os.path.abspath('D:\python\python3'))
# os.path.split(path)  将path分割成目录和文件名二元组返回
print(os.path.split('D:\python\python3'))
# os.path.dirname(path)  返回path的目录。其实就是os.path.split(path)的第一个元素
print(os.path.dirname('D:\python\python3'))
# os.path.basename(path)  返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
print(os.path.basename('D:\python\python3'))
# os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
print(os.path.exists('D:\python\python3'))
# os.path.isabs(path)  如果path是绝对路径,返回True
print(os.path.isabs('D:\python\python3'))
# os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
print(os.path.isfile('D:\python\python3'))
# os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
print(os.path.isdir('D:\python\python3'))
# os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
print(os.path.join('D:\python\python3','test.py'))
print(os.path.join('test.py','D:\python\python3','test'))
# os.path.getatime(path)  返回path所指向的文件或者目录的最后存取时间
print(os.path.getatime('D:\python\python3'))
# os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间
print(os.path.getmtime('D:\python\python3'))
# os.path.getsize(path) 返回path的大小
print(os.path.getsize('D:\python\python3'))

运行结果:
D:\python\python3
('D:\\python', 'python3')
D:\python
python3
True
True
False
True
D:\python\python3\test.py
D:\python\python3\test
1496627936.308156
1496627936.308156
4096
os.path
# 在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
print(os.path.normcase('c:/windows\\system32\\'))
# os.path.normpath 规范化路径,如..和/
print(os.path.normpath('c://windows\\System32\\../Temp/'))

运行结果:
c:\windows\system32\
c:\windows\Temp

  根据os.pardir和用来规范路径的os.path.normpath可以用来将开发的软件包的根目录导入环境变量sys.path,进而可以任意导入软件包里的模块:

# start_test.py
import sys
import os

dir = os.path.normpath(os.path.join(os.path.abspath(__file__), # 当前文件的绝对路径
                              os.pardir,    # 上一级目录
                              os.pardir,))
sys.path.insert(0,dir)

print(sys.path)

运行结果:
['D:\\python\\python3', 'D:\\python\\python3\\s17day06_code', 'D:\\python\\python3', 'D:\\python\\python\\monitor_test', 'C:\\Windows\\system32\\python34.zip', 'C:\\Python34\\DLLs', 'C:\\Python34\\lib', 'C:\\Python34', 'C:\\Python34\\lib\\site-packages', 'C:\\Python34\\lib\\site-packages\\win32', 'C:\\Python34\\lib\\site-packages\\win32\\lib', 'C:\\Python34\\lib\\site-packages\\Pythonwin']

5.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       返回操作系统平台名称

  模拟进度条:

import sys,time

for i in range(50):
    sys.stdout.write('%s\r' %('#'*i))    # \r 为不换行,跳到行首   
    sys.stdout.flush()
    time.sleep(0.1)

'''
注意:在pycharm中执行无效,请到命令行中以脚本的方式执行
'''

6.shutil模块:

  高级的 文件、文件夹、压缩包 处理模块

  shutil.copyfileobj(fsrc, fdst[, length])
  将文件内容拷贝到另一个文件中

import shutil  
shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))

   shutil.copyfile(src, dst)

  拷贝文件

shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在

   shutil.copymode(src, dst)

  仅拷贝权限。内容、组、用户均不变

shutil.copymode('f1.log', 'f2.log') #目标文件必须存在

   shutil.copystat(src, dst)

  仅拷贝状态的信息,包括:mode bits, atime, mtime, flags

shutil.copystat('f1.log', 'f2.log') #目标文件必须存在

  shutil.copy(src, dst)
  拷贝文件和权限

import shutil
shutil.copy('f1.log', 'f2.log')

  shutil.copy2(src, dst)

  拷贝文件和状态信息

import shutil
shutil.copy2('f1.log', 'f2.log')

  shutil.copytree(src, dst, symlinks=False, ignore=None)
  递归的去拷贝文件夹

import shutil
shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) 
#目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除 
import shutil

shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))

'''
通常的拷贝都把软连接拷贝成硬链接,即对待软连接来说,创建新的文件
'''

  shutil.rmtree(path[, ignore_errors[, onerror]])
  递归的去删除文件

import shutil  
shutil.rmtree('folder1')

  shutil.move(src, dst)
  递归的去移动文件,它类似mv命令,其实就是重命名

import shutil
shutil.move('folder1', 'folder3')

  shutil.make_archive(base_name, format,...)

  • base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径:

    如: data_bak =>保存至当前路径

    如:/tmp/data_bak =>保存至/tmp/

  • format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
  • root_dir: 要压缩的文件夹路径(默认当前目录)
  • owner: 用户,默认当前用户
  • group: 组,默认当前组
  • logger: 用于记录日志,通常是logging.Logger对象
#将 /data 下的文件打包放置当前程序目录
import shutil
ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data')
  
  
#将 /data下的文件打包放置 /tmp/目录
import shutil
ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')

  shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的:

import zipfile

# 压缩
z = zipfile.ZipFile('laxi.zip', 'w')
z.write('a.log')
z.write('data.data')
z.close()

# 解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall(path='.')
z.close()

zipfile压缩解压缩
zipfile
import tarfile

# 压缩
>>> t=tarfile.open('/tmp/egon.tar','w')
>>> t.add('/test1/a.py',arcname='a.bak')
>>> t.add('/test1/b.py',arcname='b.bak')
>>> t.close()


# 解压
>>> t=tarfile.open('/tmp/egon.tar','r')
>>> t.extractall('/egon')
>>> t.close()

tarfile压缩解压缩
tarfile

7.json,pickle模块:

  之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值。

import json
x="[null,true,false,1]"
# print(eval(x)) #报错,无法解析null类型,而json就可以
print(json.loads(x)) 

运行结果:
[None, True, False, 1]

为什么要序列化?

1)持久保存状态:

  需知一个软件/程序的执行就在处理一系列状态的变化,在编程语言中,'状态'会以各种各样有结构的数据类型(也可简单的理解为变量)的形式被保存在内存中。

  内存是无法永久保存数据的,当程序运行了一段时间,我们断电或者重启程序,内存中关于这个程序的之前一段时间的数据(有结构)都被清空了。

  在断电或重启程序之前将程序当前内存中所有的数据都保存下来(保存到文件中),以便于下次程序执行能够从文件中载入之前的数据,然后继续执行,这就是序列化。

  具体的来说,你玩使命召唤闯到了第13关,你保存游戏状态,关机走人,下次再玩,还能从上次的位置开始继续闯关。或如,虚拟机状态的挂起等。

2)跨平台数据交互:

  序列化之后,不仅可以把序列化后的内容写入磁盘,还可以通过网络传输到别的机器上,如果收发的双方约定好实用一种序列化的格式,那么便打破了平台/语言差异化带来的限制,实现了跨平台数据交互。

  反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。

json:

  如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。

  JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:

 

   对一段python数据类型我们可以使用json方式对其进行序列化和反序列化:

# 序列化
import json

dic = {
    'name':'elaine',
    'age':18,
    'gender':'girl'
}

res = json.dumps(dic)

with open('a.json','w') as f :
    f.write(res)

#反序列化:
with open('a.json','r') as f :
    data = f.read()

res = json.loads(data)
print(res,type(res))

# 运行结果:
{'gender': 'girl', 'age': 18, 'name': 'elaine'} <class 'dict'>


# 也可以用简便方式:
# 序列化:
dic = {
    'name':'elaine',
    'age':18,
    'gender':'girl'
}
json.dump(dic,open('b.json','w'))

# 反序列化:
res = json.load(open('b.json','r'))
print(res,type(res))

#运行结果:
{'name': 'elaine', 'age': 18, 'gender': 'girl'} <class 'dict'>

pickle:

  同样,对一段python数据类型我们也可以使用pickle方式对其进行序列化和反序列化:

# 序列化:
import pickle
dic = {
    'name':'elaine',
    'age':18,
    'gender':'girl'
}
pickle.dump(dic,open('a.plk','wb'))    #使用二进制方式打开

#反序列化:
res = pickle.load(open('a.plk','rb'))
print(res,type(res))

运行结果:
{'name': 'elaine', 'gender': 'girl', 'age': 18} <class 'dict'>

  函数作为python的对象,是否可以被pickle序列化呢?

import pickle
def func():
    print('from func')

pickle.dump(func,open('func.plk','wb'))

  序列化没问题,我们进行反序列化:

import pickle
pickle.load(open('func.plk','rb'))

运行结果:
Traceback (most recent call last):
  File "D:/python/python3/s17day06_code/pickle模块.py", line 25, in <module>
    pickle.load(open('func.plk','rb'))
AttributeError: Can't get attribute 'func' on <module '__main__' from 'D:/python/python3/s17day06_code/pickle模块.py'>

  对于函数来说,pickle序列化的只是其内存地址(函数名),而没有这个内存地址对应的值,而对于普通的数据类型(字典,列表,元组)序列化的是其值的本身,反序列化会在内存中重新定义这个数据类型。 

 8.shelve模块:

  shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型

import shelve

with shelve.open('test') as s:
    s['user_info1'] = {'name':'elaine','age':18}
    s['user_info2'] = {'name': 'dylan', 'age': 29}
    print(s['user_info1']['name'])

运行结果:
elaine

9.xml模块:

  xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,至今很多传统公司如金融行业的很多系统的接口还主要是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>

xml数据
xml

 

 

import xml.etree.ElementTree as ET

tree = ET.parse('xml_test')    # 导入xml文件
root = tree.getroot()    # 生成根节点

print(root.tag)    # 根节点标签名
print(root.iter('year')) #全文搜索
print(root.find('country')) #只在root的子节点找,只找一个
print(root.findall('country')) #只在root的子节点找,找所有

for i in root:    # 遍历xml文档,得到root下子节点对象
    print(i.tag,':%s'%i.attrib['name'])
    for n in i :
        print('====> tag:%s attrib:%s text:%s'%(n.tag,n.attrib,n.text))

for i in root.iter('year'):   # 遍历找到的year节点
    print('tag:%s text:%s'%(i.tag,i.text))


运行结果:
data    # 根节点的tag
<_elementtree._element_iterator object at 0x0000000000828EA0>    # 搜索到所有year节点的对象
<Element 'country' at 0x0000000000C2CD68>    # 根下第一个找到的country节点对象
[<Element 'country' at 0x0000000000C2CD68>, <Element 'country' at 0x0000000000C40778>, <Element 'country' at 0x0000000000C40908>]    # 根节点下找到的所有的country节点对象
country :Liechtenstein
====> tag:rank attrib:{'updated': 'yes'} text:2
====> tag:year attrib:{} text:2008
====> tag:gdppc attrib:{} text:141100
====> tag:neighbor attrib:{'name': 'Austria', 'direction': 'E'} text:None
====> tag:neighbor attrib:{'name': 'Switzerland', 'direction': 'W'} text:None
country :Singapore
====> tag:rank attrib:{'updated': 'yes'} text:5
====> tag:year attrib:{} text:2011
====> tag:gdppc attrib:{} text:59900
====> tag:neighbor attrib:{'name': 'Malaysia', 'direction': 'N'} text:None
country :Panama
====> tag:rank attrib:{'updated': 'yes'} text:69
====> tag:year attrib:{} text:2011
====> tag:gdppc attrib:{} text:13600
====> tag:neighbor attrib:{'name': 'Costa Rica', 'direction': 'W'} text:None
====> tag:neighbor attrib:{'name': 'Colombia', 'direction': 'E'} text:None
tag:year text:2008
tag:year text:2011
tag:year text:2011
# 修改所有year节点
for node in root.iter('year'):
    new_year = int(node.text) + 1
    node.text = str(new_year)
    node.set('updated', 'yes')    # 设置updated属性
    node.set('version', '1.0')    # 设置version属性
tree.write('test.xml')    # 写入test.xml

 

import xml.etree.ElementTree as ET

tree = ET.parse('xml_test')    # 导入xml文件
root = tree.getroot()    # 生成根节点

# 删除year.text大于2010的year节点
for country_node in root:
    year_node = country_node.find('year')
    if int(year_node.text) > 2010:
        country_node.remove(year_node)    # 因为year节点在country下,所以必须从country节点下删除
tree.write('test02.xml')

 

# 在country添加year2节点
import xml.etree.ElementTree as ET
tree = ET.parse("a.xml")
root=tree.getroot()

for country_node in root :
    for year_node in country_node.findall('year'):
        if int(year_node.text) > 2000:
            year2 = ET.Element('year2')
            year2.text = '千禧年'
            year2.attrib = {'update':'yes'}  #或者year2.set('update','yes')
            country_node.append(year2)   #往country节点下添加子节点
        tree.write('test03.xml')

 

#创建自定义xml
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 = '33'
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) #打印生成的格式

 

 

 

10.hashlib模块:

  hash:一种算法 ,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512,MD5 算法
  三个特点:
  1.内容相同则hash运算结果相同,内容稍微改变则hash值则变
  2.不可逆推
  3.相同算法:无论校验多长的数据,得到的哈希值长度固定。

 

import hashlib

m = hashlib.md5()
m.update('hello'.encode('utf-8'))
print(m.hexdigest())
# 5d41402abc4b2a76b9719d911017c592

m.update('elaine'.encode('utf-8'))
print(m.hexdigest())
# b24d57a2292ed7bec0c15e3c7ebe6f29

m2 = hashlib.md5()
m2.update('helloelaine'.encode('utf-8'))
print(m2.hexdigest())
# b24d57a2292ed7bec0c15e3c7ebe6f29

'''
把一段很长的数据update多次,与一次update这段长数据,得到的结果一样 ,update多次为校验大文件提供了可能。
'''

 

 

m = hashlib.md5()
with open(r'E:\war3\YDWE1.27.6正式版\backups\0.w3x','rb') as f:
    for line in f:
        m.update(line)
    md5_num = m.hexdigest()

print(md5_num)

m2 = hashlib.md5()
with open(r'E:\war3\YDWE1.27.6正式版\backups\0.w3x','rb') as f:
    data = f.read()
    m2.update(data)
    md5_num = m2.hexdigest()

print(md5_num)

运行结果:
a976202f4ad8e6fa9bb9992fe71cc7c7
a976202f4ad8e6fa9bb9992fe71cc7c7

  以上加密算法虽然依然非常厉害,但时候存在缺陷,即:通过撞库可以反解。所以,有必要对加密算法中添加自定义key再来做加密。

import hashlib
 
# ######## 256 ########
 
hash = hashlib.sha256('898oaFs09f'.encode('utf8'))
hash.update('alvin'.encode('utf8'))
print (hash.hexdigest())#e79e68f070cdedcfe63eaf1a2e92c83b4cfb1b5c6bc452d214c1b7e77cdfd1c7
import hashlib
passwds=[
    'elaine123',
    'elaine456',
    'elaine789',
    'elaine234',
    'elaine345',
    'elaine6789',
    ]
def make_passwd_dic(passwds):
    dic={}
    for passwd in passwds:
        m=hashlib.md5()
        m.update(passwd.encode('utf-8'))
        dic[passwd]=m.hexdigest()
    return dic

def break_code(cryptograph,passwd_dic):
    for k,v in passwd_dic.items():
        if v == cryptograph:
            print('密码是===>\033[46m%s\033[0m' %k)

cryptograph='92dd15c5552dc0df831ed2eddcbea0c5'
break_code(cryptograph,make_passwd_dic(passwds))

运行结果:
密码是===>elaine789
模拟撞库破解密码

 

 

 

11.subprocess模块:

   os.system()模块可以直接执行命令将其打印到终端,但是往往我们想通过一种方式在服务端执行命令,需要通过另外的方式输出到其它终端上,我们可以通过subprocess实现:

import subprocess

res = subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE)
# 使用stdout接收存储执行的命令正确的结果
# print(res.stdout.read())    # 输出为bytes格式,需要decode为当前系统的编码格式
print(res.stdout.read().decode('gbk'))

 

import subprocess

res = subprocess.Popen('dir_test',shell=True,stderr=subprocess.PIPE,stdout=subprocess.PIPE)
# 使用stderr来接收存储错误的命令结果
# print(res.stdout.read())
print(res.stdout.read().decode('gbk'))
print(res.stderr.read().decode('gbk'))

运行结果:
'dir_test' 不是内部或外部命令,也不是可运行的程序
或批处理文件。

 

# 模拟一个windows下的dir | findstr test* 类似linux下的ls /root |grep txt$
import subprocess

res1 = subprocess.Popen('dir D:\python\py17\code\py17day06',shell=True,stdout=subprocess.PIPE)
# 将第一条命令的stdout 以stdin的方式传给第二条命令
res = subprocess.Popen("findstr test*",shell=True,stdin=res1.stdout,stdout=subprocess.PIPE)

print(res.stdout.read().decode('gbk'))


运行结果:
2017/06/04  15:42               462 json_test.py
2017/06/04  16:03               282 pickle_test01.py
2017/06/04  13:31               522 test.py
2017/06/04  15:40                47 test01.json

 

12.logging模块:

用于便捷记录日志且线程安全的模块

注:

1)如果不指定filename,则默认打印到终端
2)指定日志级别:
    指定方式:
        1:level=10
        2:level=logging.ERROR
    日志级别种类:
        CRITICAL = 50
        FATAL = CRITICAL
        ERROR = 40
        WARNING = 30
        WARN = WARNING
        INFO = 20
        DEBUG = 10
        NOTSET = 0
3)指定日志级别为ERROR,则只有ERROR及其以上级别的日志会被打印
import logging

logging.basicConfig(filename='test.log',    # 将日志写入test.log
                    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s', # 指定日志格式
                    datefmt='%Y-%m-%d %H:%M:%S %p', # 指定日期时间格式
                    level=10    # 指定日志级别,如果level=40,只有logging.error和logging.critical会被打印
                    )    

logging.debug('debug')
logging.info('info')
logging.warning('warning')
logging.error('error')
logging.critical('critical')


运行后写入test.log结果:
2017-06-06 10:50:28 AM - root - DEBUG -logging_test:  debug
2017-06-06 10:50:28 AM - root - INFO -logging_test: info
2017-06-06 10:50:28 AM - root - WARNING -logging_test: warning
2017-06-06 10:50:28 AM - root - ERROR -logging_test: error
2017-06-06 10:50:28 AM - root - CRITICAL -logging_test: critical

可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有
  filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
  filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
  format:指定handler使用的日志显示格式。 
  datefmt:指定日期时间格式。 
  level:设置rootlogger(后边会讲解具体概念)的日志级别 
  stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。http://blog.csdn.net/zyz511919766/article/details/25136485/

日志格式:

 

%(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

用户输出的消息

 

 

13.configparser模块:

 

[section1]
k1 = v1
k2:v2
user=elaine
age=18
is_admin=true
salary=31

[section2]
k1 = v1
配置文件

基本用法:

  读取:

import configparser

config = configparser.ConfigParser()
config.read('config_test')
#查看所有的标题
sec = config.sections()
print(sec)
#查看标题section1下所有key=value的key
opt = config.options('section1')
print(opt)
#查看标题section1下所有key=value的(key,value)格式
items = config.items('section1')
print(items)
#查看标题section1下user的值=>字符串格式
get_value = config.get('section1','user')
print(get_value)
#查看标题section1下age的值=>整数格式
val1=config.getint('section1','age')
print(val1) #18
#查看标题section1下is_admin的值=>布尔值格式
val2=config.getboolean('section1','is_admin')
print(val2) #True
#查看标题section1下salary的值=>浮点型格式
val3=config.getfloat('section1','salary')
print(val3) #31.0

运行结果:
['section1', 'section2']
['k1', 'k2', 'user', 'age', 'is_admin', 'salary']
[('k1', 'v1'), ('k2', 'v2'), ('user', 'elaine'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')]
elaine
18
True
31.0

  改写,删除,添加:

import configparser

config = configparser.ConfigParser()
config.read('config_test')

#  设置sections1下的user为dylan
val = config.set('section1','user','dylan')

#删除整个标题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','user'))


#添加一个标题
config.add_section('section3')

#在标题section3下添加user=dylan,age=29的配置
config.set('section3','user','dylan')
config.set('section3','age',29)  # 报错,必须是字符串


#最后将修改的内容写入文件,完成最终的修改
config.write(open('a.cfg','w'))

 

 

 

 

二、软件开发规范

 

三、面向对象程序设计

posted @ 2017-06-04 08:41  Dylan_Wu  阅读(263)  评论(0)    收藏  举报