常用模块

常用模块

模块

定义:在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。

为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。

在Python中,一个.py文件就可以称之为一个模块。

优点

1.最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。

2.使用模块还可以避免函数名和变量名冲突。每个模块有独立的命名空间,因此相同名字的函数和变量完全可以分别存在不同的模块中,所以,我们自己在编写模块时,不必考虑名字会与其他模块冲突。

分类

模块分为三种:

内置标准模块(又称标准库)执行help(‘modules’)查看所有python自带模块列表

第三方开源模块,可通过pip install 模块名 联网安装

自定义模块

模块的导入与调用

import module_a  #导入
from module import xx
from module.xx.xx import xx as rename #导入后重命令
from module.xx.xx import *  #导入一个模块下的所有方法,不建议使用
module_a.xxx  #调用

 

模块查找路径

发现,自己写的模块只能在当前路径下的程序里才能导入,换一个目录再导入自己的模块就报错说找不到了, 这是为什么?

这与导入模块的查找路径有关

import sys

print(sys.path)

输出(注意不同的电脑可能输出的不太一样)

['', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', 
'/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', 
'/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', 
'/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages']

你导入一个模块时,Python解释器会按照上面列表顺序去依次到每个目录下去匹配你要导入的模块名,只要在一个目录下匹配到了该模块名,就立刻导入,不再继续往后找。

注意:列表第一个元素为空,即代表当前目录,所以你自己定义的模块在当前目录会被优先导入。

我们自己创建的模块若想在任何地方都能调用,那就得确保你的模块文件至少在模块路径的查找列表中。

我们一般把自己写的模块放在一个带有“site-packages”字样的目录里,我们从网上下载安装的各种第三方的模块一般都放在这个目录。

 

os模块

os 模块提供了很多允许你的程序与操作系统直接交互的功能。

import os
os.getcwd()  # 返回当前工作目录,即当前脚本的工作路径

os.listdir()  # 返回指定路径下所有的目录名和文件名

os.path.basename() # 获取文件名

os.path.join(dir,fliename)  # 将目录名和文件名结合起来

os.path.split()  # 将文件名和目录分开,返回一个元组

os.path.dirname()  #返回指定路径的上一层路径
print(os.path.dirname('D:\OldBoy_Luffy\代码基础练习\chapter4\os_sys.py'))  
# ('D:\\OldBoy_Luffy\\代码基础练习\\chapter4', 'os_sys.py')


os.path.abspath()  # 返回绝对路径
#常用用法
os.path.abspath(__file__)  # 当前文件的绝对路径,包含文件名
#__fil__是当前目录起的相对路径 在终端中打印__file__显示的是相对路径   pycharm是从根目录开始的,因此在pycharm中__file__就是绝对路径

os.path.isfile()  # 检验给出的路径是否是一个文件
os.path.isdir()  # 检验给出的路径是否是一个目录
os.path.isabs()  # 检验路径是否为绝对路径
os.path.exists()  # 检验给出的路径是否真的存在

os.stat(filr)  # 获取文件属性

os.remove()  # 用来删除一个文件
os.removedirs()  # 删除多个目录

