Python模块Ⅱ
Python模块2
part3
模块的分类:
- 内置模块200种左右:python自带的模块,time os sys hashlib等
- 第三方模块6000种左右:需要pip install beautiful_soup request Django
- 自定义模块:自己写的py文件
- from . import versions : 带相对导入的是不可以直接运行的
from...import...:copy一份过来(对于函数来说,就是引用函数名的内存地址)
他不是在本文件完全创建一个新的函数,而是创建一个变量read1但是read1指向的函数还是沿用tbjx的read1的内存地址
part4
软件开发规范
bin --> 启动文件
conf --> 配置文件 register_path 静态的路径,数据库连接设置 变量不能改变,只能引用
core ----> 主逻辑的
db --> 跟数据相关
lib--> 公共组件:装饰器,日志函数
log ---> 日志文件
part5
正则表达式元字符(重要)
- 什么是正则表达式:一套规则-匹配字符串
- 能做什么(常见的两个场景)
- 检测一个输入的字符串是否合法--web开发项目表单验证
用户输入一个内容的时候,我们要提前做检测
能够提高程序的效率并且减轻服务器的压力 - 从一个大文件中找到所有符合规则的内容
能够高效的从一大段文字中找到符合规则的内容--日志分析/爬虫
- 正则规则
字符组[][^]
描述的是一个位置上能出现的所有可能性
接受范围,可以描述多个范围,连着写就可以了
[abc]一个中括号只表示一个字符位置
匹配a或者b或者c
[0-9]根据ascil进行范围匹配
[a-z]小写字母
[A-Z]大写字母
[a-zA-Z]大小写字母
[0-9a-z]数字小写
[0-9a-zA-Z]数字小写大写字母
在正则表达式中能够帮助我们表示匹配的内容的符号都是正则中的元字符
[0-9]<--->\d表示匹配一位任意数字(与[0-9]等同)digit
[0-9a-zA-Z]---->\w(表示匹配一位任意数字字母下划线)word
空格-->
tab-->\t
enter-->\n
空格,tab,enter-->\s表示所有空格
\W非数字字母下划线
\D非数字
\S非空白
[\d\D][\w\W][\s\S]表示匹配所有
.匹配除了换行符之外的所有(但是可以设置)
^匹配一个字符串的开始
$匹配一个字符串的结尾
a表达式|b表达式 或 匹配a表达式或者b表达式中的内容,如果a匹配成功了不会和b进行匹配,如果规则有重叠部分长的放在前面
() 分组 #约束|描述的内容的范围问题
正则表达式量词
量词必须跟在元字符后面,并且只能约束前面一个元字符
{n}表示匹配n次
{n,}表示匹配至少n次
{n,m}表示至少匹配n次至多m次
?表示匹配0次或者1次{0,1}
+表示匹配1次或多次{1,}
*表示匹配0次或多次{0,}
0--?-1---------------------------------+------------------------无穷>(整个数轴*)
贪婪匹配/惰性匹配/转义符
- 贪婪匹配
- 在量词范围允许的情况下,尽量多的匹配内容
- .*x表示匹配任意字符任意多次数遇到最后一个x才停下来
- 非贪婪(惰性)匹配【量词?】(尽可能少的匹配)
- .*?x表示匹配任意字符任意多次数但是一旦遇到x就停下来
- 转义符(\)
- 原本有特殊意义的字符,到了表达它本身的意义的时候,需要转义. \n
- 有一些有特殊意义的内容,放在字符组中,会取消他的特殊意义
- [().*+?]放在字符组中会取消他的特殊意义
- [a-c] - 在字符组中表示范围,如果不希望它表示范围,需要转义,或者放在字符组的最前面或最后面
re模块
import re
ret=re.findall('\d+','19sda256984as57sd40')
print(ret) #找所有符合规则的返回一个列表
ret1=re.search('\d+','sda256984as57sd40')#找一个就返回
print(ret1)#变量
print(ret1.group())
findall还是按照完整的正则进行匹配,总是只显示括号里匹配到的内容
ret=re.findall('9(\d)\d','1925sda256984as57sd40')
search还是按照完整的正则进行匹配,显示也显示匹配到的第一个内容,但是我们可以通过给group方法传参数,来获取具体分组的内容
ret1=re.search('9(\d)(\d)','sda25698425as57sd40')#找一个就返回
print(ret1)#变量
if ret1:
print(ret1.group())
print(ret1.group(1))
print(ret1.group(2))
findall
取所有符合条件的,优先显示分组中的
取消优先分组(?:正则)
search只取第一个符合条件的,没有优先显示这件事
得到的结果是一个变量
变量.group()的结果完全和变量.group(0)的结果一致
变量.group(n)的形式来指定获取第n个分组中匹配到的内容
- 如果我们要查找的内容在一个复杂的环境中
- 我们要查的内容并没有一个突出的与众不同的特点甚至会和不需要的杂乱的数据混合在一起
- 这个时候我们就需要把所有的数据都统计出来,然后对这个数据进行筛选,把我们真正需要的数据对应的正则表达式用()圈起来
- 这样我们就可以筛选出真正需要的数据了
re模块中的flag参数(第三个参数[可选])
re.I
IGNORECASE
忽略字母大小写
re.L
LOCALE
影响 “w, “W, “b, 和 “B,这取决于当前的本地化设置。
re.M
MULTILINE
使用本标志后,‘^’和‘$’匹配行首和行尾时,会增加换行符之前和之后的位置。
re.S
DOTALL
使 “.” 特殊字符完全匹配任何字符,包括换行;没有这个标志, “.” 匹配除了换行符外的任何字符。
re.X
VERBOSE
当该标志被指定时,在 RE 字符串中的空白符被忽略,除非该空白符在字符类中或在反斜杠之后。
它也可以允许你将注释写入 RE,这些注释会被引擎忽略;
注释用 “#”号 来标识,不过该符号不能在字符串或反斜杠之后。
part 6
re模块2
- 解决findall,search空间/时间问题
1.compile()**(会先进行预编译,节省代码时间的工具)
假如同一个正则表达式要使用多次
节省了多次解析同一个正则表达式的时间
如果没有重复使用同一个正则,也不能节省时间
2.finditer()**节省空间(迭代器)(在结果特别多时用这个)
ret=re.finditer('\d+','jsdiausd548l521h3a5jsadj')
for i in ret:
print(i.group()) #i是一个变量
3.split()切割
ret=re.split('\d+','alex222hahaha')
4.sub()替换
ret=re.sub('\d+','HH','alex123haha456')
5.subn()替换返回一个元组(第一个参数替换的东西,第二个参数替换的次数)
ret=re.subn('\d+','HH','alex123haha456') #('alexHHhahaHH',2)
6.match()*从头找(等同于search前面加个^)
match用户输入的内容匹配的时候,要求用户输入11位手机号码,^手机号码正则$
match('手机号正则$','ss')规定这个字符号必须是什么样的
search('^手机号正则$','ss')用来寻找是否含有满足条件的子内容
ret=re.match('\d+','123evaltaibai456')
re模块3
- 分组命名
- (?P<名字>正则表达式)
- ret.group('名字')
ret=re.search('\d(\d)\d(\w+?)(\d)(\w)\d(\d)\d(?P<name1>\w+?)(\d)(\w)\d(\d)\d(?P<name2>\w+?)(\d)(\w)',
'123abc45678agsf_123abc45678agsf123abc45678agsf')
print(ret.group('name1'))
print(ret.group('name2'))
- 取消分组优先:(?:正则)
- 不希望他在python中转义用r'',加r取消转义
分组的索引引用(使用的不多)python中\1有特殊意义,可以通过在前面加r取消特殊意义
import re
exp='<abc>akda65485*11</abc>asdjasd5a</abd>'
ret=re.search(r'<(\w+)>.*?</\1>',exp)#\1取消在python中的特殊意义,加r体现在正则中的意义
递归函数
recursion 递归
递归的最大深度1000层(官网规定):节省内存空间
1.递归要尽量控制次数
2.循环和递归的关系
递归不是万能的
递归比起循环来说更占内存
可以修改递归的最大深度
import sys
sys.setrecursionlimit(2000)
一个递归函数想要结束,必须再函数内写一个return,并且return的条件必须是一个可以达到的条件
并不是函数中有return,return的结果就一定能够再调用函数的外层接受到
def func1 (count):
count+=1
print(count)
if count==5:
return5
ret=func1(count)
return ret #上面两段等同于return func1(count)(先执行再return)
#print(count,ret)
#return ret
print('-->',func1(1))
带参数的装饰器
def xxx(*args):#这里的参数是装饰器的参数
def wrapper(f):#这里的f是被装饰的函数
def inner(*args,**kwargs):#这里的*args,**kwargs是被装饰函数的参数
""""添加额外的功能:执行被装饰函数之前的操作"""
ret=f(*args,**kwargs)
""""添加额外的功能:执行被装饰函数之后的操作"""
return ret #这里的ret是被装饰函数的返回值
return inner #这里inner等同于调用被装饰函数
return wrapper
- 为什么不能改变原函数的调用方式
- 开放封闭原则
- 我们提前写好一个功能,让别人使用的时候能够直接使用就能完成相应的功能
@logger # show_goods=logger(show_goods)
@logger('ashash')
#log=logger('ashash')
#@log-->show_goods=log(show_goods)
#@logger('ashash')---------> show_goods=logger('ashash')(show_goods)
part7
shutil模块
1.copy文件
shutil.copy2('原文件','现文件')
2.copy目录
shutil.copytree("原目录","新目录") #,ignore=shutil.ignore_patterns("*.pyc"))#[忽略什么文件不想copy]
3.rmtree()删除文件
shutil.rmtree('文件',ignore_errors=True)#ignore_errors忽略错误
4.move()移动copy过来并把之前的删除掉
shutil.move('原文件','现文件',copy_function=shutil.copy2)
5.shutil.disk_usage()查看当前磁盘使用空间
total,used,free=shutil.disk_usage(".")#.查看当前所在磁盘
print(f'当前磁盘共:{total/1073741824}GB,已使用{used/1073741824}GB,剩余{free/1073741824}GB')
6.shutil.mark_archive()压缩文件【一般用来手动压缩文件】
shutil.make_archive('haha_z','zip','D:\老男孩python22期代码及笔记\day21\haha')
7.shutil.unpack_archive()解压文件
shutil.unpack_archive('haha_z.zip')
shutil.unpack_archive('haha_z.zip',r'D:\老男孩python22期代码及笔记\day21\测试')
logging模块
- 使用日志:
- 用来记录用户的行为---数据分析
- 用来记录用户的行为---操作审计
- 排查代码中的错误
import logging
输出内容是有等级的:默认处理warning级别以上的所有信息
logging.debug('debugmessage') #调试
logging.info('infomessage') #信息
logging.warning('warningmessage') #警告
logging.error('errormessage') #错误
logging.critical('criticalmessage') #批判性的
logging模块输出到屏幕/文件
开始写
fh=logging.FileHandler('tmp.log',encoding='utf-8')#输出到文件
sh=logging.StreamHandler()#输出到屏幕
#logging.basicConfig#asctime:时间name:什么用户levelname:日志等级lineno:哪一行module:什么文件message:自己打印什么信息
logging.basicConfig(
format='%(asctime)s-%(name)s-%(levelname)s[line:%(lineno)s]-%(module)s:%(message)s',
datefmt='%Y-%m-%d%H:%M:%S%p',
level=logging.DEBUG,
handlers=[fh,sh]
)
logging.debug('debug')
logging.warning('warningmessagetest2')
logging.error('errormessagetest2')
logging.critical('criticalmessagetest2')
程序工作一段时间后写
- 日志的切分
import time
from logging import handlers
#每maxBytes=1024切一个文件backupCount=5:最多保留5个文件。在第6个时删除第一个文件
rh=handlers.RotatingFileHandler('myapp.log',maxBytes=1024,backupCount=5)#按照大小进行切割
#when='s':按照秒来切interval=5:每5秒切一个
fh=handlers.TimedRotatingFileHandler(filename='x2.log',when='s',interval=5,encoding='utf-8')#按照时间切割
fh=logging.FileHandler('tmp.log',encoding='utf-8') # 输出到文件
sh=logging.StreamHandler() # 输出到屏幕
logging.basicConfig(
format='%(asctime)s-%(name)s-%(levelname)s[line:%(lineno)s]-%(module)s:%(message)s',
datefmt='%Y-%m-%d%H:%M:%S%p',
level=logging.DEBUG,
handlers=[fh,sh]
)
for i in range(1,10):
time.sleep(1)
logging.error(f'error{str(i)}')