Python之路 Day5 常用模块
import 导入模块
1.定义
类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合。而对于一个复杂的功能来,可能需要多个函数才能完成(函数又可以在不同的.py文件中),多个.py 文件组成的代码集合就称为模块,是为了实现某个功能的代码集合。
2.导入模块
导入模块其实就是告诉Python解释器去解释那个py文件,导入一个py文件,解释器解释该py文件。导入一个包,解释器解释该包下的 __init__.py 文件。
导入方法:
import module
from module.xx.xx import xx
from module.xx.xx import xx as rename
from module.xx.xx import *
3.模块的分类
- 标准库
- 开源模块
- 自定义模块
####时间模块
模块有time,datetime表示方式有(1)时间戳,(2)格式化时间字符串,(3)元组(struct_time)共九个元素。
时间戳
>>> time.time()
1550499641.1268253 #打印从19700101 8:00:00到当前时间所经历的秒数
>>> time.mktime(time.strptime("2018-11-08 15:32:02","%Y-%m-%d %X"))
1541662322.0 #将当前时间转为时间戳
格式化时间字符串
>>> time.ctime(time.time())
'Mon Feb 18 22:24:59 2019' #接收的参数是字符串
>>> time.asctime(time.localtime())
'Mon Feb 18 22:25:02 2019' #接收的参数是元组
>>> print(datetime.datetime.now())
2019-02-18 22:26:41.758610
>>> time.strftime('%X %Y-%m-%d',time.localtime())
'22:33:20 2019-02-18' #根据time.localtime()来自定义时间
>>> print(time.strptime("2018-11-08 15:32:02","%Y-%m-%d %X"))
time.struct_time(tm_year=2018, tm_mon=11, tm_mday=8, tm_hour=15, tm_min=32, tm_sec=2, tm_wday=3, tm_yday=312, tm_isdst=-1) #将'2018-11-08 15:32:02'转为time.localtime()格式,#前后格式需要一一对应但是顺序不需要。
元组(struct_time)
>>> time.gmtime() #UTC标准时间
time.struct_time(tm_year=2019, tm_mon=2, tm_mday=18, tm_hour=14, tm_min=30, tm_sec=32, tm_wday=0, tm_yday=49, tm_isdst=0)
>>> time.localtime() #当前时间
time.struct_time(tm_year=2019, tm_mon=2, tm_mday=18, tm_hour=22, tm_min=30, tm_sec=36, tm_wday=0, tm_yday=49, tm_isdst=0)
获取过去或未来时间
>>> print(datetime.datetime.now() + datetime.timedelta(3))
2019-02-21 22:37:31.583559 #三天后时间
>>> print(datetime.datetime.now() + datetime.timedelta(hours=3))
2019-02-19 01:38:06.303301 #三小时后时间
>>> print(datetime.datetime.now() + datetime.timedelta(hours=-3))
2019-02-18 19:38:28.503632 #三小时前时间
替换时间
>>> print(datetime.datetime.now().replace(minute=3,hour=2))
2019-02-18 02:03:08.503691
####random模块
import random
print(random.random()) ##生成0到一之间随机数
print(random.randint(100,999)) ##生成100到999之间随机数
print random.randrange(1,10) ##生成1到10之间随机数,不包含10
print(random.choice([1,'23',[4,5]])) #从列表中返回其中一个值
print(random.uniform(1,3)) ##大于1小于3的小数,如1.927109612082716
print(random.sample('hello',3)) ##从总体序列或集合中选择多个唯一的随机元素,以列表形式返回。
item=[1,3,5,7,9]
random.shuffle(item) ##打乱item的顺序,相当于"洗牌"
print(item)
import string
print(string.ascii_lowercase) ##生成小写字母
print(string.ascii_uppercase) ##生成大写字母
print(string.ascii_letters) ##生成所有字母
print(string.digits) ##生成0-9数字
生成随机验证码:
import random,string
checkcode = ''
road=True
for i in range(8):
if road:
checkcode+=random.choice(string.ascii_letters)
road=False
else:
checkcode += random.choice(string.digits)
road=True
print(checkcode)
####os模块
提供对操作系统进行调用的接口
import 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 输出用于分割文件路径的字符串
os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") 运行shell命令,直接显示,结果无法赋值给变量
os.popen("bash command") 执行系统命令,可以赋值保存但是需要read读。
os.environ 获取系统环境变量
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所指向的文件或者目录的最后修改时间
####shutil模块
import shutil
shutil.copyfile('1.txt','2.txt') 拷贝文件
shutil.copy('1.txt','2.txt') 拷贝文件和权限
shutil.copy2('1.txt','2.txt') 拷贝文件和权限,还有时间等属性。
shutil.copymode('f1.log', 'f2.log') 仅拷贝权限。内容、组、用户均不变,目标文件需要已经存在。
shutil.copystat('f1.log', 'f2.log') 仅拷贝权限和状态信息访问时间等。内容、组、用户均不变,目标文件需要已经存在。
shutil.move('1.txt','2.txt') 移动文件,相同目录下相当与改名
shutil.copytree(src, dst) 拷贝目录
shutil.rmtree(path) 删除目录
压缩目录:
shutil.make_archive(base_name, format,...)
base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径。
format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
root_dir: 要压缩的文件夹路径(默认当前目录)压缩文件。
注:默认会给你的压缩包加上后缀名。
shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:
import zipfile
#压缩
z=zipfile.ZipFile('test.zip','w')
z.write('test.xml')
z.write('test1.xml')
z.close()
#解压出一个文件
z=zipfile.ZipFile('test.zip','r')
z.extract(member='test.xml')
z.close()
#解压出所有文件
z=zipfile.ZipFile('test.zip','r')
z.extractall(member='test.xml')
z.close()
import tarfile
#压缩
tar = tarfile.open('your.tar','w')
tar.add('test.xml', arcname='test.xml')
tar.add('test1.xml', arcname='test1.xml')
tar.close()
# 解压
tar = tarfile.open('your.tar','r')
tar.extractall() # 可设置解压地址
tar.close()
shelve模块
shelve模块以k,v格式存储数据,可以持久化任何pickle可支持的Python数据类型。
#写入:
d=shelve.open('shelve_test')
info={'age':22,'j ob':'it'}
name=['zyl','syf','test']
d['in']=info
d['na']=name
d.close()
#读取例
d=shelve.open('shelve_test')
print(d.get('in '))
结果:{'age': 22, 'j ob': 'it'}
xml模块
import xml.etree.ElementTree as ET
#读取:
tree = ET.parse('xmltest.xml')
root=tree.getroot()
for i in root:
print(i.tag,i.attrib) ##tag是第一层的标签名,attrib是第一层标签名的信息。
for c in i:
print(c.tag,c.text,c.attrib) ##打印第二层的标签名,文本数据,标签名的信息。
for node in root.iter('year'):
print(node.tag,node.text) ##只打印单个节点信息,就算year在多级目录下也会打印。
#修改:
tree = ET.parse('xmltest.xml')
root=tree.getroot()
for node in root.iter('year'):
node.text=str(int(node.text)+1) ##所有标签为year的内容加1
node.set("updated",'yes') ##设置标签属性。
tree.write('xmltest.xml') ##修改完毕后需要在写入到文件
删除某一段:
tree = ET.parse('xmltest.xml')
root=tree.getroot()
for country in root.findall('country'):
rank=int(country.find('year').text)
if rank == 2012:
root.remove(country) #删除年份为2012的节点
tree.write('output.xml')
编写xml文件:
new_xml=ET.Element('data') #一级标签
info=ET.SubElement(new_xml,"personinfo",attrib={'enrolled':'yes'}) #二级标签
info2=ET.SubElement(new_xml,"personinfo2",attrib={'a':'666'}) #二级标签
name=ET.SubElement(info,"name") #三级标签
age=ET.SubElement(info,'age')
name.text='zyl' #给三级标签设置值
age.text='30'
name=ET.SubElement(info2,"name") #三级标签
age=ET.SubElement(info2,'age')
name.text='wq'
age.text='16'
et=ET.ElementTree(new_xml) #生成et对象
et.write('new_xml',encoding="utf-8",xml_declaration=True) #写入到new_xml文件中
configparser模块
用于生成和修改常见配置文档
生成如下格式:
[Default]
a = 1
b = 2
c = 3
forwardx11 = yes
[bit]
user = hg
[topse]
port = 5022
forwardx11 = no
如果想用python生成一个这样的文档怎么做呢?
import configparser
#编写文件:
config=configparser.ConfigParser()
config["Default"]={'a':1,
'b':2,
'c':3}
config['bit']={}
config['bit']['user']='hg'
config['topse']={}
a=config['topse']
a['port']='5022'
a['forwardx11']='no'
config['Default']['ForwardX11']='yes'
with open('ConfParser.py','w') as configfile:
config.write(configfile)
#返回节名称列表,不包括[DEFAULT]:
import configparser
config = configparser.ConfigParser()
config.read('example.ini')
config.sections()
#读取模块下单独的选项:
import configparser
config = configparser.ConfigParser()
config.read('example.ini')
config['bitbucket.org']['User']
#读取模块下选项和对应的参数:
>>>print(config.items('bit'))
[('user', 'hg')]
#只读取模块下所有的选项:
>>>config.options('bit')
['user']
#删除单个模块:
config.remove_section('group1')
#添加一个模块:
config.add_section('wupeiqi')
#给新加的模块添加一个键值对
config.set('wupeiqi','user','zyl')
#修改一个选项的值:
config.set('group2','k1',11111)
#删除一个选项:
config.remove_option('group2','age')
#注意:所有修改文件的操作都需要冲新写入到一个文件中。
config.write(open('ConfParser.py','w'))
hashlib模块
用于加密相关的操作,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512,MD5算法
import hashlib
#md5:
m = hashlib.md5()
m.update(b"Hello") ##必须为bytes格式
m.update(b"It's me") ##多个值会组成一个值,相当于b“Hello It's me”
print(m.digest()) #2进制格式hash
print(m.hexdigest()) #16进制格式hash
#sha256:
m = hashlib.sha512()
m.update(b"Hello")
print(m.hexdigest())
#加密中文格式:
m = hashlib.sha512()
m.update("小朱朱".encode(encoding='utf-8'))
print(m.hexdigest())
re模块
常用正则表达式符号
'.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",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次
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c
'[]' 匹配其中任意一个字符,也可以写为[a-zA-Z0-9]
'[^]' 排除其中所有字符
'\A' 只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\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'
#flags标志位
re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
例:re.search("([a-z]+)","aaaAaAC234aaa",flags=re.I)
S(DOTALL): 点任意匹配模式,改变'.'的行为,可以匹配到换行符。
例:re.search(".+","aaaAaAC\r\n234aaa",flags=re.S)
1.re.match函数
尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
语法:re.match(pattern, string, flags=0)
#示例:
>>> import re
>>> obj = re.match('\d+', '123uuasf')
>>> print(obj.group())
123
2.匹配对象方法
1.group() 匹配的整个表达式的字符串
2.group(1) 第一个匹配的()中的值
3.groupdict() 返回以有别名的组的别名为键、以该组截获的子串为值的字典
例:print(re.search("(?P[0-9]{2})(?P\d+)","1234567").groupdict())
结果:{'zyl': '12', 'zz': '34567'}
4.start() 返回匹配开始的位置
5.end() 返回匹配结束的位置
6.span() 返回一个元组包含匹配(开始,结束)的位置
3.re.search方法
扫描整个字符串并返回第一个成功的匹配。
#示例1:
>>> print(re.search('com','www.baidu.com').group())
com
#示例2:
>>> line = "Cats are smarter than dogs";
>>> searchobj=re.search(r'(.*re)(.*)(th.*)',line) ##默认贪婪
>>> print(searchobj.group(2))
smarter
4.re.sub方法
##替换字符串中的匹配项。
语法: re.sub(pattern, repl, string, count=0, flags=0)
#示例1:
>>> s='2017/19/31'
>>> print(re.sub('(\d+)/(\d+)/(\d+)',r'\3-\2-\1',s))
31-19-2017
#示例2:
>>> re.sub("[0-9]+",'|',"aaa234aa111sfaf")
'aaa|aa|sfaf'
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认0表示替换所有的匹配。
5.findall
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表.match 和 search 是匹配一次而findall匹配所有。
#示例:
>>>print(re.findall('\d+','zul111zyl111'))
['111', '111']
6.split方法
按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:
语法:re.split(pattern, string[, maxsplit=0, flags=0])
#示例:
>>> re.split("[0-9]+","aaa234aa111sfaf")
['aaa', 'aa', 'sfaf']
>>> re.split("([0-9]+)","aaa234aa111sfaf")
['aaa', '234', 'aa', '111', 'sfaf'] #保留分隔符
每日练习
开发一个简单的python计算器
- 实现加减乘除及拓号优先级解析
- 用户输入
1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )
等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式(不能调用eval等类似功能偷懒实现),运算后得出结果,结果必须与真实的计算器所得出的结果一致
代码如下
# Author:ZhuYuLiang
import re
def format_mark(express):
express = express.replace('+-', '-')
express = express.replace('-+', '-')
express = express.replace('++', '+')
express = express.replace('--', '+')
express = express.replace('*+', '*')
express = express.replace('+*', '*')
express = express.replace('+/', '/')
express = express.replace('/+', '/')
return express
def Add_and_Sub(value):
expr = value
sub_expr = re.search(r"\-?\d+\.?\d*[\+\-]\d+\.?\d*", expr)
if not sub_expr:
return expr
else:
sub_expr2 = sub_expr.group()
if len(sub_expr2.split('+')) > 1:
n1, n2 = sub_expr2.split('+')
result = float(n1) + float(n2)
else:
n1, n2 = sub_expr2.split('-')
result = float(n1) - float(n2)
re_sub_expr = re.sub(r"\-?\d+\.?\d*[\+\-]\d+\.?\d*", str(result), expr, count=1)
bb = Add_and_Sub(str(re_sub_expr))
return bb
def Multiplication_and_division(value):
expr = value
sub_expr = re.search(r"\d+\.?\d*[\/\*]\-?\d+\.?\d*", expr)
if not sub_expr:
return expr
else:
sub_expr2 = sub_expr.group()
if len(sub_expr2.split('/')) > 1:
n1, n2 = sub_expr2.split('/')
result = float(n1) / float(n2)
elif len(sub_expr2.split('*')) > 1:
n1, n2 = sub_expr2.split('*')
result = float(n1) * float(n2)
else:
# 只计算乘除,加减直接pass,放入加减函数执行
pass
re_sub_expr = re.sub(r"\d+\.?\d*[/\*]\-?\d+\.?\d*", str(result), expr, count=1)
# 反复调用除法
bb = Multiplication_and_division(format_mark(re_sub_expr))
return bb
def compute(value):
value=Multiplication_and_division(format_mark(value))
value=Add_and_Sub(format_mark(value))
return value
def del_brackets(value):
sub_expr=re.search('\([^()]+\)',value)
if not sub_expr:
return value
else:
sub_expr=sub_expr.group()[1:-1]
sub_expr=compute(sub_expr)
sub_expr3 = re.sub('(\([\+\-\*\/\.0-9]+\))', str(sub_expr), value, count=1)
delkuohao_expr=del_brackets(format_mark(sub_expr3))
return delkuohao_expr
if __name__ == '__main__':
while True:
express=input('>>: ').replace(' ','')
print('eval输出值: ',eval(express))
if not express:
continue
elif express == 'q':
exit()
elif re.search('[^0-9.+\-*/()]',express):
print('\033[31;1m输入错误\033[0m')
else:
express=del_brackets(express)
express2 = compute(format_mark(express))
print('公式输出值: ',express2)