os.path.splitext(')  # 分离扩展名
print(os.path.splitext('\chapter4\os_sys.py'))  # ('\\chapter4\\os_sys', '.py')

os.getenv("HOME")  # 读取操作系统环境变量HOME的值
os.environ  # 返回操作系统所有的环境变量
os.environ.setdefault('HOME','/home/alex')  # 设置系统环境变量,仅程序运行时有效

os.linesep  # 给出当前平台使用的行终止符
os.name   # 指示你正在使用的平台  对于Windows,它是'nt',而对于Linux/Unix用户,它是'posix'

os.rename(old, new) # 重命名
os.makedirs(r“c:\python\test”) # 创建多级目录
os.mkdir(“test”) # 创建单个目录

os.chmod(file) # 修改文件权限与时间戳
os.path.getsize(filename) # 获取文件大小

os.chdir(dirname)  # 改变工作目录到dirname

os.get_terminal_size()  # 获取当前终端的大小
os.kill(10884,signal.SIGKILL)  # 杀死进程

 

 

 

sys模块

sys.argv           命令行参数List,第一个元素是程序本身路径
sys.exit(n)        退出程序,正常退出时exit(0)
sys.version        获取Python解释程序的版本信息
sys.maxint         最大的Int值
sys.path 返回模块的搜索路径,模块导入时按照搜索路径依次搜索模块,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称 sys.stdout.write(
'please:') #标准输出 , 引出进度条的例子, 注,在py3上不行,可以用print代替 val = sys.stdin.readline()[:-1] #标准输入 sys.getrecursionlimit() #获取最大递归层数 当递归次数过多会导致栈溢出 sys.setrecursionlimit(1200) #设置最大递归层数 sys.getdefaultencoding() #获取解释器默认编码 sys.getfilesystemencoding #获取内存数据存到文件里的默认编码

 

 

time模块

在Python与时间处理有关的模块是time,datetime。

我们写程序时对时间的处理可以归为以下3种:

时间的显示,在屏幕显示、记录日志等

时间的转换,比如把字符串格式的日期转成Python中的日期类型

时间的运算,计算两个日期间的差值等

在Python中,通常有这几种方式来表示时间:

时间戳(timestamp), 表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。例子:1554864776.161901

格式化的时间字符串,比如“2020-10-03 17:54”

元组(struct_time)共九个元素。由于Python的time模块实现主要调用C库,所以各个平台可能有所不同,mac上:time.struct_time(tm_year=2020, tm_mon=4, tm_mday=10, tm_hour=2, tm_min=53, tm_sec=15, tm_wday=2, tm_yday=100, tm_isdst=0)

索引(Index)    属性(Attribute)    值(Values)
0     tm_year(年)                 比如2011
1     tm_mon(月)                  1 - 12
2     tm_mday(日)                 1 - 31
3     tm_hour(时)                 0 - 23
4     tm_min(分)                  0 - 59
5     tm_sec(秒)                  0 - 61
6     tm_wday(weekday)            0 - 6(0表示周日)
7     tm_yday(一年中的第几天)       1 - 366
8     tm_isdst(是否是夏令时)        默认为-1

 

UTC时间

UTC(Coordinated Universal Time,世界协调时)亦即格林威治天文时间,世界标准时间。在中国为UTC+8,又称东8区。

 

time模块的方法

time.localtime()  # 将一个时间戳转换为当前时区的struct_time 没有参数就默认为当前时间

time.gmtime()  # 将一个时间戳转换为UTC时间的struct_time

time.time()  # 返回当前时间的时间戳
time.mktime()  # 将一个struct_time 转换为时间戳、

time.sleep()  # 线程推迟指定时间后再运行

time.asctime()  # 把一个时间元组转化成’Sun Oct 1 12:04:38 2019的形式

time.ctime()  # 把一个时间戳转换为’Sun Oct 1 12:04:38 2019的形式

time.strftime()  # 把一个时间元组转换为格式化的字符串。
time.strftime(“%Y-%m-%d %X”, time.localtime()) #输出’2017-10-01 12:14:23’

time.strptime()  # 把一个格式化的字符串转换成struct_time
time.strptime(‘2017-10-3 17:54’,”%Y-%m-%d %H:%M”) # 需要告诉程序字符串的格式
#输出 time.struct_time(tm_year=2017, tm_mon=10, tm_mday=3, tm_hour=17, tm_min=54, tm_sec=0, tm_wday=1, tm_yday=276, tm_isdst=-1)

 

字符串转时间格式对应表

 

 

转换关系图

 

datetime模块

相比于time模块,datetime模块的接口则更直观、更容易调用

datetime模块定义了下面这几个类:

  • datetime.date:表示日期的类。常用的属性有year, month, day;

  • datetime.time:表示时间的类。常用的属性有hour, minute, second, microsecond;

  • datetime.datetime:表示日期时间。

  • datetime.timedelta:表示时间间隔,即两个时间点之间的长度。

  • datetime.tzinfo:与时区有关的相关信息。(这里不详细充分讨论该类,感兴趣的童鞋可以参考python手册)

 

常用方法

datetime.date.today()  # 打印当前时间的年月日 只打印到日

datetime.datetime.today()  #  打印当前时间的年月日 时分秒

datetime.date.timetuple()  #  将日期转换为元组格式

datetime.date.ctime() # 显示英文日期格式 Fri Dec  6 00:00:00 2019

datetime.date.fromtimestamp()  # 把一个时间戳转为datetime日期类型

datetime.datetime.fromtimestamp() # 将时间戳转换为datetime日期时间类型

#时间运算
>>> datetime.datetime.now() + datetime.timedelta(4) #当前时间 +4天
datetime.datetime(2017, 10, 5, 12, 53, 35, 276589)
>>> datetime.datetime.now() + datetime.timedelta(hours=4) #当前时间+4小时
datetime.datetime(2017, 10, 1, 16, 53, 42, 876275)

print(datetime.datetime.now()+datetime.timedelta(days=10, minutes=100, seconds=10))  # 当前时间加十天 加100分钟 加十秒

#时间替换
d = datetime.datetime.now()
print(d.replace(year=2020, month=12, day=22, hour=9, minute=20, second=30))  # 将当前时间替换为2020-12-22 09:20:30.135930

>>> d.replace(year=2999,month=11,day=30)
datetime.date(2999, 11, 30)
 

pytz  # 关于时区的模块

import datetime
import pytz
print(datetime.datetime.now(tz=pytz.timezone('Asia/Dushanbe')))  
# 2019-12-06 12:07:11.573210+05:00显示时间加上时区

 

 

random随机模块

程序中有很多地方需要用到随机字符,比如登录网站的随机验证码,通过random模块可以很容易生成随机字符串

random.randrange(1,10)  # 返回1到10的随机数,不包括10

random。randint(1,10)  # 返回1到10的随机数,包括10

random.randrange(1,100,2)  # 返回1到100的偶数   ,可指定步长

random.random()  # 返回0到1的随机浮点数

random.choice('sde@32')  #  返回一个给定字符集中的随机字符

random.sample('asd123',3)  # 从给定字符集中选定给定数量的字符

# 生成随机字符串
import random
import string
a = ''.join(random.sample(string.ascii_lowercase+string.digits,6))
#sring.ascii_lowercase 所有的小写英文 
#string.digits 所有的数字
print(a)

#洗牌
a = list(range(10))
random.shuffle(a)
print(a)  # 列表中的元素将打乱顺序

 

 

序列化 pickle&json模块

序列化是指把内存里的数据类型转变成字符串,以使其能存储到硬盘或通过网络传输到远程,因为硬盘或网络传输时只能接受bytes。

用于序列化的两个模块

  • json,用于字符串 和 python数据类型间进行转换

  • pickle,用于python特有的类型 和 python的数据类型间进行转换

pickle模块提供了四个功能:dumps、dump、loads、load

import pickle
d = {
    'name': 'alex',
    'age': 23,
    'sex': 'male',
}

a = ['alex', 'eric', 'egon']

d_dump = pickle.dumps(d)  # 生成序列化的字符串
print(d_dump)  # bytes类型

d_load = pickle.loads(d_dump)  # 将序列化的字符串反向解析
print(d_load)

f = open("pick.pkl", 'wb')
# f.write(d_dump)  # 将序列化的二进制字符串直接写入文件
pickle.dump(d, f)  # 用dump方法可以直接写入文件
pickle.dump(a, f)

print(pickle.load(f))
print(pickle.load(f))  # dump几次就load几次
总结
pickle.dumps() 生成序列化的字符串
pickle.loads() 反向解析序列化的字符串
pickle.dump() 写入文件
dump几次就要load几次
写入文件时,最好只用一次dump 避免因不知道次数而引发的错误

 Json模块也提供了四个功能:dumps、dump、loads、load,用法跟pickle一致

import json
d = {
    'name': 'alex',
    'age': 23,
    'sex': 'male',
}

a = ['alex', 'eric', 'egon']

d_json = json.dumps(d)
print(type(d_json))  # json.dumps() #将数据通过特殊的形式转换位所有程序语言都认识的字符串
# 注意json dumps生成的是字符串,不是bytes
print(type(json.loads(d_json)))  # 转换成原来的数据类型

f = open('js.json', 'w')
# f.write(d_json)
json.dump(d, f)
print(json.load(f))  
总结
json 和 pickle 相似 有dump load dumps loads 四种用法
但json 和 pickle 也有不同
pickle : 支持所有python的数据类型
list、int、dict、set、str、tuple、class--object 、function 、datetime 都可以存入
但只能在python中使用 占用空间大
json: 所有语言都可以用json交接 且存入文件时体积小 便于阅读
但因为是所有语言通用的 因此只支持python常规的数据类型 int、str、list、dict、set、tuple

网站前后端的交互就是通过json传递数据 后端数据---->json序列化------>前端
一般序列化用json

 hashlib模块

Hash,一般翻译做“散列”,也有直接音译为”哈希”的,就是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。

MD5讯息摘要演算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码杂凑函数,可以产生出一个128位的散列值(hash value),用于确保信息传输完整一致。MD5的前身有MD2、MD3和MD4。

MD5功能

输入任意长度的信息,经过处理,输出为128位的信息(数字指纹);

不同的输入得到的不同的结果(唯一性);

 

 

前面我们知道hash算法可以生成一段固定的散列值,但是同一段数据,每次打开解释器hash出来的值都不相同,不能用来加密。
因此,为了进行加密 MD5算法就被发明出来 数据经过MD5算法会生成128位的散列值(一个十六进制四位)并且不管在哪一台机器上
MD5 相同的数据也是相同的。
hash算法、MD5算法,虽然生成的散列值是唯一的,但是当数据量极大时,也可能出现不同的数据,生成散列值相同的情况,称之为碰撞,但概率是极低的。
在支付宝、京东这些平台上,用户的数据就是通过加密的算法生成散列值 ,存入数据库当中。通过散列值不能倒推出明文
但是,当密码过于简单时,如果黑客得到了数据库中的密文,就可以通过穷举算法通过不断的试值进行对比 ,称之为撞库。
如果匹配上那你的信息就会泄露,
所以有些服务器为了防止撞库,就将得出的MD5值再加一些字符串 ,再进行别的运算 ,称为加盐。

 

常用方法

m1 = hashlib.md5()
# m1.update(b"WQ2017617")  # 必须是bytes类型 中文要进行encode
m1.update("小猿圈".encode("utf8"))
print(m1.hexdigest())  # 以16进制来显示
print(m1.hexdigest())

m2 = hashlib.sha1()  # 生成160位散列值
m2.update(b"WQ2017617")
print(m2.hexdigest())

m3 = hashlib.sha256()  # 生成256位散列值
m3.update(b"WQ2017617")
print(m3.hexdigest())

SHA-1,安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。

SHA是美国国家安全局设计的,由美国国家标准和技术研究院发布的一系列密码散列函数。

由于MD5和SHA-1于2005年被山东大学的教授王小云破解了,科学家们又推出了SHA224, SHA256, SHA384, SHA512,当然位数越长,破解难度越大,但同时生成加密的消息摘要所耗时间也更长。目前最流行的是加密算法是SHA-256 .

 

 

MD5与SHA-1的比较

由于MD5与SHA-1均是从MD4发展而来,它们的结构和强度等特性有很多相似之处,SHA-1与MD5的最大区别在于其摘要比MD5摘要长32 比特。对于强行攻击,产生任何一个报文使之摘要等于给定报文摘要的难度:MD5是2128数量级的操作,SHA-1是2160数量级的操作。产生具有相同摘要的两个报文的难度:MD5是264是数量级的操作,SHA-1 是280数量级的操作。因而,SHA-1对强行攻击的强度更大。但由于SHA-1的循环步骤比MD5多80:64且要处理的缓存大160比特:128比特,SHA-1的运行速度比MD5慢。

 

 shutil模块

高级的 文件、文件夹、压缩包 处理模块

import shutil
shutil.copyfile('old.py', 'new.py')  # 拷贝文件

shutil.copyfileobj(open('old.py', encoding='utf8'), open('new_2.py', 'w',encoding='utf8'))
将文件内容拷贝到另一个文件中 不过需要将文件打开

shutil.copymode('f1.log', 'f2.log') #仅拷贝权限。内容、组、用户均不变
#目标文件必须存在

shutil.copystat('f1.log', 'f2.log') # 仅拷贝状态的信息,包括:mode bits, atime, mtime, flags    目标文件必须存在

shutil.copy('f1.log', 'f2.log')  # 拷贝文件和权限

shutil.copytree('../chapter4', 'new_chapter')  # 递归地去拷贝文件夹  ..是返回上层目录

shutil.copytree('../chapter4', 'new_chapter2',ignore=shutil.ignore_patterns('__init__.py','js*.py'))
拷贝文件 同时忽略某些不想要的文件  *是指所有

shutil.rmtree('folder1') # 递归的删除文件夹

shutil.move('new_chapter','new_chapter2/new_chapter')  # 递归地移动文件


shutil.make_archive(base_name='new.zip',format='zip',root_dir='../chapter4')  # 将文件压缩为压缩包
可选参数如下:

base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
      如 data\_bak =>保存至当前路径  
      如:/tmp/data\_bak =>保存至/tmp/

format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”

root_dir: 要压缩的文件夹路径(默认当前目录)

owner: 用户,默认当前用户

group: 组,默认当前组

logger: 用于记录日志,通常是logging.Logger对象

 

下面做一个添加zip压缩包的代码示例

import zipfile
import os
# ---------------------->压缩
file_list = []
z = zipfile.ZipFile('new.zip.zip', 'w')
z.write('new.py')
# z.write('new_chapter2')  # 该方法不能写入文件夹中的文件

file = list(os.walk('new_chapter2'))
# [('new_chapter2', ['new_chapter', '__pycache__'], ['datetime_mod.py']  ]
# 列表中第一个元素是相对路径  第二个是文件夹  第三个该路径下的文件
# os.walk()方法会将下面的每一层的文件的路径 以及其下的文件返回 因此 可通过文件拼接的方法拿到各层文件的绝对路径 再写入压缩包

for root_dir, dirs, files in file:
    for i in files:
        file_list.append(os.path.join(root_dir, i))
for line in file_list:
    z.write(line)


#-------------------------->解压
z = zipfile.ZipFile('new.zip.zip', 'r')
z.extractall(path='new_chapter2')
z.close()

 

re模块

正则表达式就是字符串的匹配规则,在多数编程语言里都有相应的支持。

字符匹配(普通字符,元字符):

1 普通字符:大多数字符和字母都会和自身匹配
              >>> re.findall('alvin','yuanaleSxalexwupeiqi')
                      ['alvin'] 

2 元字符:. ^ $ * + ? { } [ ] | ( ) \

'.'     默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^'     匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$'     匹配字符结尾, 若指定flags MULTILINE ,re.search('foo.$','foo1\nfoo2\n',re.MULTILINE).group() 会匹配到foo1
'*'     匹配*号前的字符0次或多次, re.search('a*','aaaabac')  结果'aaaa'
'+'     匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?'     匹配前一个字符1次或0次 ,re.search('b?','alex').group() 匹配b 0次
'[]' 字符集
'{m}' 匹配前一个字符m次 ,re.search('b{3}','alexbbbs').group() 匹配到'bbb' '{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|45)", "abcabca456c").group() 结果为'abcabca45' '\A' 只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的,相当于re.match('abc',"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' '(?P...)' 分组匹配 re.search("(?P[0-9]{4})(?P[0-9]{2})(?P[0-9]{4}

 

re的匹配语法有以下几种

  • re.match 从头开始匹配

  • re.search 匹配包含

  • re.findall 把所有匹配到的字符放到以列表中的元素返回

  • re.split 以匹配到的字符当做列表分隔符

  • re.sub 匹配字符并替换

  • re.fullmatch 全部匹配

import re
 
ret=re.findall('a..in','helloalvin')
print(ret)#['alvin']
 
 
ret=re.findall('^a...n','alvinhelloawwwn')
print(ret)#['alvin']
 
 
ret=re.findall('a...n$','alvinhelloawwwn')
print(ret)#['awwwn']
 
 
ret=re.findall('a...n$','alvinhelloawwwn')
print(ret)#['awwwn']
 
 
ret=re.findall('abc*','abcccc')#贪婪匹配[0,+oo]  
print(ret)#['abcccc']
 
ret=re.findall('abc+','abccc')#[1,+oo]
print(ret)#['abccc']
 
ret=re.findall('abc?','abccc')#[0,1]
print(ret)#['abc']
 
 
ret=re.findall('abc{1,4}','abccc')
print(ret)#['abccc'] 贪婪匹配

注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配

ret=re.findall('abc*?','abcccccc')
print(ret)#['ab']

 

字符集[ ]

ret=re.findall('a[bc]d','acd')
print(ret)#['acd']
 
ret=re.findall('[a-z]','acd')
print(ret)#['a', 'c', 'd']
 
ret=re.findall('[.*+]','a.cd+')
print(ret)#['.', '+']
 
#在字符集里有功能的符号: - ^ \
# ^ 在字符集中是取反的功能 
 
ret=re.findall('[1-9]','45dha3')
print(ret)#['4', '5', '3']
 
ret=re.findall('[^ab]','45bdha3')  # 匹配除ab外的所有字符
print(ret)#['4', '5', 'd', 'h', '3']
 
ret=re.findall('[\d]','45bdha3')
print(ret)#['4', '5', '3']

 

元字符之转义符\
反斜杠后边跟元字符去除特殊功能,比如\.
反斜杠后边跟普通字符实现特殊功能,比如\d

\d 匹配任何十进制数;它相当于类 [0-9]。
\D 匹配任何非数字字符;它相当于类 [^0-9]。
\s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
\b 匹配一个特殊字符边界,比如空格 ,&,#等

import re
ret=re.findall('c\l','abc\le')
print(ret)#[]
ret=re.findall('c\\l','abc\le')
print(ret)#[]
ret=re.findall('c\\\\l','abc\le')
print(ret)#['c\\l']
ret=re.findall(r'c\\l','abc\le')
print(ret)#['c\\l']
 
#之所以选择\b是因为\b在ASCII表中是有意义的
m = re.findall('\bblow', 'blow')
print(m)
m = re.findall(r'\bblow', 'blow')
print(m)

  

 

元字符之分组()

m = re.findall(r'(ad)+', 'add')
print(m)
 
ret=re.search('(?P<id>\d{2})/(?P<name>\w{3})','23/com')
print(ret.group())#23/com
print(ret.group('id'))#23

 

元字符之|

ret=re.search('(ab)|\d','rabhdg8sd')
print(ret.group())#ab

 

re模块下的常用方法

import re
#1
re.findall('a','alvin yuan')    #返回所有满足匹配条件的结果,放在列表里
#2
re.search('a','alvin yuan').group()  #函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以
                                     # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
 
#3
re.match('a','abc').group()     #同search,不过尽在字符串开始处进行匹配
 
#4
ret=re.split('[ab]','abcd')     #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
print(ret)#['', '', 'cd']
 
#5
ret=re.sub('\d','abc','alvin5yuan6',1)
print(ret)#alvinabcyuan6
ret=re.subn('\d','abc','alvin5yuan6')
print(ret)#('alvinabcyuanabc', 2)
 
#6
obj=re.compile('\d{3}')
ret=obj.search('abc123eeee')
print(ret.group())#123


import re
ret=re.finditer('\d','ds3sy4784a')
print(ret)        #<callable_iterator object at 0x10195f940>
 
print(next(ret).group())
print(next(ret).group())

 

注意

import re
 
ret=re.findall('www.(baidu|oldboy).com','www.oldboy.com')
print(ret)#['oldboy']     这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
 
ret=re.findall('www.(?:baidu|oldboy).com','www.oldboy.com')
print(ret)#['www.oldboy.com']

 

补充:

import re

print(re.findall("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>"))
a = re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")
print(a.groups())  # 将匹配到的以元组形式打印
print(a.groupdict())  # 将匹配到的以字典形式打印出 tag_name: xxx









#匹配出所有的整数
import re

#ret=re.findall(r"\d+{0}]","1-2*(60+(-40.35/5)-(-4*3))")
ret=re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")
ret.remove("")

print(ret)

 

 

compile and match

re.compile(pattern, flags=0)
Compile a regular expression pattern into a regular expression object, which can be used for matching using its match(), search() and other methods, described below.

The sequence

prog = re.compile(pattern)
result = prog.match(string)
is equivalent to

result = re.match(pattern, string)
but using re.compile() and saving the resulting regular expression object for reuse is more efficient when the expression will be used several times in a single program.
# 普通的匹配是每一次都找规则 再去匹配字符
# compile 先找出对应规则 再一次性匹配出字符




re.match(pattern, string, flags=0)
从起始位置开始根据模型去字符串中匹配指定内容,匹配单个

pattern 正则表达式

string 要匹配的字符串

flags 标志位,用于控制正则表达式的匹配方式

import re
obj = re.match('\d+', '123uuasf') #如果能匹配到就返回一个可调用的对象,否则返回None
if obj: 
    print obj.group()

 

Flag标志符

Flags标志符
re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)

re.M(MULTILINE): 多行模式,改变’^’和’$’的行为

re.S(DOTALL): 改变’.’的行为,make the ‘.’ special character match any character at all, including a newline; without this flag, ‘.’ will match anything except a newline.

re.X(re.VERBOSE) 可以给你的表达式写注释,使其更可读,下面这2个意思一样

a = re.compile(r"""\d + # the integral part
                \. # the decimal point
                \d * # some fractional digits""", 
                re.X)
b = re.compile(r"\d+\.\d*")
re.search(pattern, string, flags=0)
根据模型去字符串中匹配指定内容,匹配单个

import re
obj = re.search('\d+', 'u123uu888asf')
if obj:
    print obj.group()
re.findall(pattern, string, flags=0)
match and search均用于匹配单值,即:只能匹配字符串中的一个,如果想要匹配到字符串中所有符合条件的元素,则需要使用 findall。

import re
obj = re.findall('\d+', 'fa123uu888asf')
print obj
re.sub(pattern, repl, string, count=0, flags=0)
用于替换匹配的字符串,比str.replace功能更加强大

>>>re.sub('[a-z]+','sb','武配齐是abc123',)
>>> re.sub('\d+','|', 'alex22wupeiqi33oldboy55',count=2)
'alex|wupeiqi|oldboy55'
re.split(pattern, string, maxsplit=0, flags=0)
用匹配到的值做为分割点,把值分割成列表

>>>s='9-2*5/3+7/3*99/4*2998+10*568/14'
>>>re.split('[\*\-\/\+]',s)
['9', '2', '5', '3', '7', '3', '99', '4', '2998', '10', '568', '14']
>>> re.split('[\*\-\/\+]',s,3)
['9', '2', '5', '3+7/3*99/4*2998+10*568/14']
re.fullmatch(pattern, string, flags=0)
整个字符串匹配成功就返回re object, 否则返回None

re.fullmatch('\w+@\w+\.(com|cn|edu)',"alex@oldboyedu.cn")

 

configparser模块

一些软件或者文件的格式如下

[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
  
[bitbucket.org]
User = hg
  
[topsecret.server.com]
Port = 50022
ForwardX11 = no

 

用Python生成这样一个文档

import configparser
  
config = configparser.ConfigParser()
config["DEFAULT"] = {'ServerAliveInterval': '45',
                      'Compression': 'yes',
                     'CompressionLevel': '9'}
  
config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '50022'     # mutates the parser
topsecret['ForwardX11'] = 'no'  # same here
config['DEFAULT']['ForwardX11'] = 'yes'<br>
with open('example.ini', 'w') as configfile:
   config.write(configfile)

对文档的增删改查

import configparser

config = configparser.ConfigParser()

#---------------------------------------------查
print(config.sections())   #[]

config.read('example.ini')

print(config.sections())   #['bitbucket.org', 'topsecret.server.com']

print('bytebong.com' in config)# False

print(config['bitbucket.org']['User']) # hg

print(config['DEFAULT']['Compression']) #yes

print(config['topsecret.server.com']['ForwardX11'])  #no


for key in config['bitbucket.org']:
    print(key)


# user
# serveraliveinterval
# compression
# compressionlevel
# forwardx11


print(config.options('bitbucket.org'))#['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11']
print(config.items('bitbucket.org'))  #[('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes'), ('user', 'hg')]

print(config.get('bitbucket.org','compression'))#yes


#---------------------------------------------删,改,增(config.write(open('i.cfg', "w")))


config.add_section('yuan')

config.remove_section('topsecret.server.com')
config.remove_option('bitbucket.org','user')

config.set('bitbucket.org','k1','11111')

config.write(open('i.cfg', "w"))

 

subprocess模块

      当我们需要调用系统的命令的时候,最先考虑的os模块。用os.system()和os.popen()来进行操作。但是这两个命令过于简单,不能完成一些复杂的操作,如给运行的命令提供输入或者读取命令的输

出,判断该命令的运行状态,管理多个命令的并行等等。这时subprocess中的Popen命令就能有效的完成我们需要的操作。

subprocess模块允许一个进程创建一个新的子进程,通过管道连接到子进程的stdin/stdout/stderr,获取子进程的返回值等操作。 

            obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            # shell 解析字符串成为命令 相当于开启了一个终端  同时要注意操作系统编码的问题
            #  PIPE是建立一个管道 stdout是正确命令的执行结果 stderr是错误命令的结果
            #  PIPE的执行内部其实是执行了一个方法 加了一个property
       stdout = obj.stdout.read()
       stderr = obj.stderr.read()
 

 

在创建Popen对象时,subprocess.PIPE可以初始化stdin, stdout或stderr参数。表示与子进程通信的标准流。

这是因为subprocess创建了子进程,结果本在子进程中,if 想要执行结果转到主进程中,就得需要一个管道,即 : stdout=subprocess.PIPE

创建Popen对象时,用于初始化stderr参数,表示将错误通过标准输出流输出。

更详细的用法,参考yuan先生博客:https://www.cnblogs.com/yuanchenqi/articles/5732581.html

 

logging模块

import logging  
logging.debug('debug message')  
logging.info('info message')  
logging.warning('warning message')  
logging.error('error message')  
logging.critical('critical message')  

输出:

WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message

可见,默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),默认的日志格式为日志级别:Logger名称:用户输出消息。

 

 

配置日志输出级别,日志格式,输出位置

import logging  
logging.basicConfig(level=logging.DEBUG,  
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',  # 输出的格式
                    datefmt='%a, %d %b %Y %H:%M:%S',  # 时间格式
                    filename='/tmp/test.log',  
                    filemode='w')  
  
logging.debug('debug message')  
logging.info('info message')  
logging.warning('warning message')  
logging.error('error message')  
logging.critical('critical message')

可见在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有
filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。 
datefmt:指定日期时间格式。 
level:设置rootlogger(后边会讲解具体概念)的日志级别 
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open('test.log','w')),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。

