目录
一、基础概念
1、模块定义
2、包的定义
3、导入包的本质
4、导入模块的本质
5、导入方法
6、import的本质
7、导入优化
8、模块分类
9、标准库介绍
1、time与datetime
2、random模块
3、os模块
4、sys模块
5、shutil模块
6、shelve模块
7、XML模块
8、Pyyaml模块
9、configParser模块
10、hashlib模块
11、re模块
12、collections模块
13、subprocess模块
14、logging模块
10、二分法
11、冒泡排序
12、时间复杂度
13、深拷贝
一、基础概念:
1、模块定义
本质就是.py结尾的python文件(文件名:test.py 对应模块名: test),用来从逻辑上组织python代码(变量、函数、类、逻辑)
2、包的定义
用来从逻辑上组织模块的,本质就是一个目录(必须带有一个名字叫__init__.py的文件)
3、导入包的本质
执行包目录下所在的__init__.py文件
4、导入模块的本质
将该模块的python文件在导入的程序中通过解释器去解释一遍
5、导入方法
1、import module_name
2、import module_name1,module_name2.....
3、from module_name import func_name (as func1_name) #可以对导入的函数起别名,为了避免与本文件的函数重名导致功能没法实现
6、import的本质
导入模块本质就是找到这个文件,并且把python文件解释一遍,其中import test 表示 test=‘test.py all code’ 把该test.py文件全部解释一遍,而from test import m m=‘test.py about m code’ 表示从test.py文件中取出关于m的代码在本文件中解释一遍
7、导入优化
通常情况下,使用import module_name 如果在其中总是使用test函数,这样每次在使用时会实现检查test函数在module_name模块中是否存在,为了提高效率,可以使用from module_name import test方法导入该函数,相当于直接将test函数在这里直接解释了一编,提高运行效率
8、模块分类
1、标准库也叫内置模块
2、开源模块也叫第三方模块
3、自定义模块
9、标准库介绍
1、time与datetime
时间戳,以秒为单位
time.time()函数,以秒来计算
print(time.time()) #time.time不需要提供任何参数,表示自1970年1月1日到现在经过多少秒 #输出: 1487733672.621412
元组方式表示时间struct_time,包括了9个元素
time.localtime()#如果里面没有提供任何参数,会表示当前时间, 如果里面提供已秒为单位的数字,会显示对应其对应时间
print(time.localtime()) #输出 time.struct_time(tm_year=2017, tm_mon=2, tm_mday=22, tm_hour=14, tm_min=34, tm_sec=7, tm_wday=2, tm_yday=53, tm_isdst=0)#其中wday代表本周第几天,yday代表本年的第几天,而lsdst代表夏令时 #DST:夏令时 #UTC:世界标准时间
time.timezone #以秒的格式表示时区
print(time.timezone) #输出 -28800 #28800/3600=8表示东八区
time.daylight#是否使用夏令时
print(time.daylight) #输出 0
time.sleep()#其中跟参数表示暂停运行几秒
time.sleep(3)
time.gmtime与locatime
两者都是表示以元组形式表示时间,同时都以秒为所传参数,其中gmtime表示UTC时间,而localtime表示本地时间
print(time.gmtime()) print(time.gmtime(394049430)) #输出 time.struct_time(tm_year=2017, tm_mon=2, tm_mday=22, tm_hour=6, tm_min=53, tm_sec=56, tm_wday=2, tm_yday=53, tm_isdst=0) time.struct_time(tm_year=1982, tm_mon=6, tm_mday=27, tm_hour=18, tm_min=10, tm_sec=30, tm_wday=6, tm_yday=178, tm_isdst=0)
print(time.localtime()) print(time.localtime(394049430)) #输出 time.struct_time(tm_year=2017, tm_mon=2, tm_mday=22, tm_hour=14, tm_min=54, tm_sec=57, tm_wday=2, tm_yday=53, tm_isdst=0) time.struct_time(tm_year=1982, tm_mon=6, tm_mday=28, tm_hour=2, tm_min=10, tm_sec=30, tm_wday=0, tm_yday=179, tm_isdst=0)
x = time.localtime() print(x.tm_year) #同理,在得到的strcut_time中可以根据参数取不同的值 #输出 2017
time.mktime()#直接传入元组的形式,变为对应的秒
x = time.localtime(394049430) print(x) print(time.mktime(x)) #通过传入已元组形式的时间,转换成对应的秒 #输出 time.struct_time(tm_year=1982, tm_mon=6, tm_mday=28, tm_hour=2, tm_min=10, tm_sec=30, tm_wday=0, tm_yday=179, tm_isdst=0) 394049430.0
time.strftime()#将struct_time转成格式化的时间字符串
x = time.localtime(394049430) print(time.strftime('%Y-%m-%d %H:%M:%S', x))#%Y代表四位的年,%y代表两位表示的年,%m代表月,%M代表分钟,%H代表小时,%S代表秒 %w代表这种的第几天 #输出 1982-06-28 02:10:30
time.strptime()#将格式化的时间字符串转成struct_time
x = time.localtime(394049430) y = time.strftime('%y-%m-%d %H:%M:%S', x) print(time.strptime(y,'%%m-%d %H:%M:%S'))# 前面为格式化的时间字符串,后面是对应的格式,可以将该格式化时间字符串变为struct_time元组,格式只要匹配就可以,没有顺序要求例如:time.strptime("02-20 14:08:34 2017", "%m-%d %H:%M:%S %Y")
#输出 time.struct_time(tm_year=1982, tm_mon=6, tm_mday=28, tm_hour=2, tm_min=10, tm_sec=30, tm_wday=0, tm_yday=179, tm_isdst=-1)
strftime('格式',struct_time(元组格式)) --->转换成格式化时间字符串
strptime('格式化时间字符串',‘格式’) -----> 转成成struct_time
转换关系:
时间戳转成struct_time:gmtime、localtime
struct_time转成时间戳:mktime
struct_time转成格式化时间字符串:strftime
格式化时间字符串转成struct_time:strptime
time.asctime()#将struct_time转成格式化时间字符串,格式为%a %b %d %H:%M:%S %Y,其中%a表示星期,%b表示月,如果asctime没有传递参数,默认会导入localtime()的结果
print(time.asctime()) x = time.localtime(394049430) print(time.asctime(x)) #输出 Wed Feb 22 15:44:21 2017 Mon Jun 28 02:10:30 1982
time.ctime()将时间戳转成为%a %b %d %H:%M:%S %Y,其中%a表示星期,%b表示月
print(time.ctime()) #如果没参数传递,会将locatime转成成的秒传进去 x = time.time() print(time.ctime(x)) #传递进来的是时间戳,为秒 #输出 Wed Feb 22 15:48:25 2017 Wed Feb 22 15:48:25 2017
datetime模块:
datetime.datetime.now()#获取当前时间
print(datetime.datetime.now()) #输出 2017-02-22 15:52:24.551932
datetime.datetime.now()+datetime.timedelta(3) #默认是三天后的时间
print(datetime.datetime.now()+datetime.timedelta(3)) #输出 2017-02-25 15:54:03.199349
datetime.datetime.now()+datetime.timedelta(-3)#三天前的时间
print(datetime.datetime.now()+datetime.timedelta(-3)) #输出 2017-02-19 15:54:59.262861
datetime.datetime.now()+datetime.timedelta(hours=3)#三小时后的时间
print(datetime.datetime.now()+datetime.timedelta(hours=3)) #输出 2017-02-22 19:04:30.683096
datetime.datetime.now()+datetime.timedelta(hours=-3)#三小时前的时间
print(datetime.datetime.now()+datetime.timedelta(hours=-3)) #输出 2017-02-22 13:05:11.410832
当前时间替换time.replace()
c_time= datetime.datetime.now() print(c_time) r_time = c_time.replace(minute=3,hour=2) print(r_time) #输出 2017-02-22 16:08:55.694556 2017-02-22 02:03:55.694556
2、random模块
import random print(random.random()) #random()函数会在0-1之间随机取值 #输出 0.28605143730067417 print(random.randint(1,3)) #从整数中随机取值,得到的值均为1-3之间,1和3均有机会取到 #输出 3 print(random.randrange(1,3))#随机取1-2的整数,不会取到3 #输出 2 print(random.choice('abcde')) #choice表示从序列中取值,序列包括字符串 元组 列表 字典 #输出 #b print(random.choice([4,3,2,4])) #输出 3 print(random.choice((4,3,2,4))) #输出 4 print(random.sample('hello word',4)) #随机取四个数字 #输出 #['r', 'l', 'w', 'h'] print(random.uniform(1,3)) #手工设置random.random的取值范围,默认只是0-1之间,通过uniform方法可以做到在任意范围 #输出 2.07789196870395 item = [1,2,3,4,5,6,7,8] random.shuffle(item) print(item) #输出 [5, 2, 3, 8, 6, 4, 1, 7]
例子:
验证码
import random checkcode = '' for i in range(1,6): x = random.randint(0,9) #取0-9随机数 if x == i: x = chr(random.randint(65,90)) #将随机取一个数字然后转换成ascii码 else: x = random.randint(0,9) checkcode += str(x) #添加x到字符串中 print(checkcode)
3、os模块
>>> import os >>> os.getcwd() #获取当前路径 '/Users/Gavin' >>> os.chdir('/Users') #修改当前路径 >>> os.getcwd() '/Users' >>> os.curdir #获取当前目录 '.' >>> os.pardir #获取上一级目录 '..' >>> os.makedirs('/Users/Gavin/Desktop/a/b/c') #创建目录,就算没有父级目录页会递归创建 >>> os.removedirs('/Users/Gavin/Desktop/a/b/c')#删除目录,如果父集目录没有文件也会随之删除 os.mkdir('/Users/Gavin/Desktop/a/b/c')#如果创建的目录中没有父集目录会报错 Traceback (most recent call last): File "", line 1, in FileNotFoundError: [Errno 2] No such file or directory: '/Users/Gavin/Desktop/a/b/c' >>>os.mkdir('/Users/Gavin/Desktop/a') >>>os.rmdir('/Users/Gavin/Desktop/a')#删除创建的目录 >>>os.listdir('/Users/Gavin/Desktop')#列出目录中的文件以及子目录 >>>os.remove('/Users/Gavin/Desktop/ä¸两ç½网å合å¹并.xlsx')#删除对应的文件 >>>os.rename('/Users/Gavin/Desktop/oldname.doc','/Users/Gavin/Desktop/newname.doc')#修改文件名 >>>os.stat('/Users/Gavin/Desktop/newname.doc') os.stat_result(st_mode=33152, st_ino=40047776, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=116224, st_atime=1487753837, st_mtime=1487753837, st_ctime=1487753837) >>> os.sep #显示特定系统的目录分隔符 '/' >>> os.linesep #显示特定系统的换行符 '\n' >>> os.pathsep#显示特定系统的路径分隔符 ':' os.environ #显示环境变量 environ({'SHELL': '/bin/bash', 'SHLVL': '1', 'PWD': '/Users/Gavin', 'TMPDIR'}) >>> os.name 'posix' os.system('ls -l') #执行系统bash命令 total 2992 drwx------ 3 Gavin staff 102 10 29 11:42 Applications drwx------+ 35 Gavin staff 1190 2 22 22:10 Desktop >>> os.path.abspath('__file__') #查找文件的绝对路径 '/Users/Gavin/__file__' >>> os.path.split('/Users/Gavin') #os.path.split会将字符串通过/分割为两部分,不管文件或者路径是否存在 ('/Users', 'Gavin') >>> os.path.split('a/b') ('a', 'b') >>> os.path.dirname(os.path.abspath('__file__')) #os.path.dirname显示文件所在路径 '/Users/Gavin' >>> os.path.basename(os.path.abspath('__file__')) #os.path.basename只显示文件名 '__file__' >>> os.path.exists('/Users/Gavin') #os.path.exists判断文件或者目录是否存在 True >>> os.path.exists('/Users/a') False >>> os.path.isfile('/Users/Gavin/Desktop/newname.doc') #判断是否为文件 True >>> os.path.isfile('/Users/Gavin/Desktop/oldboy') False >>> os.path.isfile('/Users/Gavin/Desktop/oa') #就算不存在也不会报错只不过显示不为文件 False >>> os.path.isdir('/Users/Gavin/Desktop/oa') #判断目录是否为目录,不存在也不会报错 False >>> os.path.isdir('/Users/Gavin/Desktop') #判断是否为目录 True >>> os.path.join('a','b') #将前面两个字符串通过/方式合并 'a/b' >>> os.path.join('/Users','Gavin') '/Users/Gavin' >>> os.path.getatime('/Users/Gavin') #目录或者文件的访问时间 1487772945.0 >>> os.path.getctime('/Users/Gavin') #目录或者文件的创建时间 1486950756.0
4、sys模块
>>> sys.version #显示python版本号 '3.5.2 (v3.5.2:4def2a2901a5, Jun 26 2016, 10:47:25) \n[GCC 4 vim sys-test.py import sys print(sys.argv[1]) print(sys.argv[2]) >>>python3 sys-test.py a b a b >>>sys.exit(1) #退出,默认情况下正常退出为0
5、shutil模块
进行高级的文件、文件夹的拷贝工作,还可以压缩包
shutil.copyfileobj(src_file,dest_file) #拷贝文件,不常用,因为没有流控制
import shutil source_file= open('本节笔记','r',encoding='utf-8') dest_file = open('本节拷贝','w',encoding='utf-8') shutil.copyfileobj(source_file,dest_file)
shutil.copyfile(src_file,dest_file)#拷贝文件,copyfile比copyfileobj多了with open file as f这个步骤,所以无需使用source_file 和dest_file这两个变量代替引用
shutil.copyfile('本节笔记','本节拷贝') #源文件存在,目标文件可以存在,也可以不存在
shutil.copymode(src_file,dest_file) #只拷贝权限,内容,组、用户都不变
shutil.copymode('本节笔记','本节拷贝') #目标文件需要存在,只拷贝权限
shutil.copystat(src_file,dest_file)#拷贝状态的信息,包括:mode bits, atime, mtime, flags
shutil.copymode('本节笔记','本节拷贝') #目标文件需要存在,只拷贝权限
shutil.copy(src_file,dest)#copy比copyfile更高明的一点就是在于dest就算是目录,copy动作也会成功,同时会在dest的目录下创建一个和src_file完全相同的文件名,比copyfile多了copymode方法
shutil.copy('本节笔记','/Users/Gavin/PycharmProjects/python/day5/test')
shutil.copy2(src_file,dest)#copy2和copy类似,和copy的区别在于不是调用copymode,而是调用copystat函数
shutil.copy2('本节笔记','/Users/Gavin/PycharmProjects/python/day5')
shutil.copytree('src_dict','dest_dict') #copytree是目录拷贝,将源目录所有文件和目录全部拷贝到目标目录,有个必须注意的地方在于dest_dict目录必须是不存在的,如果存在就会报错
shutil.copytree('/Users/Gavin/Desktop/a','/Users/Gavin/Desktop/k')
shutil.rmtree('目录')#rmtree会递归方式删除相应目录
shutil.rmtree('/Users/Gavin/Desktop/a')
shutil.move(src_dict,dest_dict)#将a目录更名为b目录,如果在不同路径下,就完成移动动作
shutil.move('/Users/Gavin/Desktop/a','/Users/Gavin/Desktop/b')
shutil.make_archive(base_name,format,root=dir='')
shutil.make_archive('/Users/Gavin/Desktop/b/desktop','zip',root_dir='/Users/Gavin/Desktop/b') '''第一个参数表示base_name即压缩后的名字,后缀名会自动添加为第二个参数也就是压缩的方法包括:bztar,gztar,tar,xztar,zip等方法可选,root_dir表要压缩 目录或者文件,总体来讲,第一个是压缩后的basename,如果第一个参数只写了名字而没有写目录,会将压缩包保存到当前目录然后添加后面第二个参数为扩展名,第三个参数表示要压缩的目录或者文件''' print(shutil.get_archive_formats()) #表示压缩打包包括哪几种方法,如果忘记可以通过该函数进行查询
补充说明:
shutil对压缩包的调用ZipFile和TarFile两个模块完成的
a) ZipFile函数
import zipfile #压缩 z = zipfile.ZipFile('压缩名.zip','w') #压缩文件 z.write('本节笔记') #要压缩的文件添加 z.write('本节拷贝') #要压缩的文件添加 z.close()
#解压
z = zipfile.ZipFile('压缩名.zip','r')
z.extractall() #将压缩文件解压
z.close()
b) TarFile
import tarfile #打包 tar = tarfile.open('tar.tar','w') tar.add('本节笔记.zip',arcname='本节笔记.zip') #tar.add('本节拷贝',arcname='本节拷贝.zip') tar.close() #解包 tar = tarfile.open('tar.tar','r') tar.extractall() tar.close()
6、shelve模块
一个简单的k,v 将内存数据通过持久化的模块,可以持久任何pickle可支持python数据格式
import shelve,datetime info = {'name':'gavin', 'age': 16 ,'job': 'IT'} name1 = [1,2,3,4,5] name2 = 'abededg' time_now = datetime.datetime.now() #持久化存储 with shelve.open('shelve_test',) as f: #通过shelve.open方式打开文件,不需要写w和r f['info'] = info #将需要持久化的数据导入shelve_test中保存 f['name1'] = name1 f['name2'] = name2 f['time_now'] = time_now #从文件中读取 with shelve.open('shelve_test',) as f: print(f.get('name1')) #通过k方式获取value print(f.get('info')) print(f.get('name2')) print(f.get('time_now'))
7、XML模块
xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是xml。
xml的格式如下,就是通过<>节点来区别数据结构的:
xml version="1.0"?> <data> <country name="Liechtenstein"> <rank updated="yes">2rank> <year>2008year> <gdppc>141100gdppc> <neighbor name="Austria" direction="E"/> <neighbor name="Switzerland" direction="W"/> country> <country name="Singapore"> <rank updated="yes">5rank> <year>2011year> <gdppc>59900gdppc> <neighbor name="Malaysia" direction="N"/> country> <country name="Panama"> <rank updated="yes">69rank> <year>2011year> <gdppc>13600gdppc> <neighbor name="Costa Rica" direction="W"/> <neighbor name="Colombia" direction="E"/> country> data>
xml协议在各个语言里的都 是支持的,在python中可以用以下模块操作xml
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) for i in child: print(i.tag,i.text) #只遍历year 节点 for node in root.iter('year'): print(node.tag,node.text)
修改和删除xml文档内容
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") tree.write("xmltest.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文档
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) #打印生成的格式
8、Pyyaml模块
Python也可以很容易的处理ymal文档格式,只不过需要安装一个模块,参考文档:http://pyyaml.org/wiki/PyYAMLDocumentation
9、configParser模块
用于生成和修改常见配置文档,当前模块的名称在 python 3.x 版本中变更为 configparser。
a)生成config文件
import configparser config = configparser.ConfigParser() config['DEFAULT'] = { 'ServerAliveInterval': '45', 'Compresssion': 'yes', 'CompressionLevel': '9' } config['bitbucket.org'] = {} bitbucket = config['bitbucket.org'] bitbucket['User'] = 'hg' config['topsercret.server.com'] = {} topsercert = config['topsercret.server.com'] topsercert['Host Port'] = '50022' topsercert['ForwardX11'] = 'no' config['DEFAULT']['ForwardX11'] = 'yes' with open('example.ini', 'w') as f: config.write(f) #输出 [DEFAULT] serveraliveinterval = 45 compressionlevel = 9 compresssion = yes forwardx11 = yes [bitbucket.org] user = hg [topsercret.server.com] host port = 50022 forwardx11 = no
b)读配置文件
import configparser config = configparser.ConfigParser() print(config.sections()) #开始没有读进来之前没法看到sections config.read('example.ini') print(config.sections()) #通过sections函数没法读到default内容 conf_default = config.defaults() for line in conf_default: print('%s:\t%s' %(line,conf_default[line])) print(config['bitbucket.org']['User']) if 'bitbucket.org' in config: print(True) topsecert = config['topsercret.server.com'] print(topsecert['Host Port']) for key in config['bitbucket.org']: print(key) #输出 [] ['bitbucket.org', 'topsercret.server.com'] serveraliveinterval: 45 compressionlevel: 9 compresssion: yes forwardx11: yes hg True 50022 user serveraliveinterval compressionlevel compresssion forwardx11
c)修改配置文件
import configparser config = configparser.ConfigParser() config.read('example.ini') #读取 secs = config.sections() print(secs) options = config.options('bitbucket.org') #单独针对调用某一section对应的配置选项,options选项会将default选项内容带入 print(options) item_list= config.items('bitbucket.org') #针对调用section中对应的配置选项已经对应参数,item选项会将default选项也带入 print(item_list) val = config.get('bitbucket.org','user') print(val) val = config.get('bitbucket.org','compresssion') print(val) #修改 sec = config.remove_section('bitbucket.org') #移除secion sec = config.add_section('DB') #添加section sec = config.has_section('DB') #判断section是否存在 print(sec) sec = config.has_option('topsercret.server.com','forwardx11') #判断section中的option是否存在 print(sec) config.set('DB','mysql','https://www.mysql.com/3306') #对section中的option添加参数,必须为str类型 config.remove_option('topsercret.server.com','Host Port') #移除section内option with open('example1.ini','w') as f: config.write(f) #输出 [DEFAULT] serveraliveinterval = 45 compressionlevel = 9 compresssion = yes forwardx11 = yes [topsercret.server.com] forwardx11 = no [DB] mysql = https://www.mysql.com/3306
10、hashlib模块
用于加密相关的操作,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
import hashlib m = hashlib.sha512() #hashlib还包括md5 sha1等不同安全等级的函数调用 m.update('hello'.encode(encoding='utf-8')) print(m.hexdigest()) #按照16进制格式显示 m.update('中文也可以加密'.encode(encoding='utf-8')) print(m.hexdigest()) m1 = hashlib.sha512() m1.update('hello中文也可以加密'.encode(encoding='utf-8')) print(m1.hexdigest()) m2 = hashlib.sha512() with open('config.cfg','r') as f: f1 = f.read() m2.update('f1'.encode(encoding='utf-8')) #可以将整个文件进行加密 print(m2.hexdigest()) #输出 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043 9600f16b6ac743e6a78557de89b458f9c373424d8762ed4730397148e5f352d0339e879786fd0404635c907503f7a73ae70ea9be82dbcf9a1c66cc77f33690de 9600f16b6ac743e6a78557de89b458f9c373424d8762ed4730397148e5f352d0339e879786fd0404635c907503f7a73ae70ea9be82dbcf9a1c66cc77f33690de bc07fac547256ebcf7abc70731753f4ba70d4c09d856fab4f89255787bde9cbadc2ab85a77dcbbb523a7acf818bdf8db2da5ffb9b1a4d2b4ad71810795d3a546
python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 再进行处理然后再加密
import hmac h = hmac.new('中文key也可以'.encode(encoding='utf-8'),'message也是可以是中文'.encode(encoding='utf-8')) #前面是key,后面mess,在后面可以使用加密方法,但是一直没有使用过 h.update('我们在奋斗的路上一直不停留'.encode(encoding='utf-8')) print(h.hexdigest()) #输出 749c771880c1cf952c957623605918d8
11、re模块
常用的正则表达式符号
'.' 默认匹配除了\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
’^‘ 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r'^a', '\nabc\necc',flags=re.MULTILINE)
'$' 匹配字符结尾,或e.search('foo$', 'bfoo\nsdfsf', flags=re.MULTILINE).group()也可以
’*‘ 匹配*号前的字符0次或多次,re.findall('ab*', 'cabb3abcbbac') 结果为['abb', 'ab', 'a']
'+' 匹配前一个字符1次或多次,re.findall('ab+', 'ab+cd+abb+bba')结果['ab', 'abb']
'?' 匹配钱一个字符1次或0次
’{m}‘ 匹配前一个字符m次
’{m,n}‘ 匹配前一个字符m到n次,re.findall('ab{1,3}', 'abb abc abbcbbb') 结果['abb', 'ab', abb]
'|' 匹配|左或|右的字符,re.search('ab|ABC','ABCBabcCD') 结果['ABC']
(...) 分组匹配,re.search('(abc){2}a(123|456)c', 'abcabca456c').group() 结果 abcabca456c
\A 只从字符开头匹配,re.search('\Aabc', 'alexabc') 是匹配不到的,\A == ^
\Z 匹配字符结尾,同$
\d 匹配数字0-9
\D 匹配非数字
\w 匹配[A-Za-z0-9]
\W 匹配非[A-Za-z0-9]
\s 匹配空白字符,\t \n \r ,re.search('\s' ,'ab\tc1\n3').group() 结果\t
\b 类似与bash中\< \>对单词做锚定
(?P
371481199306143242').groupdict() 结果是{’province‘: 37, 'city': 14, 'hometown': 81,'birthday': 19930614}
最常用的匹配语法
re.match 从头开始匹配
re.search 匹配包含
re.findall 把所有匹配到的字符放到以列表中的元素返回
re.splitall 以匹配到的字符当做列表分隔符
re.sub 匹配字符并替换
仅需轻轻知道的几个匹配模式
re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同) M(MULTILINE): 多行模式,改变'^'和'$'的行为(参见上图) S(DOTALL): 点任意匹配模式,改变'.'的行为
import re Match = re.search(r'\ber\b', ' i am er eraber') print(Match.group()) #输出 er a = re.match('chen', 'chenronghuachenronghua') #有返回就是匹配到了,match从开头匹配 print(a.group()) #输出 chen a = re.match('k', 'chenronghuachenronghua') print(a) #匹配不到,如果写a.group()会报错 匹配不到 a = re.match('chen\d', 'chen234ronghua1234chenronghua12431adec') #有返回就是匹配到了 print(a.group()) #输出 chen2 \d代表数字,匹配一次,如果表示一个或多个,使用\d+ a = re.match('.+', 'chen234ronghua1234chenronghua12431adec') #有返回就是匹配到了 print(a.group()) #输出 chen234ronghua1234chenronghua12431adec a = re.search('^chen', 'chen234ronghua1234ronghua12431adec') #匹配所有,但是找到第一个就返回 print(a.group()) #输出 chen a = re.search('^c.+n\d+', 'chen234ronghua1234ronghua12431adec') #已c开头,中间用多个任意字符,后面是一个数字\d,因为使用search所以只能匹配第一个匹配就返回 print(a.group()) #输出 chen234 a = re.findall('^c.+n\d+', 'chen234ronghua1234ronghua12431adec') #findall会匹配全部匹配到值 print(a) #输出 ['chen234'] a = re.findall('\+$', 'chen234ronghua1234ronghua12431adec') #findall会匹配全部匹配到值D \D表示匹配非数字但是会匹配特殊字符 print(a) #输出 ['adec'] a = re.search('a[a-zA-Z]+c$', 'chen234ronghua1234ronghua12431adec') #[a-zA-Z]表示匹配所有字符一次,加+表示1次到多次 print(a.group()) #输出 adec a = re.search(r'\b#.+#$', '1123#hello#') #\b表示锚定字符 print(a.group()) #输出 #hello# a = re.findall(r'a?', 'abaalexa') # ?表示匹配前面字符0-1次 print(a) #输出 ['a', '', 'a', 'a', '', '', '', 'a', ''] a = re.search('[0-9]{3}','aa1x2a345aa') # {3}匹配 数字3次 print(a.group()) #输出 345 a = re.findall('[0-9]{1,3}','aa1x2a345aa') # {1,3}匹配 数字1-3次 print(a) #输出 ['1', '2', '345'] a = re.findall('abc|ABC','abcdedaABCCDABC') #匹配abc或者ABC print(a) #输出 ['abc', 'ABC', 'ABC'] a = re.findall('(abc){2}','abcabcABCabcdeabcabcdaedabcadedcad') # print(a) #输出 ['abc', 'abc'] a = re.findall('\A[0-9]+[a-z]+\Z','103494abd') #\A 等效于^ \Z 等效于\ print(a) #输出 ['103494abd'] a = re.findall('\D','103494abd\t \n\\') #\D 匹配非数字包括字符和特殊格式 print(a) #输出 ['a', 'b', 'd', '\t', ' ', '\n', '\\'] a = re.findall('\w','103494abd\t \n\\') #\w 匹配数字和字母 print(a) #输出 ['1', '0', '3', '4', '9', '4', 'a', 'b', 'd'] a = re.findall('\W','103494abd\t \n\\') #\W匹配非数字和字母 表示特殊格式与空格 print(a) 输出 #['\t', ' ', '\n', '\\'] a = re.findall('\s','103494abd\t \n\\') #\s匹配特殊字符 空格 不包括 "\" print(a) #输出 ['\t', ' ', '\n'] a = re.search('(?P[0-9]{2})(?P ', '371481199306143242') print(a.groupdict()) 输出 #{'province': '37', 'hometown': '81', 'city': '14', 'birthday': '19930614'} a = re.search('[a-z]+','abccdA', flags=re.I) #re.I 忽略大小写 print(a.group()) #输出 abccdA a = re.search('[a-z]+','abccdA', flags=re.I) #re.I 忽略大小写 print(a.group()) 输出 abccdA a = re.search('[a-z]+d$','abccdA\nsecondline\nthird', flags=re.M) #re.M匹配换行 print(a.group()) #输出 third a = re.search('.+','oneline\nsecondline\nthird\nfourthline', flags=re.S) #在.中如何使用re.S可以连换行都能匹配上 print(a.group()) #输出 oneline secondline third fourthline[0-9]{2})(?P [0-9]{2})(?P [0-9]{8})
12、conllections模块
1、Counter函数
counter函数对字符串、列表进行分割,统计字符串出现的次数
import collections obj = collections.Counter('abedjdjajdebaqazwsxedccvfredaa djdjejkd;ddoeeo;ddedpdkdkdk')#元素里出现次数记录,计数器功能
print(obj) #输出 Counter({'d': 16, 'e': 8, 'j': 6, 'a': 6, 'k': 4, 'o': 2, 'c': 2, ';': 2, 'b': 2, 'w': 1, 'q': 1, 'v': 1, 'z': 1, ' ': 1, 'f': 1, 'p': 1, 'r': 1, 'x': 1, 's': 1})
ret = obj.most_common(5) #输出前五个 print(ret) #输出 [('d', 16), ('e', 8), ('j', 6), ('a', 6), ('k', 4)]
obj = collections.Counter([11,22,33,22,33]) #对列表进行统计 print(obj) #输出 Counter({33: 2, 22: 2, 11: 1}) obj.update(['erc',11,11,22,11]) #对原有obj进行更新,添加数据 print(obj) #输出 Counter({11: 4, 22: 3, 33: 2, 'erc': 1}) obj.subtract(['erc', 11,22,33,11]) print(obj) #输出 Counter({11: 2, 22: 2, 33: 1, 'erc': 0})
2、双向队列与单向队列
deque表示双向队列,双向队列表示从右面与左面均可添加与消耗队列中的数据
import collections d = collections.deque() d.append('1') #正常的append从右面添加,append可以添加单个元素 d.appendleft('10') #从左面添加 d.appendleft('1') print(d) #输出 deque(['1', '10', '1']) print(d.count('1')) #输出 2 d.extend(['aa','bb','aa']) #extend添加多个元素 print(d) #输出 deque(['1', '10', '1', 'aa', 'bb', 'aa']) d.extendleft(['aa','bb','aa']) print(d) #输出 deque(['aa', 'bb', 'aa', '1', '10', '1', 'aa', 'bb', 'aa'])
单向队列只能从一侧添加一侧消耗
import queue q = queue.Queue() q.put('123') print(q.qsize()) #输出 1 q.put('789') print(q.qsize()) #输出 2 print(q.get()) #输出 123 print(q.get()) #输出 789
3、可命名元组
import collections M = collections.namedtuple('Mytuple', ['x','y','z']) obj = M(11,22,33) print(obj.x,obj.y,obj.z) #输出 11 22 33
4、有序字典
import collections dic = collections.OrderedDict() #有序字典定义 dic['k1'] = 'v1' dic['k2'] = 'v2' dic['k3'] = 'v3' for i in dic: print(i + '\t\t' + dic[i]) #输出® k1 v1 k2 v2 k3 v3 dic.popitem() print(dic) #输出 OrderedDict([('k1', 'v1'), ('k2', 'v2')]) ret = dic.pop('k1') print(dic) print(ret) #输出 OrderedDict([('k2', 'v2')]) v1 dic.setdefault('k2','444') #如果没有就变成444,如果本身有值就不变 dic.setdefault('k4') #只有k4,就把值变为None print(dic) #输出 OrderedDict([('k2', 'v2'), ('k4', None)]) dic.update({'k2': 'v222', 'k10':'v10'}) #通过update方法添加多个元素,如果原来key存在会修改原value print(dic) #输出 OrderedDict([('k2', 'v222'), ('k4', None), ('k10', 'v10')])
5、默认字典
import collections dic = collections.defaultdict(list) #创建一个字典,字典的默认值为list dic['k1'].append('alex') dic['k1'].extend(['gavin','age',23]) print(dic) #输出 defaultdict(<class 'list'>, {'k1': ['alex', 'gavin', 'age', 23]}) dic1 = collections.defaultdict(dict) dic1['k1']['k1'] = 'v1' dic1['k2']['k2'] = 'v2' print(dic1) #输出 defaultdict(<class 'dict'>, {'k2': {'k2': 'v2'}, 'k1': {'k1': 'v1'}})
13、subprocess模块
subprocess将代替os.system与os.spawn模块,在python2.7中,subprocess模块调用call()函数显示实时输出结果,通过Popen函数保存输出结果,在python3.5以后,通过run()代替call()函数
import subprocess subprocess.run('df -h',shell=True) a = subprocess.Popen('df -h',shell=True,stdout=subprocess.PIPE) #run与call和Popen都是如此,如果参数不止一个,同时也不想通过列表方式传入,需要shell=True #如果需要保存输出结果,需要通过Popen函数保存,同时需要通过subprocess.PIPE管道方式将结果传递给输出 print(a.stdout.read())
终端输入命令分为两种:
1、输入即可得到输出 如ifconfig
2、输入进行某环境依赖再输入 如python
需要交互命令实例:
可以使用这个方法与另外一个子进程进行交互(配合管道PIPE来使用)
import subprocess obj = subprocess.Popen(['python'], stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) obj.stdin.write('print 1 \n'.encode('utf-8')) obj.stdin.write('print 2 \n'.encode('utf-8')) obj.stdin.write('print 3 \n'.encode('utf-8')) obj.stdin.write('print 4 \n'.encode('utf-8')) out_err_list = obj.communicate(timeout=10)#如果想结束进程,使用communicate函数 print(out_err_list)
14、logging模块
很多程序都有记录日志的需求,并且日志中包含的信息既有正常的程序访问日志,还可能有错误告警灯信息输出,python的logging模块提供了标准的日志接口,可以通过它存储各种格式的日志,logging的日志分为debug、info、warning、error5个等级
import logging logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%Y-%m-%d %H:%M:%s ', filename='example-log.log',level=logging.INFO) #%S 表示正常秒 %s表示更精确的秒, %p表示 AM或者PM这个可以和%I一起使用 logging.debug('this message should go to the log files') logging.info('so should this') logging.warning('and this, too')
10、二分法
def find_data(data,find_i): if len(data) > 1: if data[int(len(data)/2)] > find_i: print(data[:int(len(data)/2)]) find_data(data[:int(len(data)/2)],find_i) elif data[int(len(data)/2)] < find_i: print(data[int(len(data)/2):]) find_data(data[int(len(data)/2):],find_i) else: print('find the number: %s' %data[int(len(data)/2)]) else: if data[int(len(data)/2)] == find_i: print('find the number: %s' %data[int(len(data)/2)]) else: print('cant not find') if __name__ == '__main__': data = list(range(1,50,3)) find_data(data,5)
11、冒泡排序
data = [10,4,33,21,22,54,3,8,11,5,22,17,13,6] for j in range(1,len(data)): for i in range(len(data)-j): if data[i] > data[i+1]: tmp = data[i] data[i] = data[i+1] data[i+1] = tmp print(data)
12、时间复杂度
时间复杂度是用来衡量算法的优劣,通常来讲,算法效率越高,时间复杂度消耗的时间越低,通常来说,时间复杂度分为O(n) 线性复杂度,O(n2)和O(n3),还有 O(1)和O(logn),其中O(1)为常量,不论数据量多大,都是同一时间完成,效率最高,而O(logn)的典型代表就是二分法和二叉树法,这种方法随着数据量越高,效率越高, O(n)为线性增长,随着数据量的增大而线性增大,最后是O(n2) O(n3)分别代表算法中存在两次循环和三次循环,效率比前面的低
13、深拷贝
拷贝分为深拷贝与浅拷贝,其中copy.copy()与变量赋值均属于浅拷贝,浅拷贝的特点为只拷贝第一层数据,而不拷贝第一层以外的数据,这样的坏处在于修改了第一层以外的数据的拷贝数据时,原始数据也会跟着修改,而深拷贝会拷贝所有数据,无论数据处于第几层,这样拷贝数据与原始数据相互之间不受影响
import copy ''' #浅拷贝 copy.copy() #深拷贝 copy.deepcopy() #赋值 a = '111' b = a ''' #赋值 a1 = 123 b1 = 123 print(id(a1)) print(id(b1)) a2 = a1 print(id(a1)) print(id(a2)) #字符串拷贝,对于字符串,深浅拷贝都只是指向内存都一地址 a3 = copy.copy(a1) print(id(a3)) a4 = copy.deepcopy(a1) print(id(a4)) #对元组/列表/字典拷贝 n1 = {'k1': 'wu', 'k2': 123, 'k3': ['alex',456]} n2 = n1 #赋值 print(id(n1)) print(id(n2)) n3 = copy.copy(n1) #浅拷贝,只拷贝一层,所以n3只拷贝了k1 k2 k3对应的值,而k3中代表的列表没有进行拷贝 print(id(n3)) print(id(n3['k3'])) #由于浅拷贝只拷贝一层,所以n3与n1的k3对应的列表内存地址一样 print(id(n1['k3'])) n4 = copy.deepcopy(n1) print(id(n4['k3'])) print(id(n4))