python 模块
#模块
模块的分类
1. 安装包中自带的内置模块
2. 需要下载的第三方模块
3. 自定义模块
内存中,如果这个模块已经加载过了,就不会重复加载.
系统内置名称空间(内置的模块)
sys.path指定的路径
__name__属性
__name__是Python内置的一个属性,Python中的函数,模块,类都有这个属性.
1. 模块直接以脚本方式执行的话, __name__ 属性值是固定的字符串: __main__ .
2. 如果模块是被其他模块导入的话,被导入模块的 __name__ 属性就是这个模块的真实名字.
通过__name__属性的值判断是否执行此测试函数: if __name__ == '__main__': main()
-
-
在程序中命名不要和模块中的成员同名.
-
使用别名
别名(alias)的使用
import test_module as tm # 相当于定义一个tm变量,指向了被导入的模块对象 print(tm.a) # 使用模块的别名访问变量 tm.test() # 使用模块的别名调用方法 1 2 3
在使用 from ... import * 这种方式导入一个模块时,默认情况下这个模块中的所有成员都会被导入.可以在被导入 的模块中使用 __all__ 这个属性控制某些成员可以不被其他模块导入. # 在my_module.py中添加 __all__ 属性,它是一个由允许被导入的成员名组成的列表. __all__ = ['f1','f2'] def f1(): print('f1') def f2(): print('f2') 1 2 3 4 5 6 7
from 相对路径 import xxx 其中,常用的相对路径就是.和..
random模块主要用于获取一定范围的随机数. 常用的方法有: randint(a,b) :返回一个[a,b]范围内的整数值.注意是闭区间! random() :返回一个[0.0, 1.0]范围内的浮点数. uniform(a,b) :返回一个[a,b]或[a,b]范围内的浮点数. shuffle(x [, random]) :返回一个被打乱顺序的shuttle对象.要求第一个参数必须是可变的数据类型,顺序 打乱之后直接反应在第一个参数表示的对象上.第二个参数表示的是打乱的规则.默认使用的是random.random 函数.如果想对一个不可变数据类型中的元素进行打乱.可以使用sample函数. sample(x,k) :从x中随机选择k个元素,返回一个列表.如果对一个不可变数据类型中的元素打乱顺序,只需要将 所有的元素随机抽取出来即可. slice = random.sample(list, 5) # 从list中随机获取5个元素,作为一个片断返回
time模块表示的是和时间有关的操作. 常用的方法有: time() :返回从时间原点(1970-01-01 00:00:00)到现在经过的秒数,即:当前的时间戳(timestamp). gmtime([seconds]) :返回一个以元组形式的结构化时间对象(struct_time),参数是表示从时间原点开始经 过的秒数.默认使用当前的时间戳,即: time() 的返回值. localtime([seconds]) :和gtime作用相似,只是结果中的某些字段转换成了本地格式. mktime(t) :和localtime是相反的操作.参数是一个格式化时间对象,返回值表示的是这个时间对象相对时间 原点的秒数.
时间戳 time()
结构化 gmtime()
字符串 localtime()
时间戳,结构化时间对象,字符串是time模块中非常重要的三大对象. 其中:时间戳和结构化时间对象利于在不同的时区之间进行传播(即:国际化),但是不利于阅读. 字符串便于阅读.但是不利于国际化. 结构化时间对象看起来像一个元组,一共有九个属性字段,可以单独使用其中的属性值. 例如: import time t = time.strftime('%Y-%m-%d %H:%M:%S') # 把当前时间转换成指定格式的字符串 print(t)
-
-
time :时间,包含hour,minute,second,microsecond,tzinfo属性.
-
datetime :前两者的混合体.
-
timedelta :(时间增量),主要用来在某些属性上进行数学运算.
举例
import datetime d = datetime.date(2010,10,10) print(d.year) # 2010 print(d.month) # 10 print(d.day) # 10 t = datetime.time(10,22,15) print(t.hour) # 10 print(t.minute) # 22 print(t.second) # 15 dt = datetime.datetime(2010,10,10,8,9,20) print(dt.year,dt.month,dt.day,dt.hour,dt.minute,dt.second) # 2010 10 10 8 9 20 1 2 3 4 5 6 7 8 9 10
# 本地写入环境配置 (读取环境变量) # 变量名 = os.getenv('变量名','默认值') from dotenv import load_dotenv load_dotenv("/Users/hunter/work/env_list/local_wechat.env") # 环境地址 # 获取环境变量 vim local_wechat.env # 这里的变量名需要和os.getenv(变量名)相同才会引入 # 变量名 = 配置信息 HOSt = 127.0.0.1
-
-
os.rmdir(dir_path) :删除空文件夹
-
删除非空文件夹使用另一个模块:shutil
-
shutil.rmtree(path)
-
os.removedirs(name) :递归删除空文件夹
-
os.rename(src, dst) :文件,目录重命名,目标不能事先存在.
举例
import os os.remove('a.txt') os.rmdir('aa') # 只能删除空目录 os.removedirs('bb') os.rename('abc','def')
shutil删除非空目录.
使用shutil模块删除非空目录.
import shutil shutil.rmtree('aa') # 可以删除带内容目录
获取功能
os.path.abspath(path):返回一个路径的绝对路径.
os.path.abspath(path) :返回一个路径的绝对路径. 如果参数路径是相对的路径,就把当前路径和参数路径的组合字符串当成结果返回. 如果参数路径已经是绝对路径,就直接把参数返回. 如果参数路径以/开始,则把当前盘符和参数路径连接起来组成字符串返回. import os print(os.path.abspath('aa')) # D:\PycharmProjects\test03\test01\aa print(os.path.abspath('D:/test/aa')) # D:\test\aa print(os.path.abspath('/bb')) # D:\bb
os.path.split(path):分割
返回一个元组,第二个元素表示的是最后一部分的内容,第一个元素表示的是剩余的内容
os.path.split(path) :返回一个元组,第二个元素表示的是最后一部分的内容,第一个元素表示的是剩余的内 容. 如果只是一个盘符或者是以路径分隔符结尾的字符串,则第二个元素为空. 否则第二个元素就是最后一部分的内容. 如果path中不包含路径分隔符,则第一个元素为空. import os print(os.path.split('D:/')) # ('D:/', '') print(os.path.split('.')) # ('', '.') print(os.path.split('/aa')) # ('/', 'aa')
os.path.basename(path):返回path指定的路径的最后一个内容
os.path.basename(path) :返回path指定的路径的最后一个内容. 如果只是一个盘符,或者是以路径分隔符结尾的字符串,则返回空; 否则返回的是路径中的最后一部分内容. import os print(os.path.basename('.')) # . print(os.path.basename('/aa')) # aa print(os.path.basename('/aa/')) # print(os.path.basename('D:/test')) # test
os.path.dirname(path) :返回一个路径中的父目录部分.
os.path.dirname(path) :返回一个路径中的父目录部分. 如果只是一个盘符,或者是以路径分隔符结尾的字符串,则整体返回. 否则返回的是路径中的父目录部分. import os print(os.path.dirname('.')) # print(os.path.dirname('/aa/')) # /aa print(os.path.dirname('D:/test')) # D:/ print(os.path.dirname('D:/')) # D:/
os.path.getsize(path) :获取文件的字节数.
如果是文件夹,返回0或者是一个不准确的值
print(os.path.getsize('aa')) # 0 print(os.path.getsize('.')) # 4096 print(os.path.getsize('aa/test.txt')) # 6 1 2 3
os.path.join(path,*paths) :连接路径
若干个路径为一个路径.
如果路径中有绝对路径,则在这个路径之前的路径都会被丢弃,而从这个路径开始往后拼接. Windows中盘符一定要带\,否则不认为是一个盘符. res = os.path.join('aa','bb','cc') print(res) # aa\bb\cc res2 = os.path.join('D:/','test') print(res2) # D:/test
os.path.exists(path) :判断路径是否真正存在.
os.path.isabs(path) :判断是否是绝对路径
os.path.isfile(path) :判断是否是文件
os.path.isdir(path) :判断是否是目录
sys.argv :
当以脚本方式执行程序时,从命令行获取参数.
提供了解释器使用和维护的变量和函数. sys.argv :当以脚本方式执行程序时,从命令行获取参数. argv[0]表示的是当前正在执行的脚本名.argv[1]表示第一个参数,以此类推. import sys print('脚本名称:',sys.argv[0]) print('第一个参数是:',sys.argv[1]) print('第二个参数是:',sys.argv[2])
使用cmd命令行方式运行该脚本: python test.py hello world
sys.modules 返回系统已经加载的模块,以字典形式返回.
sys.modules :返回系统已经加载的模块,以字典形式返回.
对这个字典中的值进行修改并没有什么具体意义.反而有时会引发异常.
常用来作为是否重新加载一个模块的判断依据.
sys.path:系统寻找模块的路径
sys.path :系统寻找模块的路径.可以通过PYTHONPATH来进行初始化.
由于是在程序执行的时候进行初始化的,所以,路径的第一项path[0]始终是调用解释器的脚本所在的路径.如果
是动态调用的脚本,或者是从标准输入读取到脚本命令,则path[0]是一个空字符串.程序中可以随时对这个路径
进行修改.以达到动态添加模块路径的目的.
-
不同语言都遵循的一种数据转化格式,即不同语言都使用的特殊字符串。(比如Python的一个列表[1, 2, 3]利用json转化成特殊的字符串,然后在编码成bytes发送给php的开发者,php的开发者就可以解码成特殊的字符串,然后在反解成原数组(列表): [1, 2, 3])
-
json序列化只支持部分Python数据结构:dict,list, tuple,str,int, float,True,False,None
l1 = [i for i in range(10000)] # l1 --->bytes # b1 = l1.encode('utf-8') # 不能直接转换 # l1转化成字符串在转化成bytes s1 = str(l1) b1 = s1.encode('utf-8') # print(b1) # 岑哥接收了b1 s2 = b1.decode('utf-8') # print(s2,type(s2)) # str 我们学过的str # dic = {'username': '太白', 'password': 123,'status': True} import json #dumps loads 主要用于网络传输,但是也可以读写文件 # 特殊的字符串 # st = json.dumps(dic,ensure_ascii=False) # print(st,type(st)) # # 反转回去 # dic1 = json.loads(st) # print(dic1,type(dic1)) # 写入文件 # l1 = [1, 2, 3, {'name': 'alex'}] # 转化成特殊的字符串写入文件 # with open('json文件',encoding='utf-8',mode='w') as f1: # st = json.dumps(l1) # f1.write(st) # 读取出来还原回去 # with open('json文件',encoding='utf-8') as f2: # st = f2.read() # l1 = json.loads(st) # print(l1,type(l1)) # 特殊的参数 l1 = [1, 2, 3, {'name': 'alex'}] # dump load 只能写入文件,只能写入一个数据结构 # with open('json文件1',encoding='utf-8',mode='w') as f1: # json.dump(l1,f1) # 读取数据 # with open('json文件1',encoding='utf-8') as f2: # l1 = json.load(f2) # print(l1,type(l1)) # 一次写入文件多个数据怎么做? # 错误示例: # dic1 = {'username': 'alex'} # dic2 = {'username': '太白'} # dic3 = {'username': '大壮'} # with open('json文件1',encoding='utf-8',mode='w') as f1: # json.dump(dic1,f1) # json.dump(dic2,f1) # json.dump(dic3,f1) # 读取数据 # with open('json文件1',encoding='utf-8') as f1: # print(json.load(f1)) # print(json.load(f1)) # print(json.load(f1)) # 正确写法: dic1 = {'username': 'alex'} dic2 = {'username': '太白'} dic3 = {'username': '大壮'} # with open('json文件1',encoding='utf-8',mode='w') as f1: # f1.write(json.dumps(dic1) + '\n') # f1.write(json.dumps(dic2) + '\n') # f1.write(json.dumps(dic3) + '\n') # with open('json文件1',encoding='utf-8') as f1: # for i in f1: # print(json.loads(i))
pickle模块:
-
只能是Python语言遵循的一种数据转化格式,只能在python语言中使用。
-
支持Python所有的数据类型包括实例化对象。
l1 = [1, 2, 3, {'name': 'alex'}] # dumps loads 只能用于网络传输 # import pickle # st = pickle.dumps(l1) # print(st) # bytes # # l2 = pickle.loads(st) # print(l2,type(l2)) # dump load 直接写入文件 # import pickle # dic1 = {'name':'oldboy1'} # dic2 = {'name':'oldboy2'} # dic3 = {'name':'oldboy3'} # # f = open('pick多数据',mode='wb') # pickle.dump(dic1,f) # pickle.dump(dic2,f) # pickle.dump(dic3,f) # f.close() # import pickle # f = open('pick多数据',mode='rb') # print(pickle.load(f)) # print(pickle.load(f)) # print(pickle.load(f)) # f.close() import pickle def func(): print('in func') # f = open('pick对象',mode='wb') # pickle.dump(func,f) # f.close() # f = open('pick对象', mode='rb') # ret = pickle.load(f) # print(ret) # ret()
import pickle with open("account", mode="rb") as f: while 1: try: res = pickle.load(f) l1.append(res) except: break 读的时候要try,因为不会自动停止超过内容就会报错
总结
json
-
序列化的结果是字符串
-
只支持部分数据类型
-
可以跨编程语言传输数据
-
不能多次读写序列化文件
pickle
-
序列化的结果是字节
-
支持python所有的数据类型
-
只在python中使用
-
可以多次读取序列化文件
dump 文件传输 dumps 网络传输
load 文件传输 loads 网络传输
# 加盐 # s2 = '19890425' # ret = hashlib.md5('太白金星'.encode('utf-8')) # ret.update(s2.encode('utf-8')) # print(ret.hexdigest()) # 84c31bbb6f6f494fb12beeb7de4777e1 # 动态的盐 # s2 = '19890425' # ret = hashlib.md5('太白金星'[::2].encode('utf-8')) # ret.update(s2.encode('utf-8')) # print(ret.hexdigest()) # 84c31bbb6f6f494fb12beeb7de4777e1
import hashlib import json # 对用户名和密码进行加密 def get_md5(username,password): encrypt = hashlib.md5(username.encode('utf-8')) encrypt.update(password.encode('utf-8')) return encrypt.hexdigest() username = 'Andy' password = '123' # 将用户信息保存到文件中: # 格式:用户名|用户名和密码加密后的字符串 with open('login.info',mode='wt',encoding='utf-8') as f: json.dump(username + '|' + get_md5(username,password),f) # 验证 name = input('input username:') passwd = input('input password:') # 反序列化出info with open('login.info',mode='rt',encoding='utf-8') as f: info = json.load(f) username,password = info.split('|') if name == username and get_md5(name,passwd) == password: print('登录成功') else: print('登录失败')
requests查看网络源码
import requests response =requests.get("https://www.baidu.com") ret.text
re模块
正则表达式的关系
[a-zA-Z] 大小写
[0-9a-z]
[0-9a-zA-Z_]
元字符 -- 匹配内容的规则 # [] [^] # \d 匹配数字 # \w 匹配字母或数字或下划线 # \s 匹配任意的空白符 # \t 匹配一个制表符 # \n 匹配一个换行符 # \b 匹配一个单词的结尾 # \W 非数字字母下划线 # \D 非数字 # \S 非空白 # [\d] \d # [\d\D] [\w\W] [\s\S] 表示匹配所有 # . 匹配除了换行符之外的所有 # [^\d] 匹配所有的非数字 # [^1] 匹配所有的非数字 # ^ 匹配一个字符串的开始 # $ 匹配一个字符串的结尾 # a表达式|b表达式 匹配a或者b表达式中的内容,如果匹配a成功了,不会继续和b匹配 # 所以,如果两个规则有重叠部分,总是把长的放在前面 # () 匹配括号内的表达式,也表示一个组
记忆元字符 : 都是表示能匹配哪些内容,一个元字符总是表示一个字符位置上的内容 \d \w \s \t \n \D \W \S [] [^] . ^ $ | ()
# 量词 # {n} 表示匹配n次 # {n,} 表示匹配至少n次 # {n,m}表示至少匹配n次,至多m次 # ? 表示匹配0次或1次 {0,1} # + 表示1次或多次 {1,} # * 表示0次或多次 {0,} # 匹配0次 # 整数 \d+ # 小数 \d+\.\d+ # 整数或小数 : \d+\.?\d* # 分组的作用 : \d+(\.\d+)?
# 判断用户输入的内容是否合法,如果用户输入的对就能查到结果,如果输入的不对就不能查到结果 # ^1[3-9]\d{9}$ # 从一个大文件中找到所有符合规则的内容 # 1[3-9]\d{9}
贪婪匹配
在量词范围允许的情况下,尽量多的匹配内容 .*x 表示匹配任意字符 任意多次数 遇到最后一个x才停下来
.*?x 表示匹配任意字符 任意多次数 但是一旦遇到x就停下来
总是在量词范围内尽量多匹配 - 贪婪 总是在量词范围内尽量少匹配 - 惰性 .*?x 匹配任意内容任意次数 遇到x就停止 .+?x 匹配任意内容至少1次 遇到x就停止
转义符
原本有特殊意义的字符,到了表达它本身的意义的时候,需要转义 有一些有特殊意义的内容,放在字符组中,会取消它的特殊意义 [().*+?] 所有的内容在字符组中会取消它的特殊意义 [a-
. 有特殊的意义,取消特殊的意义\.
取消一个元字符的特殊意义有两种方法
在这个元字符前面加\
对一部分字符生效,把这个元字符放在字符组里
[.()+?*]
正则表达式网站
http://tool.chinaz.com/regex/?qq-pf-to=pcqq.group
练习
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
练习 # 18/15位的身份证号 # 15 # 1-9 15 # [1-9]\d{14} # 18 # 1-9 16 0-9/x # [1-9]\d{16}[\dx] # [1-9]\d{16}[0-9x] #[1-9]\d{16}[0-9x]|[1-9]\d{14} # ^([1-9]\d{16}[0-9x]|[1-9]\d{14})$ # [1-9]\d{14}(\d{2}[\dx])? # ^[1-9]\d{14}(\d{2}[\dx])?$
ret = re.findall('<\w+>(\w+)</\w+>','<h1>askh930s02391j192agsj</h1>') print(ret) 结果 ['askh930s02391j192agsj']
ret = re.search('<(\w+)>(\w+)</\w+>','<h1>askh930s02391j192agsj</h1>') print(ret.group()) print(ret.group(1)) print(ret.group(2)) 结果 <h1>askh930s02391j192agsj</h1> h1 askh930s02391j192agsj
# 为什么要用分组,以及findall的分组优先到底有什么好处 exp = '2-3*(5+6)' # a+b 或者是a-b 并且计算他们的结果 ret = re.search('\d+[+]\d+',exp) print(ret) a,b = ret.group().split('+') print(int(a)+int(b)) 1.re模块结尾 2.带参数的装饰器\递归函数 如果我们要查找的内容在一个复杂的环境中 我们要查的内容并没有一个突出的 与众不同的特点 甚至会和不需要的杂乱的数据混合在一起 这个时候我们就需要把所有的数据都统计出来,然后对这个数据进行筛选,把我们真正需要的数据对应的正则表达式用()圈起来 这样我们就可以筛选出真正需要的数据了
ret = re.split('\d+','alex222wusir') 结果 # ['alex', 'wusir'] ret = re.split('\d(\d)\d','alex123wusir') 结果 # ['alex', '2', 'wusir'] print(ret)
ret = re.sub('\d+','H','alex123wusir456',1) print(ret) 结果 # alexHwusir456 # 替换掉遇到的第一个
ret = re.subn('\d+','H','alex123wusir456') print(ret) 结果 ('alexHwusirH', 2)
ret = re.match('\d+','123eva456taibai') print(ret.group()) 结果 #123 match 用户输入的内容匹配的时候,要求用户输入11位手机号码,^手机号正则$ match('手机号正则$','123eva456taibai') 规定这个字符号必须是什么样的 search('^手机号正则$','123eva456taibai') 用来寻找这个字符串中是不是含有满足条件的子内容 ret1 = re.search('^\d+','123eva456taibai') print(ret1.group()) 结果 #123
假如同一个正则表达式要被使用多次 节省了多次解析同一个正则表达式的时间 ret = re.compile('\d+') res1 = ret.search('alex37176') res2 = ret.findall('alex37176') print(res1.group()) print(res2) 结果 37176 ['37176'] findall返回的是列表
ret = re.finditer('\d+','agks1ak018093') for i in ret: print(i.group()) 结果 # 1 # 018093
(?p:<组名>正则) ?p=组名 ?:取消优先
re模块的常用方法
findall(正则,待匹配字符串,flag) : 返回所有匹配项的列表
search : 返回一个变量,通过group取到的是第一个匹配的项
finditer :返回一个迭代器,通过迭代取到的是一个变量,通过group取值
match : 从头开始找第一个,其他和search一样
compile(正则):同一个正则表达式需要多次使用的时候提前编译来节省时间
split 通过正则表达式匹配的内容进行分割
sub 替换,通过正则表达式匹配的内容来进行替换
subn 替换,在sub的基础上,返回一个元组,第一个内容是替换结果,第二个是替换次数
例题
# 标签匹配 # <h1>aksfgi031oq3h</h1><h2>sdhyqo-120v b,</h2> # re.findall('<\w+>(.*?)</\w+>',exp) # ret = re.search(r'<(\w+)>(.*?)</\1>',exp) # ret.group(2)
# 用户输入身份证号匹配 # re.match('^[1-9]\d{14}(\d{2}[\dx])?$',ident_num) # ^([1-9]\d{16}[\dx]|[1-9]\d{14})$
# 分组命名 取消分组优先 # (?P<组名>正则) (?P=组名) (?:正则)
# 2、匹配年月日日期 格式2018.12.16 # [1-9]\d{3}-(1[0-2]|0?[1-9])-([12]\d|3[01]|0?[1-9]) # [1-9]\d{3}-(1[0-2]|0?[1-9])-([12]\d|3[01]|0?[1-9]) # [1-9]\d{3}(?P<sub>[^\d])(1[0-2]|0?[1-9])(?P=sub)([12]\d|3[01]|0?[1-9])