format参数中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s用户输出的消息

 

 logger对象

上述几个例子中我们了解到了logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()(分别用以记录不同级别的日志信息),logging.basicConfig()(用默认日志格式(Formatter)为日志系统建立一个默认的流处理器(StreamHandler),设置基础配置(如日志级别等)并加到root logger(根Logger)中)这几个logging模块级别的函数,另外还有一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger)

一个简单过程

import logging

logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log')

# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

fh.setFormatter(formatter)
ch.setFormatter(formatter)

logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
logger.addHandler(ch)

logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')

      先简单介绍一下,logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。

     (1)

      Logger是一个树形层级结构,输出信息之前都要获得一个Logger(如果没有显示的获取则自动创建并使用root Logger,如第一个例子所示)。
      logger = logging.getLogger()返回一个默认的Logger也即root Logger,并应用默认的日志级别、Handler和Formatter设置。
当然也可以通过Logger.setLevel(lel)指定最低的日志级别,可用的日志级别有logging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、logging.CRITICAL。
      Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()输出不同级别的日志,只有日志等级大于或等于设置的日志级别的日志才会被输出。 

logger.debug('logger debug message')  
logger.info('logger info message')  
logger.warning('logger warning message')  
logger.error('logger error message')  
logger.critical('logger critical message')  

