python初识day5
本节内容:
- 模块介绍
- 模块的导入和使用
- 常用模块一
- time&datetime模块
- random模块
- os模块
- sys模块
- 序列化模块
- re模块
- 常用模块二
- hashlib模块
- configpares模块
- logging模块
一、模块介绍
什么是模块?
通俗来说:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。
但其实import'加载的模块分为四个通用类别:
- 使用python编写的代码(.py文件)
- 已被编译为共享库或DLL的C或C++扩展
- 包好一组模块的包
- 使用C编写并链接到python解释器的内置模块
为何要使用模块?
如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写道文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script.
随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用。
二、模块的导入和使用
import
自定义了一个名叫haha.py的模块,模块内容如下:
#haha.py print("haha") aha= 520 def a(): print("aaa") def b(): print("bbb") def c(): global aha
aha = 0
知识点一、模块可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行(import语句是可以在程序中的任意位置使用的,且针对同一个模块很import多次,为了防止你重复导入,python的优化手段是:第一次导入后就将模块名加载到内存了,后续的import语句仅是对已经加载大内存中的模块对象增加了一次引用,不会重新执行模块内的语句),如下
#lala.py import haha.py #只在第一次导入时才执行my_module.py内代码,此处的显式效果是只打印一次'from the my_module.py',当然其他的顶级代码也都被执行了,只不过没有显示效果. import haha.py import haha.py #执行结果 #haha
我们可以从sys.modules中找到已经加载的模块,sys.modules是一个字典,内部包含模块名与模块对象的映射,该字典 决定了导入模块时是否需要重洗导入。
知识点二、每个模块都是一个独立的命名空间,定义这个模块中的函数,把这个模块的名称空间当作全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会在被导入时,与使用者的全局变量冲突。
1 #测试一:aha与haha.aha不冲突 2 #lala.py 3 4 import haha 5 6 aha = 521 7 print(aha) 8 print(haha.aha) 9 10 #输出: 11 521 12 520
1 #测试二、aaa()与haha.aaa()不冲突 2 #lala.py 3 4 import haha 5 6 def aaa(): 7 print("aaa1") 8 9 haha.aaa() 10 aaa() 11 #输出 12 13 haha 14 aaa 15 aaa1
1 #测试三、执行haha.ccc()操作的全局变量aha仍然是haha中的 2 #lala.py 3 4 import haha 5 6 aha = 521 7 haha.ccc() 8 9 print(aha) 10 print(haha.aha) 11 12 #输出 13 haha 14 521 15 0
小总结:首次导入模块haha.py时会做三件事:
1.为源文件(haha.py模块)创建新的命名空间,在haha.py中定义的函数和方法若是使用到global时访问的就是这个命名空间。
2.在新创建的命名空间中执行模块中包含的代码,见初始导入import haha
提示:导入模块时到底执行了什么?
事实上函数定义也是“被执行”的语句,模块级别函数定义的执行将函数名放入模块全局名称空间表,用globals()可以查看
3.创建名字haha来引用该命名空间
这个名字和变量名没什么区别,都是‘测试一’的,且使用haha.名字的方式可以访问haha.py文件中的名字,haha.名字与lala.py中的名字来源于两个完全不同的地方。
知识点四:为模块起别名,相当于m1=1;m2=m1
import haha as shasha
print(shasha.aha) == print(haha.aha)
例子一:有两个sql模块mysql和oralce,根据用户的输入,选择不同的sql功能
#mysql.py
def sqlparse():
print("from myaql sqlparse")
#oracle.py
def sqlparse():
print("from oracle sq;parse")
#text.py
db_type = input(">>>:")
if db_type == "mysql"
import mysql as db
elif db_type == "oracle"
import oracle as db
db.sqlparse()
例子二:为已经导入的模块起别名的方式对编写可扩展的代码很有用,假设有两个模块xmlreader.py和csreader.py,它们都定义了函数read_data(filename):用来从文件中读取一些数据,但是采用不同的输入格式。可以编写代码来选择性的挑选读取模块
if file_format == "xml"
import xmlreader as reader
elif file_format == "csv"
import csvreader as reader
data = reader.read_data(filename)
知识点五、几种别的导入方式
importmodule #上边详细解释的方式frommodule.xx.xximportxxfrommodule.xx.xximportxx as renamefrommodule.xx.xximport*
常用模块一:
time & datetime模块
1 import time 2 print(time.time()) #返回当前时间的时间戳(1970纪元后经过的浮点秒数)(格林尼治时间)。 3 print(type(time.time())) 4 print("-----------------------------------") 5 print(time.localtime())#作用是格式化时间戳为本地的时间(时间元组) 6 print(type(time.localtime())) 7 # 不输入参数,返回本地时间,(本时区) 8 # 如果sec参数未输入,则以当前时间为转换标准。 9 print("-----------------------------------") 10 print('时间戳,转换为元组') 11 t = 0.0 12 t1 = time.localtime(t)#不带参数就是现在的时间 13 print('时间localtime,本地时间', t1) 14 t1 = time.gmtime(t) 15 print('时间gmtime,格林尼治时间', t1) 16 print(type(t1)) 17 print('----------------------------------') 18 print('分两步,1:时间戳转时间元组,2:时间元组转字符串') 19 t = 0.0 20 t1 = time.localtime(t) 21 t2 = time.strftime('%Y-%m-%d %H:%M:%S', t1) 22 print(t2) 23 print('----------------------------------') 24 print('元组,转为时间字符串') 25 t = (1970, 1, 1, 8, 0, 0, 0, 0, 0) 26 t1 = time.strftime('%Y-%m-%d %H:%M:%S', t) 27 #把元组按照格式变成时间字符串 28 t2 = time.strftime('%Y-%m-%d %H:%M:%S') 29 #没有t这个参数时就默认当前时间的元组 30 print(t1) 31 print(t2) 32 print('----------') 33 print('----------------------------------') 34 t0 = time.clock() 35 # t0 = time.clock() # 第一次调用time.clock,标记一个时间为0.0 36 time.sleep(2) 37 t1 = time.clock() 38 # 第二次调用,从第一个time.clock开始到现在的时间 39 time.sleep(2) 40 t2 = time.clock() 41 # 第三次调用,从第一个time.clock开始到现在的时间 42 43 print(t0) 44 print(t1) 45 print(t2) 46 print(t1 - t0) 47 print(t2 - t1) 48 print(t2 - t0) 49 #以下字符串方便用来存记录, 50 now_time = time.strftime('%Y-%m-%d %H:%M:%S') # 20171123093804 当前时间 51 print(now_time) 52 print(type(now_time)) # 格式是字符串 53 print('----------') 54 now=str(datetime.datetime.now()) 55 print(now) 56 print(type(now)) #格式是字符串 带毫秒的 57 print('----------') 58 today = time.strftime('%Y%m%d') # 20171123 当前日期 59 print(today) 60 print(type(today)) # 格式是字符串 61 print('----------')
radom模块
1、定义
随机数模块
2、random.random()方法
随机返回一个0-1之间的浮点数,且这个数不会大于1
import random
print(random.random())
3、random.randint(a, b)
生成[a,b]之间一个任意的随机数(包含a, b)
import random
print(random.randint(1, 10))
4、random.randrage(a, b)
生成(a,b)之间一个任意的随机数(不包含a, b)
import random
print(random.randerage(a, b))
5、random.choice([])/(())
.chioce()中可以放一个数组,列表,字符串。输出结果是随机选出一个元素。
import random
print(random.choice([1, 2, 3, 4]))
6、random.sample([],n)
在列表中取出n个元素
import random
print(random.sample(1, 2, 3, 4 ,5 ,6),3)#在元组(1, 2, 3, 4 ,5 ,6)中取出3和任意元素。
7、random.uniform(a, b)
取出a, b 之间的一个随机浮点数
import random
print(random.uniform(a,b))
8、random.shuffle()
打乱次序
import random
l = [1, 2, 3, 4]
random.shuffe(l)
print(l) #得到打乱顺序后的l
os模块
1 os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 2 3 os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd 4 os.curdir 返回当前目录: ('.') 5 os.pardir 获取当前目录的父目录字符串名:('..') 6 os.makedirs('dirname1/dirname2') 可生成多层递归目录 7 os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 8 os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname 9 os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname 10 os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 11 os.remove() 删除一个文件 12 os.rename("oldname","newname") 重命名文件/目录 13 os.stat('path/filename') 获取文件/目录信息 14 os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/" 15 os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n" 16 os.pathsep 输出用于分割文件路径的字符串 17 os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix' 18 os.system("bash command") 运行shell命令,直接显示 19 os.environ 获取系统环境变量 20 os.path.abspath(path) 返回path规范化的绝对路径 21 os.path.split(path) 将path分割成目录和文件名二元组返回 22 os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 23 os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素 24 os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False 25 os.path.isabs(path) 如果path是绝对路径,返回True 26 os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False 27 os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False 28 os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 29 os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间 30 os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
sys模块
1 sys.argv 命令行参数List,第一个元素是程序本身路径 2 sys.exit(n) 退出程序,正常退出时exit(0) 3 sys.version 获取Python解释程序的版本信息 4 sys.maxint 最大的Int值 5 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 6 sys.platform 返回操作系统平台名称 7 sys.stdout.write('please:') 8 val = sys.stdin.readline()[:-1]
序列化模块
用于序列的模块有两个:
- json,用于字符串和python数据类型间进行转换
- pickle,用于python特有的类型和python的数据类型间的转换
josn模块提供了四个功能:dumps、dump、loads、load
pickle模块提供了四个功能:dumps、dump、loads、load
1.json——dumps&dump
dumps:序列化——将字典形式的数据类型转化为字符串类型
json.dumps1 import json 2 data = {"a": 11133, "b": 222} 3 print(data, type(data)) 4 data = json.dumps(data) 5 print(data, type(data)) 6 7 #输出 8 {'a': 11133, 'b': 222} <class 'dict'> 9 {"a": 11133, "b": 222} <class 'str'>dump:接收一个文件的句柄,直接将字典转换为json字符串写入文件
json.dumpimport json data = {"a": 111, "b": 222} f = open("zhuzhu", "w") json.dump(data, f) #输出 建立了新的名为“zhuzhu”的.text文件,以json格式将data存到“huzhu.text里
2.json——loads&load
loads:反序列化,将一个字符串格式的字典转换成一个字典
loads1 import json 2 data = {'a': 111, 'b': 222} 3 data = json.dumps(data) 4 print(data, type(data)) 5 str = json.loads(data) 6 print(str, type(str)) 7 8 #输出 9 {"a": 111, "b": 222} <class 'str'> 10 {'a': 111, 'b': 222} <class 'dict'>load:接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
View Codeimport json # data = '''{"aaa1": 111, "bbb2": 222}''' f = open("zhuzhu", "r") str = json.load(f) print(str, type(str)) #输出 {'aaa1': 111, 'bbb2': 222} <class 'dict'>
3.pickle————dumps&dump
1 import pickle 2 3 data = {"k1": 123, "k2": "hello"} 4 5 #pickle.dumps 将数据通过特殊形式转换为只有python语言认识的字符串 6 p_str = pickle.dumps(data) 7 print(p_str) 8 9 #pickle.dump 将数据通过特殊的形式转换为只有python语言认识的字符串,并写入文件 10 with open("D:/result.pk", "w") as fp: 11 pickle.dump(data,fp)
re模块
1.普通字符和11个元字符:
| 普通字符 |
匹配自身
|
abc
|
abc
|
|
.
|
匹配任意除换行符"\n"外的字符(在DOTALL模式中也能匹配换行符 |
a.c
|
abc
|
|
\
|
转义字符,使后一个字符改变原来的意思
|
a\.c;a\\c
|
a.c;a\c
|
|
*
|
匹配前一个字符0或多次
|
abc*
|
ab;abccc
|
|
+
|
匹配前一个字符1次或无限次
|
abc+
|
abc;abccc
|
|
?
|
匹配一个字符0次或1次
|
abc?
|
ab;abc
|
|
^
|
匹配字符串开头。在多行模式中匹配每一行的开头 | ^abc |
abc
|
|
$
|
匹配字符串末尾,在多行模式中匹配每一行的末尾 | abc$ |
abc
|
| | | 或。匹配|左右表达式任意一个,从左到右匹配,如果|没有包括在()中,则它的范围是整个正则表达式 |
abc|def
|
abc
def
|
| {} | {m}匹配前一个字符m次,{m,n}匹配前一个字符m至n次,若省略n,则匹配m至无限次 |
ab{1,2}c
|
abc
abbc
|
|
[]
|
字符集。对应的位置可以是字符集中任意字符。字符集中的字符可以逐个列出,也可以给出范围,如[abc]或[a-c]。[^abc]表示取反,即非abc。 所有特殊字符在字符集中都失去其原有的特殊含义。用\反斜杠转义恢复特殊字符的特殊含义。 |
a[bcd]e
|
abe
ace
ade
|
|
()
|
被括起来的表达式将作为分组,从表达式左边开始没遇到一个分组的左括号“(”,编号+1. 分组表达式作为一个整体,可以后接数量词。表达式中的|仅在该组中有效。 |
(abc){2} a(123|456)c |
abcabc
a456c
|
这里需要强调以下反斜杠\的作用:
- 反斜杠后边跟元字符去除特殊功能;(即将特殊字符转义成普通字符)
- 反斜杠后边跟普通字符实现特殊功能;(即预定义字符)
- 引用序号对应的字组所匹配的字符串。
1 a = re.search(r'(tina)(fei)haha\2','tinafeihahafei tinafeihahatina').group() 2 print(a) 3 结果: 4 tinafeihahafei
2.预定义的字符集(可以写在字符集[...]中)
|
\d
|
数字:[0-9] |
a\bc
|
a1c
|
|
\D
|
非数字:[^\d] |
a\Dc
|
abc
|
|
\s
|
匹配任何空白字符:[<空格>\t\r\n\f\v] |
a\sc
|
a c
|
| \S | 非空白字符:[^\s] |
a\Sc
|
abc
|
|
\w
|
匹配包括下划线在内的任何字字符:[A-Za-z0-9_] |
a\wc
|
abc
|
|
\W
|
匹配非字母字符,即匹配特殊字符 |
a\Wc
|
a c
|
|
\A
|
仅匹配字符串开头,同^ | \Aabc |
abc
|
|
\Z
|
仅匹配字符串结尾,同$ |
abc\Z
|
abc
|
|
\b
|
匹配\w和\W之间,即匹配单词边界匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 | \babc\b a\b!bc |
空格abc空格 a!bc |
|
\B
|
[^\b] |
a\Bbc
|
abc
|
3.特殊分组用法:
|
(?P<name>)
|
分组,除了原有的编号外再指定一个额外的别名 | (?P<id>abc){2} |
abcabc
|
|
(?P=name)
|
引用别名为<name>的分组匹配到字符串 | (?P<id>\d)abc(?P=id) |
1abc1
5abc5
|
|
\<number>
|
引用编号为<number>的分组匹配到字符串 | (\d)abc\1 |
1abc1
5abc5
|
4.re模块中常用功能函数
compile()
编写正则表达式时,返回一个对象模式。
格式:re.compile(pattern, flags = 0)
pattern:编译时用的表达式字符串。
flags:编译标志位,用于修改正则表达式的匹配方式,如:是否区分大小写,多行匹配等。常用的flags有:
标志 含义 re.S(DOTALL)使.匹配包括换行在内的所有字符 re.I(IGNORECASE) 使匹配对大小写不敏感 re.L(LOCALE) 做本地化识别(locale-aware)匹配,法语等 re.M(MULTILINE) 多行匹配,影响^和$ re.X(VERBOSE) 该标志通过给予更灵活的格式以便将正则表达式写得更易于理解 re.U 根据Unicode字符集解析字符,这个标志影响\w,\W,\b,\B
例子1 import re 2 tt = "Tina is a gggoooddd girl, she is cool, clever, and so on...GgoOOL" 3 rr = re.compile('\w*oo\w*') 4 print(rr.findall(tt)) #查找所有包含'oo'的单词 5 6 #输出: 7 ['gggoooddd', 'cool']
match()re.match( )方法匹配的是以xxx开头的字符串,若不是开头的,尽管属于str内,则无法匹配。
格式:
re.match(pattern,string,flags=0)
例子1 print(re.match('com','comwww.runcomoob').group()) 2 print(re.match('com','Comwww.runcomoob',re.I).group()) 3 执行结果如下: 4 com 5 com
search()
格式:
re.search(pattern,string,flags=0)
若string中包含了pattern子串,则返回match对象,否则返回None,如果string中存在多个pattern字串,只返回第一个。
例子1 print(re.search('\dcom','www.4comrunoob.5com').group()) 2 3 #输出 4 4com*注:match和search一旦匹配成功,就是一个match object对象,而match object对象有以下几个方法:
- group() 返回被 RE 匹配的字符串
- start() 返回匹配开始的位置
- end() 返回匹配结束的位置
- span() 返回一个元组包含匹配 (开始,结束) 的位置
- group() 返回re整体匹配的字符串,可以一次输入多个组号,对应组号匹配的字符串。
a. group()返回re整体匹配的字符串,
b. group (n,m) 返回组号为n,m所匹配的字符串,如果组号不存在,则返回indexError异常
c.groups()groups() 方法返回一个包含正则表达式中所有小组字符串的元组,从 1 到所含的小组号,通常groups()不需要参数,返回一个元组,元组中的元就是正则表达式中定义的组。
例子1 import re 2 a = "123abc456" 3 print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0)) #123abc456,返回整体 4 print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1)) #123 5 print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2)) #abc 6 print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3)) #456 7 ###group(1) 列出第一个括号匹配部分,group(2) 列出第二个括号匹配部分,group(3) 列出第三个括号匹配部分。###
findall()
re.findall遍历匹配,可以获取字符串中所有匹配的字符串,返回一个列表。
格式:
re.findall(pattern,string,flags=0)
例子1 import 2 p = re.compile(r'\d+') 3 print(p.findall('o1n2m3k4')) 4 执行结果如下: 5 ['1', '2', '3', '4']
例子1 import re 2 tt = "Tina is a good girl, she is cool, clever, and so on..." 3 rr = re.compile(r'\w*oo\w*') 4 print(rr.findall(tt)) 5 print(re.findall(r'(\w)*oo(\w)',tt))#()表示子表达式 6 执行结果如下: 7 ['good', 'cool'] 8 [('g', 'd'), ('c', 'l')]
finditer()
搜索string,返回一个顺序访问每一个结果(Match对象)的迭代器。找到re匹配的所有子串,并把它们作为一个迭代器返回。
格式:
re,finditer(pattern,string,flags=0)
例子1 import re 2 iter = re.finditer(r'\d+','12 drumm44ers drumming, 11 ... 10 ...') 3 for i in iter: 4 print(i) 5 print(i.group()) 6 print(i.span()) 7 执行结果如下: 8 <_sre.SRE_Match object; span=(0, 2), match='12'> 9 12 10 (0, 2) 11 <_sre.SRE_Match object; span=(8, 10), match='44'> 12 44 13 (8, 10) 14 <_sre.SRE_Match object; span=(24, 26), match='11'> 15 11 16 (24, 26) 17 <_sre.SRE_Match object; span=(31, 33), match='10'> 18 10 19 (31, 33)
split()
按照能够匹配的子串将string分割返回列表。
可以使用re.split来分割字符串,如:re.split(r'\s+',text);将字符串按空格分割成一个单词列表。
格式:
re.split(pattern,string,[maxsplit])
maxsplit用于指定最大分割次数,不指定将全部分割。
例子1 print(re.split('\d+','one1two2three3four4five5')) 2 执行结果如下: 3 ['one', 'two', 'three', 'four', 'five', '']
sub()
使用re替换string中每一个匹配的子串后返回替换的字符串。
格式:
re.sub(pattern,repl,string,count)
例子import re text = "JGood is a handsome boy, he is cool, clever, and so on..." print(re.sub(r'\s+', '-', text)) 执行结果如下: JGood-is-a-handsome-boy,-he-is-cool,-clever,-and-so-on... 其中第二个函数是替换后的字符串;本例中为'-' 第四个参数指替换个数。默认为0,表示每个匹配项都替换。re.sub还允许使用函数对匹配项的替换进行复杂的处理。
如:re.sub(r"\s",lambda m:'[' +m.group(0) + ']', text,0);将字符串中的空格' '替换为'[' ']'。
例子1 import re 2 text = "JGood is a handsome boy, he is cool, clever, and so on..." 3 print(re.sub(r'\s+', lambda m:'['+m.group(0)+']', text,0)) 4 执行结果如下: 5 JGood[ ]is[ ]a[ ]handsome[ ]boy,[ ]he[ ]is[ ]cool,[ ]clever,[ ]and[ ]so[ ]on...
subn()
返回替换次数
格式:
subn(pattern,repl,string,count=0,flags=0)
例子1 import re 2 print(re.subn('[1-2]','A','123456abcdef')) 3 print(re.sub("g.t","have",'I get A, I got B ,I gut C')) 4 print(re.subn("g.t","have",'I get A, I got B ,I gut C')) 5 执行结果如下: 6 ('AA3456abcdef', 2) 7 I have A, I have B ,I have C 8 ('I have A, I have B ,I have C', 3)
*注:
A、re.match与re.search与re.findall区别:
- re.match之匹配字符串开始,如果字符串开始不符合正则表达式,则匹配失败,返回函数值None;而re.search和re.findall匹配整个字符串,直到找到一个匹配。
例子1 a=re.search('[\d]',"abc33").group() 2 print(a) 3 p=re.match('[\d]',"abc33") 4 print(p) 5 b=re.findall('[\d]',"abc33") 6 print(b) 7 执行结果: 8 3 9 None 10 ['3', '3']
B、贪婪匹配与非贪婪匹配
- *?,+?,??,{m,n}? 前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
例子1 import re 2 a = re.findall(r"a(\d+?)",'a23b') 3 print(a) 4 b = re.findall(r"a(\d+)",'a23b') 5 print(b) 6 执行结果: 7 ['2'] 8 ['23'] 9 10 11 12 a = re.match('<(.*)>','<H1>title<H1>').group() 13 print(a) 14 b = re.match('<(.*?)>','<H1>title<H1>').group() 15 print(b) 16 执行结果: 17 <H1>title<H1> 18 <H1> 19 20 21 a = re.findall(r"a(\d+)b",'a3333b') 22 print(a) 23 b = re.findall(r"a(\d+?)b",'a3333b') 24 print(b) 25 执行结果如下: 26 ['3333'] 27 ['3333'] 28 ####################### 29 这里需要注意的是如果前后均有限定条件的时候,就不存在什么贪婪模式了,非匹配模式失效。
C、用flags时遇到的小坑
-
print(re.split('a','1A1a2A3',re.I))#输出结果并未能区分大小写 这是因为re.split(pattern,string,maxsplit,flags)默认是四个参数,当我们传入的三个参数的时候,系统会默认re.I是第三个参数,所以就没起作用。如果想让这里的re.I起作用,写成flags=re.I即可。
常用模块二:
hashlib模块
Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。
摘要算法: 又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。
摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。
摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。
我们以常见的摘要算法MD5为例,计算出一个字符串的MD5值:
import hashlib md5 = hashlib.md5() md5.update('how to use md5 in python hashlib?'.encode('utf-8')) print(md5.hexdigest()) #输出 d26a53750bc40b38b65a520292f69306
如果数据量很大,可以分块多次调用update(),最后计算结果是一样的:
import hashlib md5 = hashlib.md5() md5.update('how to use md5 in '.encode('utf-8')) md5.update('python hashlib?'.encode('utf-8')) print(md5.hexdigest())
#输出 d26a53750bc40b38b65a520292f69306
MD5是最常见的摘要算法,速度很快,生成结果固定的128bit字节,通常用一个32位的16进制字符传表示。另一种常见的摘要算法式SHA1,调用SHA1和调用MD5完全类似:
import hashlib sha1 = hashlib.sha1() sha1.update('how to use sha1 in '.encode('utf-8')) sha1.update('python hashlib?'.encode('utf-8')) print sha1.hexdigest() #输出 2c76b57293ce30acef38d98f6046927161b46a44
SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法越慢,而且摘要长度更长。
configparser
待写。。。
logging
1.函数的简单配置
import logging logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')
默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于warning级别的日志,这说明默认的日志级别设置为WARNING(日志的级别等级CRITICAL>ERROR>WARNING>INFO>DEBUG),默认的日志格式为——日志级别 :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,这样日志会被存储在指定的文件中。 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对象配置:
import logging logger = logging.getLogger() # 创建一个handler,用于写入日志文件 fh = logging.FileHandler('test.log',encoding='utf-8') # 再创建一个handler,用于输出到控制台 ch = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setLevel(logging.DEBUG) 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指定日志显示格式。另外,可以通过:logger.setLevel(logging.Debug)设置级别,当然,也可以通过
fh.setLevel(logging.Debug)单对文件流设置某个级别。

浙公网安备 33010602011771号