python基础5--模块
1、模块分类
-
内置模块-----python内部提供的功能
-
第三方模块-----下载/安装/使用
# 把pip.exe 所在的目录添加到环境变量中。 pip install 要安装的模块名称 # pip install xlrd # 临时更换pip源 pip install some-package==版本 -i https://mirrors.aliyun.com/pypi/simple/ # 从文件安装 pip install -r requirements.txt # 导出到文件 pip freeze -r requirements.txt # 卸载模块 pip uninstall Package # 另一种安装方式 python -m pip install Package
-
自定义模块
-
什么是模块?
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 *
2、内置模块
1. sys
python解释器相关的数据。
-
sys.getrefcount , 获取一个值的引用计数
-
sys.getrecursionlimit , python默认支持的递归数量
-
sys.stdout.write --> print
-
sys.exit(0)退出程序
sys.argv
获取用户执行脚本时,传入的参数。得到的是一个列表,第一个元素是脚本文件
# 删除用户执行脚本传入的目录
import sys
import shutil
path = sys.argv[1]
shutil.rmtree(path)
sys.path
默认Python去导入模块时,会按照sys.path中的路径挨个查找。
# 将当前项目根目录加入sys.path,方便模块导入
import os,sys
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
sys.modules
sys.modules是一个全局字典,该字典是python启动后就加载在内存中。每当程序员导入新的模块,sys.modules都将记录这些模块。字典sys.modules对于加载模块起到了缓冲的作用。当某个模块第一次导入,字典sys.modules将自动记录该模块。当第二次再导入该模块时,python会直接到字典中查找,从而加快了程序运行的速度。字典sys.modules具有字典所拥有的一切方法,可以通过这些方法了解当前的环境加载了哪些模块
常用sys.modules[__name__]
获取该文件对象,反射获取文件中任意内容
import sys
def func():
pass
ret=sys.modules
print(getattr(sys.modules[__name__],'func'))
2、os
和操作系统相关的数据。
-
os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False
-
os.stat('xx.mp4').st_size 获取文件大小
-
os.path.getsize() 获取文件大小
-
os.path.abspath() 获取一个文件的绝对路径
-
os.path.basename() 获取文件名
-
os.path.sep 路径分隔符
import os v = os.path.abspath(__file__) print(v) # D:\code\project_menu\bin\run.py
-
os.path.dirname ,获取路径的上级目录
import os v = os.path.abspath(__file__) print(os.path.dirname(v)) # D:\code\project_menu\bin
-
os.path.join ,路径的拼接 ,根据不同操作系统加分隔符
import os path = r"D:\code\project_menu\bin" v = 'n.txt' result = os.path.join(path,v) print(result) result = os.path.join(path,v,v,v) print(result)
-
os.listdir , 查看一个目录下所有的文件及文件夹名字【第一层】
import os result = os.listdir(r'D:\code\project_menu') print(result) # ['.idea', 'bin', 'conf', 'db', 'lib', 'log', 'log.txt', 'src']
-
os.walk , 查看一个目录下所有的文件【所有层】
import os path=r'D:\code\project_menu' for root, dirs, files in os.walk(path): # root正在查看的目录 dirs此目录下的文件夹 files此目录下的文件 for file in files: abspath = os.path.join(root,file) print(abspath)
-
os.makedirs,创建目录和子目录
import os file_path = r'D:\code\project_menu\log\log1.log' file_folder = os.path.dirname(file_path) if not os.path.exists(file_folder): os.makedirs(file_folder) with open(file_path,mode='w',encoding='utf-8') as f: f.write('hello')
-
os.rename(src, dst),重命名
该方法 可以重命名 文件 和目录,
如果 src参数 对应文件或目录,不存在,会保错,
如果 dst 参数 对应文件或目录,已经存在,也会报错 -
os.system() 执行系统命令
import os os.system('cd /usr/local && mkdir aaa.txt') # 或者 os.system('cd /usr/local ; mkdir aaa.txt')
-
os.rmdir() 只能删除空文件夹
补充
转义
v1 = r"D:\code\s21day14\n1.mp4" (推荐)
print(v1)
v2 = "D:\\code\\s21day14\\n1.mp4"
print(v2)
工作目录
print(os.getcwd())
print(__file__)
# D:\code\project_menu\bin
# D:/code/project_menu/bin/run.py
进度条
import time
for i in range(100):
msg = '进度条跑到%s%%\r' %i # \r 光标回到当前行的起始位置(不是覆盖.,是清空)
print(msg , end = '')
time.sleep(0.5) # 暂停0.5s后再运行
import os
# 1. 读取文件大小(字节)
file_size = os.stat('xx.mp4').st_size
# 2.一点一点的读取文件
read_size = 0
with open('xx.mp4',mode='rb') as f1,open('a.mp4',mode='wb') as f2:
while read_size < file_size:
chunk = f1.read(1024) # 每次最多去读取1024字节
f2.write(chunk)
read_size += len(chunk)
val = int(read_size / file_size * 100)
print('%s%%\r' %val ,end='')
3、shutil
import shutil
shutil.rmtree( src ) 递归删除一个目录以及目录内的所有内容
shutil.move( src, dst) 移动文件或重命名
生成压缩文件:
shutil.make_archive(base_name, 'gztar', root_dir, [base_dir)
- base_name : 创建的目标文件名,包括路径,减去任何特定格式的扩展。
- format : 压缩包格式。”zip”, “tar”, “bztar”或”gztar”中的一个。
- root_dir : 需要打包的文件夹路径。打包完成时存储在上一级目录。
- base_dir : 使用后会将base_dir作为路径,解压后有个有层级的文件夹,而仅非只有单独的打包内容。
解压文件:
shutil.unpack_archive(filename[, extract_dir[, format]])
- filename是压缩文档的完整路径
- extract_dir是解压缩路径,默认为当前目录。
- format是压缩格式。默认使用文件后缀名代码的压缩格式。”zip”, “tar”, “bztar”或”gztar”中的一个。
4、json
json是一个特殊的字符串。 【长的像列表/字典/字符串/数字/真假】
# json格式 :
1.所有的字符串都是双引号
2.最外层只能是列表或者字典
3.只支持 int float str list dict bool
4.存在字典字典的key只能是str
5.不能连续load多次
- dumps序列化 & load反序列化
import json
# 序列化,将python的值转换为json格式的字符串。
v = [12,3,4,{'k1':'v1'},True,'yhp']
v1 = json.dumps(v)
print(v1)
# 反序列化,将json格式的字符串转换成python的数据类型
v2 = '["yhp",123]'
print(type(v2))
v3 = json.loads(v2)
print(v3,type(v3))
json.dumps 序列化时对中文默认使用的ascii编码.想输出真正的中文需要指定ensure_ascii=False:
v = {'k1':'yhp','k2':'杰克'}
import json
val = json.dumps(v,ensure_ascii=False)
print(val)
-
dump序列化并写入文件
import json v = {'k1':'yhp','k2':'杰克'} f = open('x.txt',mode='w',encoding='utf-8') json.dump(v,f,ensure_ascii=False) f.close()
-
load从文件读取并反序列化
import json f = open('x.txt',mode='r',encoding='utf-8') res=json.load(f) f.close() print(res)
5、pickle
- json,优点:所有语言通用;缺点:只能序列化基本的数据类型 list/dict/int...
- pickle,优点:python中所有的东西都能被他序列化(socket对象);缺点:序列化的内容只有python认识。
用法同json
6、time&datetime
UTC/GMT:世界时间
本地时间:本地时区的时间。
-
time模块
- time.time() ,时间戳:从1970-1-1 00:00 起始 #1590660513.8918743
- time.sleep(10),等待秒数。
- time.timezone
-
datetime模块
import time from datetime import datetime,timezone,timedelta # 获取datetime格式时间 v1 = datetime.now() # 当前本地时间 print(v1) tz = timezone(timedelta(hours=7)) # 当前东7区时间 v2 = datetime.now(tz) print(v2) v3 = datetime.utcnow() # 当前UTC时间 print(v3) # 把datetime格式转换成字符串 v1 = datetime.now() print(v1,type(v1)) val = v1.strftime("%Y-%m-%d %H:%M:%S") print(val) # 字符串转成datetime v1 = datetime.strptime('2011-11-11','%Y-%m-%d') print(v1,type(v1)) # datetime时间的加减 v1 = datetime.strptime('2011-11-11','%Y-%m-%d') v2 = v1 - timedelta(days=140) date = v2.strftime('%Y-%m-%d') print(date) # 时间戳和datetime关系 ctime = time.time() print(ctime) v1 = datetime.fromtimestamp(ctime) print(v1) v1 = datetime.now() val = v1.timestamp() print(val)
7、 hashlib
- 将指定的 “字符串” 进行加密。
import hashlib
def get_md5(data):
#可以选择加盐 obj = hashlib.md5("salt".encode('utf-8'))
obj = hashlib.md5()
obj.update(data.encode('utf-8'))
result = obj.hexdigest()
return result
val = get_md5('123')
print(val)
- 校验文件一致性,分多次update,最终结果相同
import hashlib,os
path1 = r'xxx.mp4'
path2 = r'xxxxx.mp4'
def file_md5(path):
size = os.path.getsize(path)
md5 = hashlib.md5()
with open(path,mode='rb') as f:
while size>1024:
content = f.read(1024)
md5.update(content)
size -=1024
else:
content = f.read(size)
md5.update(content)
size = 0
return md5.hexdigest()
print(file_md5(path1)== file_md5(path2))
import hashlib
md5 = hashlib.sha1('盐'.encode())
md5.update(b'str')
print(md5.hexdigest())
8、random
import random
print(random.uniform(1,5)) #返回随机实数
print(random.randint(1,5)) #返回随机整数
print(random.choice([1,2,3,4,5])) #返回列表随机数
print(random.sample([1,2,3,4],3)) #从列表随机抽取3个
l=[1,2,3,4]
random.shuffle(l) #随机打乱列表
print(l)
# 4.005596196642935
# 3
# 2
# [4, 3, 1]
# [2, 1, 4, 3]
9、 functools
functools.reduce()
functools.partial()
functools.wraps()
10、 re
到底什么是正则表达式(regex)?
在编写处理字符串的程序或网页时,经常有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。
常用元字符
\d 表示所有的数字
\w 字母/数字/下划线
\s 空白(空格/换行符/制表符)
\t 匹配制表符 Tab
\n 匹配换行符
. 表示除了换行符之外的任意内容
\D 表示所有的非数字
\W 表示除 数字字母下划线之外的所有字符
\S 表示非空白
[] 字符组 :只要在中括号内的所有字符都是符合规则的字符
[^xyz] 非字符组 :只要在中括号内的所有字符都是不符合规则的字符
^ 表示一个字符的开始
$ 表示一个字符的结束
| 表示或,注意,如果两个规则有重叠部分,总是长的在前面,短的在后面
() 表示分组,给一部分正则规定为一组,|这个符号的作用域就可以缩小了
[\d\D] [\W\w] [\S\s] 匹配所有一切字符
常用限定符(量词)
代码/语法 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
重复n次 | |
重复n次或更多次 | |
重复n到m次 |
匹配一个整数或者小数 \d+.\d+|\d+ \d+.?\d* \d+(.\d+)?
# 以a开头,由至少一个字母组成的字符串
# ^a[a-zA-Z]+
# ^a[a-zA-Z]*
# 以1开头,中间3-5个数字,如果中间位置超过5个数字,则整个字符串不匹配
# ^1\d{3,5}$
贪婪匹配
默认采用回溯算法,贪婪匹配,总是会在符合量词条件的范围内尽量多匹配.
adljdkjsljdlj<.+> 会匹配到整个字符串,而不是
惰性匹配
总是匹配符合条件范围内尽量小的字符串
格式: 元字符 量词 ? x
表示按照元字符规则在量词范围内匹配,一旦遇到x就停止
# 身份证号
# 15位 全数字 首位不为0
# 18位 前17位全数字 首位不为0 最后一位可能是x和数字
# [1-9](\d{14}|\d{16}(\d|x))
# [1-9](\d{16}[\dx]|\d{14})
# [1-9]\d{14}(\d{2}[\dx])?
表达式中转义符
正则表达式中的转义符在python的字符串中也刚好有转义的作用,但是正则表达式中的转义符和字符串中的转义符并没关系,且还容易有冲突,为了避免这种冲突,我们所有的正则都以在工具中的测试结果为结果,然后只需要在正则和待匹配的字符串外面都加r即可.
- \d \s \w \t \n→python字符串中
- 匹配
()[]{}\d
等,需要加\转义
re正则模块
-
re.findall('正则表达式',字符串)
匹配字符串中所有符合规则的项,并返回一个列表,如果未匹配到返回空列表 -
re.search('正则表达式',字符串)
匹配字符串中满足条件的第一项,返回一个对象,用group方法取值;如果不能匹配上返回None,group方法会报错.
if ret:
print(ret.group()) # 如果是对象,那么这个对象内部实现了group,所以可以取值
# 如果是None,那么这个对象不可能实现了group方法,所以报错
-
ret.match('正则表达式',字符串)
会从头匹配字符串中取出从第一个字符开始是否符合规则,如果符合,就返回对象,用group取值,如果不符合,就返回None
match = search + ^正则
-
re.finditer('正则表达式',字符串)
返回一个迭代器,迭代出来的每一项都是一个对象,然后group取值
在查询的结果超过1个的情况下,能够有效的节省内存,降低空间复杂度,从而也降低了时间复杂度
-
re.compile('正则表达式')
正则表达式编译成python语言,供多次使用
ret = re.compile('\d3') r1=ret.search("djasjd5a646")
-
re.split()
re.split('\d\d','alex83wusir74taibai') #不保存被分割的内容 [,1]第几个分割 re.split('\d(\d)','alex83wusir74taibai') # 默认自动保留分组中的内容
-
re.sub('正则表达式',替换内容,字符串,[序号])
返回字符串 -
re.subn('正则表达式',替换内容,字符串,[序号])
返回元组(替换后字符串,替换个数)
分组
-
分组命名
(?P<组名>正则) -
引用分组
(?P=组命) -
findall和分组
- 优先显示分组中的内容,其他内容内容返回空字符串
""
- (?:)取消这个分组的优先⭐ ,量词为了约定多个字符加括号,会产生此情况.
import re ret = re.findall('\d+(\.\d+)?','21.234+2') print(ret) #运行结果:['.234', '']
import re ret = re.findall('\d+(?:\.\d+)?','21.234+2') print(ret) #运行结果:['21.234', '2']
- 优先显示分组中的内容,其他内容内容返回空字符串
小技巧:有的时候我们想匹配的内容包含在不相匹配的内容当中,这个时候只需要把不想匹配的先匹配出来,再通过手段去掉.
import re
ret=re.findall(r"\d+\.\d+|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
print(ret)
ret.remove('')
print(ret)
#运行结果:
#['1', '2', '60', '', '5', '4', '3']
#['1', '2', '60', '5', '4', '3']
- split和分组
会保留分组中本来应该被切割掉的内容 - search和分组
通过索引取 obj.group(1)
通过组名取 obj.group('组名')
# 1.找出<h1>123fh</h1><h2>hado</h2>中所有标签内的字符串 爬虫
import re
ret = re.findall('<.*?>(.*?)<.*?>','<h1>123fh</h1><h2>hado</h2>')
print(ret)
# 2.找出四则运算表达式中的第一个乘除法
# \d*\d|\d/\d
# \d+(\.\d+)?[*/]\d(\.\d+)?
# \d+(\.\d+)?[*/]-?\d(\.\d+)?
import re
ret = re.search('\d+(\.\d+)?[*/]-?\d(\.\d+)?', '2-3*-5/6')
print(ret.group())
# 3.检测用户输入的内容是否是一个合法的身份证号 网页的合法输入(手机号码 qq号码 银行卡号 邮箱地址)
# '^[1-9]\d{14}(\d{2}[\dx])?$'
import re
inp = input('>>>').strip()
re.match('[1-9]\d{14}(\d{2}[\dx])?$', inp) # 首选
re.search('^[1-9]\d{14}(\d{2}[\dx])?$', inp)
re.findall('^[1-9]\d{14}(\d{2}[\dx])?$', inp)
ret=re.findall(pattern,info,re.S) #允许.匹配下一行
使'.'特殊字符匹配任何字符,包括换行 ;如果没有此标志, '.'将匹配任何内容除换行符。
collections
在内置数据类型(dict,list,set,tuple)的基础上,collections 模块还提供了几个额外的数据类型:
1.namedtuple:生成可以使用名字来访问元素内容的tuple
2.deque:双向队列(两头都可进可出,但是不能取中间的值),可以快速的从另外一侧追加和推出对象
3.Counter:计数器,主要用来计数
4.OrderedDict:有序字典
5.defaultdict:带有默认值的字典
1、namedtuple
之前我们获取元组中的值,我们通过索引来取,但是通过可命名的元组,我们可以通过名称来获取值。
from collections import namedtuple # 可命名元组
# namedtuple('名称',‘属性list’)
Circle = namedtuple('Circle', ['x', 'y', 'r'])#用坐标和半径表示一个圆
c=Circle(2,3,5)
print('坐标:({},{}),半径:{}'.format(c.x,c.y,c.r))
2、deque
- 单向队列queue
import queue
q = queue.Queue()
q.put(11)
print(q.get())
- 双向队列
from collections import deque
q = deque(['a', 'b', 'c'])
# 添加元素
q.append('d')
print(q)
# 从左边添加
q.appendleft('k')
print(q)
# 删除元素
q.pop()
print(q)
# 从左边删除元素
q.popleft()
print(q)
3、OrderedDict
from collections import OrderedDict #有序字典
info = OrderedDict()
info['k1'] = 123
info['k2'] = 456
print(info.keys())
print(info.values())
print(info.items())
# out:
# odict_keys(['k1', 'k2'])
# odict_values([123, 456])
# odict_items([('k1', 123), ('k2', 456)])
4、defaultdict
当我使用普通的字典时,用法一般是dict={},添加元素的只需要dict[element] =value即,调用的时候也是如此,dict[element] = xxx,但前提是element字典里,如果不在字典里就会报错。
defaultdict的作用是在于,当字典里的key不存在但被查找时,返回的不是keyError而是一个默认值
defaultdict接受一个工厂函数factory_function作为参数,这个factory_function可以是list、set、str等等,作用是当key不存在时,返回的是工厂函数的默认值,比如list对应[ ],str对应的是空字符串,set对应set( ),int对应0。
from collections import defaultdict
dict1 = defaultdict(int)
dict2 = defaultdict(set)
dict3 = defaultdict(str)
dict4 = defaultdict(list)
dict1[2] ='two'
print(dict1[1])
print(dict2[1])
print(dict3[1])
print(dict4[1])
0
set()
[]
还可以自己定义:
from collections import defaultdict
dd = defaultdict(lambda: 'N/A')
dd['key1'] = 'abc'
print(dd['key1']) # key1存在
print(dd['key2']) # key2不存在,返回默认值