只输出了
2014-05-06 12:54:43,222 - root - WARNING - logger warning message
2014-05-06 12:54:43,223 - root - ERROR - logger error message
2014-05-06 12:54:43,224 - root - CRITICAL - logger critical message
     从这个输出可以看出logger = logging.getLogger()返回的Logger名为root。这里没有用logger.setLevel(logging.Debug)显示的为logger设置日志级别,所以使用默认的日志级别WARNIING,故结果只输出了大于等于WARNIING级别的信息。

 

Filter

     限制只有满足过滤规则的日志才会输出。
     比如我们定义了filter = logging.Filter('a.b.c'),并将这个Filter添加到了一个Handler上,则使用该Handler的Logger中只有名字带          a.b.c前缀的Logger才能输出其日志。

 

     filter = logging.Filter('mylogger') 

     logger.addFilter(filter)

     这是只对logger这个对象进行筛选

     如果想对所有的对象进行筛选,则:

      filter = logging.Filter('mylogger') 

      fh.addFilter(filter)

      ch.addFilter(filter)

      这样,所有添加fh或者ch的logger对象都会进行筛选。

import logging

logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log')

# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

fh.setFormatter(formatter)
ch.setFormatter(formatter)

# 定义一个filter
filter = logging.Filter('mylogger')
fh.addFilter(filter)
ch.addFilter(filter)

# logger.addFilter(filter)
logger.addHandler(fh)
logger.addHandler(ch)




logger.setLevel(logging.DEBUG)

logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')

##################################################
logger1 = logging.getLogger('mylogger')
logger1.setLevel(logging.DEBUG)

logger2 = logging.getLogger('mylogger')
logger2.setLevel(logging.INFO)

logger1.addHandler(fh)
logger1.addHandler(ch)

logger2.addHandler(fh)
logger2.addHandler(ch)

logger1.debug('logger1 debug message')
logger1.info('logger1 info message')
logger1.warning('logger1 warning message')
logger1.error('logger1 error message')
logger1.critical('logger1 critical message')

logger2.debug('logger2 debug message')
logger2.info('logger2 info message')
logger2.warning('logger2 warning message')
logger2.error('logger2 error message')
logger2.critical('logger2 critical message')

 

#coding:utf-8  
import logging  
  
# 创建一个logger    
logger = logging.getLogger()  
  
logger1 = logging.getLogger('mylogger')  
logger1.setLevel(logging.DEBUG)  
  
logger2 = logging.getLogger('mylogger')  
logger2.setLevel(logging.INFO)  
  
logger3 = logging.getLogger('mylogger.child1')  
logger3.setLevel(logging.WARNING)  
  
logger4 = logging.getLogger('mylogger.child1.child2')  
logger4.setLevel(logging.DEBUG)  
  
logger5 = logging.getLogger('mylogger.child1.child2.child3')  
logger5.setLevel(logging.DEBUG)  
  
# 创建一个handler,用于写入日志文件    
fh = logging.FileHandler('/tmp/test.log')  
  
# 再创建一个handler,用于输出到控制台    
ch = logging.StreamHandler()  
  
# 定义handler的输出格式formatter    
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')  
fh.setFormatter(formatter)  
ch.setFormatter(formatter)  
  
#定义一个filter  
#filter = logging.Filter('mylogger.child1.child2')  
#fh.addFilter(filter)    
  
# 给logger添加handler    
#logger.addFilter(filter)  
logger.addHandler(fh)  
logger.addHandler(ch)  
  
#logger1.addFilter(filter)  
logger1.addHandler(fh)  
logger1.addHandler(ch)  
  
logger2.addHandler(fh)  
logger2.addHandler(ch)  
  
#logger3.addFilter(filter)  
logger3.addHandler(fh)  
logger3.addHandler(ch)  
  
#logger4.addFilter(filter)  
logger4.addHandler(fh)  
logger4.addHandler(ch)  
  
logger5.addHandler(fh)  
logger5.addHandler(ch)  
  
# 记录一条日志    
logger.debug('logger debug message')  
logger.info('logger info message')  
logger.warning('logger warning message')  
logger.error('logger error message')  
logger.critical('logger critical message')  
  
logger1.debug('logger1 debug message')  
logger1.info('logger1 info message')  
logger1.warning('logger1 warning message')  
logger1.error('logger1 error message')  
logger1.critical('logger1 critical message')  
  
logger2.debug('logger2 debug message')  
logger2.info('logger2 info message')  
logger2.warning('logger2 warning message')  
logger2.error('logger2 error message')  
logger2.critical('logger2 critical message')  
  
logger3.debug('logger3 debug message')  
logger3.info('logger3 info message')  
logger3.warning('logger3 warning message')  
logger3.error('logger3 error message')  
logger3.critical('logger3 critical message')  
  
logger4.debug('logger4 debug message')  
logger4.info('logger4 info message')  
logger4.warning('logger4 warning message')  
logger4.error('logger4 error message')  
logger4.critical('logger4 critical message')  
  
logger5.debug('logger5 debug message')  
logger5.info('logger5 info message')  
logger5.warning('logger5 warning message')  
logger5.error('logger5 error message')  
logger5.critical('logger5 critical message')  

 Handler中FileHandler和StreamHandler也可以设置日志的优先级,不过全局的日志优先级最高,如果想让屏幕或者文件的日志级别发挥功能,则需要将其优先级设置得高于全局日志得优先级。

具体参考yuan先生博客:https://www.cnblogs.com/yuanchenqi/articles/5732581.html

 

 

注:部分参考自路飞学城及银角大王、yuan先生博客。

posted @ 2019-12-24 15:03  Mrterrific  阅读(271)  评论(1编辑  收藏  举报