一,python的模块
Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句。
模块让你能够有逻辑地组织你的 Python 代码段。
把相关的代码分配到一个模块里能让你的代码更好用,更易懂。
模块能定义函数,类和变量,模块里也能包含可执行的代码
模块一共有三种
-
- python标准库 (例如time)
- 第三方模块 (安装后和标准库一样调用)
- 应用程序自定义模块
新建一个python包,名称为day21_lesson和文件夹不同的是包里面包含__init__.py文件
新建两个py文件 test.py和cal.py
cal.py
def add(x,y):
return x + y
def sub(x,y):
return x - y
test.py
import cal
print(cal.add(5,3))
8
PS:调用需要在前面加模块名在家对应定义的函数名
使用Pycharm调用cal时候会标红,但是执行不会报错
import操作
1,执行对应文件(假如里面有print会先打印出对应内容 只是实际不会这样去操作)
2,引入变量 (函数也是一个变量)
如果不想加模块名调用函数
#import cal
from cal import add
from cal import sub
print(add(5,3))
print(sub(5,3))
8
2
如果有多个则使用* (不推荐这样调用,因为逻辑函数里面也可能会定义函数可能会重名,如果遇到重复的会按照顺序那个定义在最后就是那个有效)
#import cal
from cal import *
print(add(5,3))
print(sub(5,3))
8
2
PS:使用from cal import sub这种调入方式还是会执行cal.py里面所有的代码,然后把对应的变量调用过来
调用模块首先从调用模块的执行文件路径下面找模块,其次从默认的路径找模块
使用sys.path可以调出使用默认模块的路径,第一个就是执行文件的本地路径
import sys
print(sys.path)
['D:\\blzfmima\\python3_s3\\day21\\day21_lesson',
'D:\\blzfmima\\python3_s3',
'D:\\blzfmima\\python3_s3\\venv\\Scripts\\python35.zip',
'D:\\blzfmima\\python3_s3\\venv\\DLLs',
'D:\\blzfmima\\python3_s3\\venv\\lib',
'D:\\blzfmima\\python3_s3\\venv\\Scripts',
'C:\\Python35\\Lib',
'C:\\Python35\\DLLs',
'D:\\blzfmima\\python3_s3\\venv',
'D:\\blzfmima\\python3_s3\\venv\\lib\\site-packages',
'C:\\Program Files\\JetBrains\\PyCharm 2017.3.1\\helpers\\pycharm_matplotlib_backend']
在执行文件test.py在新建一个python包 把对应的模块文件放入里面
调用的方式不一样 从my_module里面调用cal
from my_module import cal
print(cal.add(1,3))
是从执行文件的路径下面开始寻找调用的模块,假如文件路径是这样
bin.py是程序入口文件
from my_module import main
main.run()
main.py是主程序文件(虽然main.py和调用的模块cal是同一文件夹下面但是这里不能使用import cal调用,因为本次的程序入口文件是bin.py所以这里main调用也必须从该入口文件开始)
#import cal
from my_module import cal
def run():
print(cal.add(5,3))
PS:如果一定想要使用import调用可以通过append方法把cal的路径添加到sys.path
多层引用模块使用.来分割
from web.web1.web2 import cal
print(cal.add(5,3))
8
PS:import调用的是py文件 如果调用文件夹运行不会报错会执行对应的的包下面的__init__.py文件
假如在__init__.py文件写入语句import . cal 也可以执行 ,不建议这样使用
变量__name__ 在执行文件里面__name__的值为 __main__ 在调用文件里面打印的是调用函数的路径,如果在cal里面加入print(__name__)使用其他的文件调用出现的值为web.web1.web2.cal
使用if __name__=='__main__'进行判断的作用
1,放在被调用的文件里面用于测试
2,放在执行文件里面不想被其他文件调用
二,python内置模块
1,time时间模块
time.py
import time
#时间戳 (用于计算)
print(time.time()) #1516937562.8488374秒从1970年1月1日0时0分0秒开始算起的时间秒
#结构化时间 使用localtime取到一个时间对象,可以通过时间对象取值
print(time.localtime())
#time.struct_time(tm_year=2018, tm_mon=1, tm_mday=26, tm_hour=11, tm_min=46, tm_sec=4, tm_wday=4, tm_yday=26, tm_isdst=0)
t = time.localtime()
#根据时间对象取年及星期的第几天,星期一是0 打印为4代表星期五
print(t.tm_year)
print(t.tm_wday)
#----
#和localtime一样但是tm_hours少了8个小时是和格林尼治时间的对比,是世界标准时间
print(time.gmtime())
#time.struct_time(tm_year=2018, tm_mon=1, tm_mday=26, tm_hour=3, tm_min=46, tm_sec=4, tm_wday=4, tm_yday=26, tm_isdst=0)
#字符串时间
#把时间戳转换成结构化时间struct_time
print(time.localtime(1431242343))
#time.struct_time(tm_year=2015, tm_mon=5, tm_mday=10, tm_hour=15, tm_min=19, tm_sec=3, tm_wday=6, tm_yday=130, tm_isdst=0)
#将结构化时间转换成时间戳
print(time.mktime(time.localtime()))
#1516946698.0
#把结构化时间转换成字符串的时间 %X代指时分秒
print(time.strftime('%Y-%m-%d %X',time.localtime()))
#2018-01-26
#把字符串是时间装换成结构化时间(需要严格一一对应包括之间的空格及-符号,否则报错)
print(time.strptime('2018-01-26 14:13:32','%Y-%m-%d %X'))
#time.struct_time(tm_year=2018, tm_mon=1, tm_mday=26, tm_hour=14, tm_min=13, tm_sec=32, tm_wday=4, tm_yday=26, tm_isdst=-1)
#asctime把一个时间元祖或者struct_time表示为固定的字符串时间格式,如果没有传递参数默认传递time.localtime()
print(time.asctime())
#Fri Jan 26 14:34:10 2018
#把一个时间戳转换成time.asctime()的形式,如果没有传递参数默认使用time.time()
print(time.ctime())
#Fri Jan 26 14:34:10 2018
#time.sleep()推迟运行时间参数为秒
time.sleep(1)
#另外一个时间模块datatime 打印的时间更加符合我们需求
import datetime
print(datetime.datetime.now())
关于时间模块的转换图示
2,random模块
随机模块.py
尾部付一个生成带字母和数字的字符串
import random
#生成一个0-1之间的随机浮点数
ret = random.random()
print(ret)
#0.06990352689202717
#生成一个区间的整数1,2,3
print(random.randint(1,3)) #[1,3]
#生成一个区间的整数不取最右边的1,2
print(random.randrange(1,3)) #[1,3)
#从一个可迭代对象里面随机选取一个元素
print(random.choice([11,22,33])) #[11,22,33]
#从一个可迭代对象里面随机选取几个元素 选两个生成一个列表
print(random.sample([11,22,33],2))
#生成一个范围内发浮点型
print(random.uniform(1,3))
#随机打乱顺序(不常用)
item = [1,2,3,4,5]
#打乱顺序修改原表,没有返回值
random.shuffle(item)
print(item)
#[4, 1, 2, 5, 3] 也可能是其他的顺序
#写一个验证码函数
def v_code():
#定义一个字符串接收验证码
ret = ''
for i in range(4):
#生成一个随机数字
num = random.randint(0,9)
#生成两个随机字母 alf1是随机大写字母 alf2是随机小写字母
alf1 = chr(random.randint(65,90))
alf2 = chr(random.randint(97,122))
#从两个随机字母中挑选一个
alf = random.choice([alf1,alf2])
#从数字或者字母中随机挑选一个
s = str(random.choice([num,alf]))
#拼接然后作为返回值返回
ret += s
return ret
res = v_code()
print(res)
2,os模块
os_test.py
import os
#getcwd获取当前工作目录
print(os.getcwd())
#D:\blzfmima\python3_s3\day22
#chdir改变工作目录相当于linux里面的cd
#可以是绝对路径也可以是当前目录的相对路径
#os.chdir('test1')
print(os.getcwd())
#D:\blzfmima\python3_s3\day22\test1
#curdir获取当前目录字符串名
print(os.curdir)
#.
#pardir获取当前目录的父目录字符串名
print(os.pardir)
#..
#makedirs生成多层递归目录新建两个文件夹其中dirname1和本文件同目录dirname2在dirname1的下一级目录
#相当于linux里面的mkdir -p命令
#os.makedirs('dirname1/dirname2')
#removedirs若目录为空则删除,并递归到上一级目录,如果也为空则删除,以此类推
#os.removedirs('dirname1/dirname2')
#mkdir生成单级目录相当于linux里面的mkdir
#os.mkdir('dirname')
#rmdir删除单级目录如果不为空则报错
#os.remove('dirname')
#listdir列出指定目录下面的所有文件和子目录,包括隐藏文件,并以列表的方式打印
#只列出一级目录
print(os.listdir())
#['dirname', 'os_test.py', 'test1']
#rename修改文件名
#os.rename('oldname','newname')
#stat列出对应文件的信息包括文件大小,创建时间修改时间等
print(os.stat('sss.py'))
#os.stat_result(st_mode=33206, st_ino=281474976879558, st_dev=1010701401, st_nlink=1, st_uid=0, st_gid=0, st_size=11, st_atime=1517191298, st_mtime=1517191298, st_ctime=1517191298)
#sep输出操作系统特定路径分隔符 win下为'\\' linux为'/'
print(os.sep)
# \
#linesep输出当前平台使用的行终止符 win下为'\r\n' linux下为'\n'
print(os.linesep)
#pathsep输出用于分割文件路径的字符串 win下为; linux下为:
print(os.pathsep)
# ;
#name输出字符串指示当前使用平台 win为'nt' linux为'posix'
print(os.name)
#nt
#system 运行shell命令直接显示
#os.system('ipcofig')
#split 将path分割成目录和文件名的二元组返回
print(os.path.split(r'D:/blzfmima/python3_s3/day21/day21_lesson/bin/bin.py'))
#('D:/blzfmima/python3_s3/day21/day21_lesson/bin', 'bin.py')
#dirname返回path目录,其实就是os.path.split(path)的第一个元素
print(os.path.dirname(r'D:/blzfmima/python3_s3/day21/day21_lesson/bin/bin.py'))
#D:/blzfmima/python3_s3/day21/day21_lesson/bin
#basename返回path最后的文件名如果以/或者\结尾那么会返回空值,及os.path.split(path)的第二个元素
print(os.path.basename(r'D:/blzfmima/python3_s3/day21/day21_lesson/bin/bin.py'))
#bin.py
#exists如果path存在返回True否则返回False
print(os.path.exists(r'D:/blzfmima/python3_s3/day21/day21_lesson/bin/bin.py'))
#True
#isabs如果是绝对路径返回True
print(os.path.isabs(r'D:/blzfmima/python3_s3/day21/day21_lesson/bin/bin.py'))
#True
#iffile是不是一个文件是文件返回True
print(os.path.isfile(r'D:/blzfmima/python3_s3/day21/day21_lesson/bin/bin.py'))
#True
#isdir是否是一个存在的目录返回True
print(os.path.isdir(r'D:/blzfmima/python3_s3/day21/day21_lesson/bin'))
#True
#join将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
a = 'D:/blzfmima/python3_s3'
b = 'day21/day21_lesson/bin/bin.py'
print(os.path.join(a,b))
#D:/blzfmima/python3_s3\day21/day21_lesson/bin/bin.py
#getatime返回path所指向的文件或者目录的最后存取时间
print(os.path.getatime(r'D:/blzfmima/python3_s3/day21/day21_lesson/bin/bin.py'))
#getmtime返回path所指向的文件或者目录的最后修改时间
print(os.path.getmtime(r'D:/blzfmima/python3_s3/day21/day21_lesson/bin/bin.py'))
#environ获取系统环境变量
print(os.environ)
3,sys模块
#print(sys.version)
#3.5.2rc1 (v3.5.2rc1:68feec6488b2+, Jun 12 2016, 08:56:24) [MSC v.1900 64 bit (AMD64)]
#path返回模块搜索路径
#print(sys.path)
#platform返回操作系统平台名称
#print(sys.platform)
#win32 或者linux
#stdout.write写进度条
import time
for i in range(10):
sys.stdout.write("#")
time.sleep(0.1)
sys.stdout.flush()
4,json模块
之前我们学习过用eval内置方法可以将一个字符串转换成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时间,eval就不管用了,所以eval的字典还是通常用来执行一个字符串表达式,并返回表达式的值
json_test.py
import json
dic = {'name':'zhangsan'}
dic_str = json.dumps(dic)
print(dic_str)
#{"name": "zhangsan"}
print(type(dic_str))
#<class 'str'>
#打开以下新文件把经过json.dumps转换后的字符串{"name": "zhangsan"}写入文件
with open('new_hello','w') as f_write:
f_write.write(dic_str)
#以只读方式打开文件并且使用json.loads方法把字符串转换成对应的数据类型为dict
with open('new_hello','r') as f_read:
data = json.loads(f_read.read())
print(data)
print(type(data))
{"name": "zhangsan"}
<class 'str'>
{'name': 'zhangsan'}
<class 'dict'>
PS:字符串不一定需要先dumps之后才能loads字符串只要符合json规范即可loads
5,pickle模块
pickle_test.py
import pickle
dic = {'name':'zhangsan'}
j = pickle.dumps(dic)
#使用pickle序列化 生成的对象是不可直接读的,读取是乱码
#只能使用pickle反序列化
f = open('序列号对象_pickle','wb')
f.write(j) #等价与pickle.dump(dic,f)
f.close()
#反序列化
f = open('序列号对象_pickle','rb')
data = pickle.loads(f.read())
f.close()
print(data['name'])
zhangsan
PS:pickle可序列化的数据类型比json多,可以序列化函数,类。但是这种需求较少,一般直接使用json即可
5,shelve模块(不常用了解即可)
shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值是python所支持的数据类型
shelve_test.py
import shelve
#f = shelve.open(r'shelve1') #目的:将一根字典放入文本
#f['stu1_info'] = {'name':'zhangsan','age':18}
#f['stu2_info'] = {'name':'lisi','age':28}
#f['school_info'] = {'website':'edu.com','city':'shenzhen'}
#f.close()
f = shelve.open(r'shelve1')
print(f.get('stu1_info')['age'])
先使用shelve方法把字典写入三个文件(不可读乱码),然后使用get方法取值
6,xml模块
xml是实现不同语言和程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单。
列子测试xml文档 xml_lesson
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year updated="yes">2012</year>
<gdppc>141100</gdppc>
<neighbor direction="E" name="Austria" />
<neighbor direction="W" name="Switzerland" />
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year updated="yes">2015</year>
<gdppc>59900</gdppc>
<neighbor direction="N" name="Malaysia" />
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year updated="yes">2015</year>
<gdppc>13600</gdppc>
<neighbor direction="W" name="Costa Rica" />
<neighbor direction="E" name="Colombia" />
</country>
</data>
对xml文件进行操作xml_test.py
#使用as可以把比较长的模块简写
import xml.etree.ElementTree as ET
#使用parse解析后赋值给tree对象
tree = ET.parse("xml_lesson")
#getroot拿到跟节点
root = tree.getroot()
print(root.tag)
#data
# for i in root:
# #print(i.tag)
# #print(i.attrib)
# #print(i.text)
# for j in i:
# print(j.tag,j.text)
# 遍历xml文档
#
# # 只遍历year 节点
# for node in root.iter('year'):
# print(node.tag, node.text)
# # ---------------------------------------
#
# import xml.etree.ElementTree as ET
#
# tree = ET.parse("xmltest.xml")
# root = tree.getroot()
#
# # 修改
for node in root.iter('year'):
new_year = int(node.text) + 1
node.text = str(new_year)
node.set("updated", "yes")
#修改后写进去文件名可以重复则覆盖,也可以不重复则新建一个文件
tree.write("xml_lesson")
#
# # 删除node
for country in root.findall('country'):
rank = int(country.find('rank').text)
if rank > 50:
root.remove(country)
tree.write('output.xml')
生成xml文档xml_create.py
import xml.etree.ElementTree as ET
new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"})
age = ET.SubElement(name, "age", attrib={"checked": "no"})
sex = ET.SubElement(name, "sex")
sex.text = '33'
name2 = ET.SubElement(new_xml, "name", attrib={"enrolled": "no"})
age = ET.SubElement(name2, "age")
age.text = '19'
et = ET.ElementTree(new_xml) # 生成文档对象
et.write("test.xml", encoding="utf-8", xml_declaration=True)
ET.dump(new_xml) # 打印生成的格式
7,re模块
就期本质而言,正则表达式(re)是一种小型的,高度专业化的编程语言,在python中它内嵌在python中通过re模块实现。
一,re模块的匹配规则及元字符
re_lesson.py
import re
#完全匹配如果需要匹配的字符串中间包含其他字符就匹配不到
ret = re.findall('zhangsan','hellozhangsan')
print(ret)
#['zhangsan']
#元字符 .^$+?{}[]|()\
#.通配符可以匹配一个任何字符,没有匹配到返回一个空列表
ret = re.findall('m..g','yueming')
print(ret)
#['ming']
#^以什么开头的
ret = re.findall('^y.e','yueming')
print(ret)
#['yue']
#$以什么结尾的
ret = re.findall('ing$','yuming')
print(ret)
#['ing']
#*代表匹配0次到无穷次
ret = re.findall('d*','sfdgsdddddd')
print(ret)
#['', '', 'd', '', '', 'dddddd', '']
#+代表匹配1到无穷次
ret = re.findall('d+','sfdgsdddddd')
print(ret)
#['d', 'dddddd']
#? 匹配0或者1次
ret = re.findall('ming?','asdhfaming')
print(ret)
#ming
#{}自己定义匹配多少 {0,} == * 0到无穷相当于*
# {1,} == + 1到无穷相当于+
# {0,1} == ? 0或者1相当于?
# {6} 重复6次 {1,6}可以重复1到6次之间的任何次数
ret = re.findall('ming{0,}','yuemingg')
print(ret)
#['mingg']
ret = re.findall('ming{1,}','yueminggg')
print(ret)
#['minggg']
ret = re.findall('ming{0,1}','yuemin')
print(ret)
#['min']
#PS:默认都是贪婪匹配尽可能多地取匹配如果需要惰性匹配在后面加一个? 如下
ret = re.findall('ming{1,}?','yueminggg')
print(ret)
#['ming']
#[]字符集
#起到或的作用
ret = re.findall('x[yz]p','xypuuuxzp')
print(ret)
#使用-代表一个区间
ret = re.findall('[a-z1-9]','abbh1210')
print(ret)
#['a', 'b', 'b', 'h', '1', '2', '1']
#PS:在字符集[]里面除了 - ^ \ 其他的均为普通字符
#^放在字符集里面不是匹配开头而是非
ret = re.findall('q[^a-z]','qa')
print(ret)
#[]
#计算器思路,匹配两个括号中间没有括号的任意字符
#前面\(代表匹配左括号 后面\)代表匹配右括号
#[^()]代表中间没有括号 这里的()因为是在[]里面不需要加\转义
#*代表匹配两个()之间的任意字符
#这样就能取出一个任意长计算字符串最里面括号的那一串字符了
ret = re.findall('\([^()]*\)','12+(34*6+2-5*(2-1))')
print(ret)
#['(2-1)']
#元字符之转义字符\
#反斜杠后面跟元字符去除特殊功能,比如\.就代表字符.
#反斜杠后面跟普通字符实现特殊功能,比如\d
#\d匹配任何十进制数,相当于[0-9]
ret = re.findall('\d','asad12asd2')
print(ret)
#['1', '2', '2']
#\D匹配任意非数字字符,相当于[^0-9]
ret = re.findall('\D+','asad12asd2')
print(ret)
#['asad', 'asd']
#\s匹配任意空白字符,相当于于[\t\n\r\f\v]
ret = re.findall('\s+','hello world')
print(ret)
#\S匹配任意非空白字符,相当于[^\t\n\r\f\v]
ret = re.findall('\S+','hello world')
print(ret)
#\s和\S不常用
#\w匹配任意字母数字字符包括下划线,相当于[a-zA-Z0-9_]
ret = re.findall('\w+','hello world')
print(ret)
#['hello', 'world']
#\W匹配任意非字母数字字符,相当于[^a-zA-Z0-9]
ret = re.findall('\W+','hello world#')
print(ret)
#[' ', '#']
#使用\去除特殊符号的特殊功能
ret = re.findall('www\*baidu','www*baidu.com')
print(ret)
#\b匹配一个特殊边界字符,比如空格 & #等
#需求匹配单独的I
#这里需要在\b前面在加一个\再次转义 或者在前面加r代表里面的字符串不做任何转义
#\\代表把\转义为普通的字符\ 在加上b就代表可以匹配空格了
#因为\b不光在re里面有意义同样在python里面也是有意义的
#\b在python里面的意义代表是退格
#print('123\b')输出为12 本来应该输出的3被退格了
ret = re.findall('I\b','hello I am LIST')
print(ret)
#需求匹配\f
#python调用模块re里面也有自己的语法及转义字符
#这里需要加4个\ 因为\\在python里面转义代表一个\
#如果re模块接收到2个\ 转义一下就代表一个普通的\了
ret = re.findall('c\\\\l','abc\le')
print(ret)
#元字符之| 或匹配
ret = re.findall('ka|b','kajkb')
print(ret)
#['ka', 'b']
ret = re.findall('(?P<name>\w+)','abcabc')
print(ret)
#search方法 只取第一个满足条件的 返回的是一个对象
#没有找到返回为空
ret = re.search('\d+','sdasd34sdf13')
print(ret)
#<_sre.SRE_Match object; span=(5, 7), match='34'>
#通过group方法返回对象的结果
print(ret.group())
#34
ret = re.search('(?P<name>[a-z]+)','123asdf43')
print(ret.group())
#asdf
#?P<name>通过分组取对应的信息假设前面是姓名后面是对应的年龄信息
#分组可用于提取url信息
ret = re.search('(?P<name>[a-z]+)\d+','zhangsan16lisi18')
print(ret.group())
#zhangsan16
print(ret.group('name'))
#zhansan
#同样年龄也可以分一个组为id
ret = re.search('(?P<name>[a-z]+)(?P<id>\d+)','zhangsan16lisi18')
print(ret.group('name'))
#zhangsan
print(ret.group('id'))
#16
二,re模块的方法
re_method.py
import re
#findall 返回所有满足条件的结果,放在一个列表里面,没有结果返回空列表
ret = re.findall('a','abc')
print(ret)
#['a']
#search匹配,只找到第一个匹配返回一个对象
#通过group()方法取得字符串,如果没有匹配返回为空
ret = re.search('a','abc')
print(ret)
#<_sre.SRE_Match object; span=(0, 1), match='a'>
print(ret.group())
#a
#match同search 不同之处在于match从字符串开始匹配
#相当于使用search匹配加了一个^
ret = re.match('\d+','asda12')
print(ret)
#None
ret = re.match('\d+','12asda12')
print(ret)
#<_sre.SRE_Match object; span=(0, 2), match='12'>
#split分割
#使用空格分割
ret = re.split(' ','hello abc')
print(ret)
#['hello', 'abc']
#使用[]可以定义多个分割符号
ret = re.split('[ |]','hello abc|def')
print(ret)
#['hello', 'abc', 'def']
#分割过程
#1,用a分割因为a左边没有及为空分割后为['','bc']
#2,用b分割既成['', '','c']
ret = re.split('[ab]','abc')
print(ret)
#['', '','c']
#sub替换
#三个参数,源 目标 字符串
#这里使用b替换a
ret = re.sub('a','b','abc')
print(ret)
#bbc
#默认是全部匹配,后面加参数指定匹配次数(使用概率小)
ret = re.sub('\d','A','abc1212324asfd',4)
print(ret)
#abcAAAA324asfd
#subn把匹配的次数打印出来
ret = re.subn('\d','A','abc1212324asfd',4)
print(ret)
#('abcAAAA324asfd', 4)
#compile把匹配规则编译生成一个对象
#调用该对象就是直接使用规则,跟的参数就只有需要匹配的字符串即可
#作用定义匹配规则可以多次调用
com = re.compile('\d+')
print(com)
#re.compile('\\d+')
ret = com.findall('ad12')
print(ret)
#['12']
#finditer 同findall效果一样 但是返回的是一个迭代器对象不是一个列表
ret = re.finditer('\d','asdasd71623asdjhagsd')
print(ret)
#<callable_iterator object at 0x0000022D562C7240>
#使用for循环加group方法可以取出结果
for item in ret:
print(item.group())
PS:使用()分组的优先级
ret = re.findall('www\.(baidu|163)\.com','www.baidu.com')
print(ret)
#['baidu']
因为使用了()分组 已经匹配到www.baidu.com但是默认优先级是取()里面的所以这里的结果是['baidu']
在分组()里面的前面加?:去除分组优先级
ret = re.findall('www\.(?:baidu|163)\.com','www.baidu.com')
print(ret)
['www.baidu.com']
分组()补充
#分组()补充
ret = re.findall('(abc)+','abcabcabc')
print(ret)
#输出如下,因为优先匹配一个()内里面的内容
#['abc']
ret = re.findall('(?:abc)+','abcabcabcdsdabc')
print(ret)
#加?:取消优先级输出如下
#['abcabcabc', 'abc']
8,logging模块(重要)
日志模块,记录信息
一,简单应用
logging_test.py
import logging
#默认只打印warning以上信息设置成debug可以打印所有信息
logging.basicConfig(
level=logging.DEBUG,
#默认是把日志显示在屏幕上,下面定义写入文件
#写入文件是追加,原内容不变
filename="logger.log",
#以下参数设置为覆盖
#filemode='w',
#定义日志格式
#asctime时间
#filename执行文件的名称这里是logging_test.py
#lineno行号
#message自定义的信息
format='%(asctime)s %(filename)s [%(lineno)d] %(message)s'
)
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
#root是默认的用户名
'''
DEBUG:root:debug message
INFO:root:info message
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message
'''
二,使用logger对象把日志信息写入到文件的同时显示到屏幕
logging_test2.py
import logging
#logger对象,使日志既显示的屏幕又输出到文件
logger=logging.getLogger()
#创建实例化对象可以向文件发送内容
fh=logging.FileHandler("test.log")
#创建实例化对象可以向屏幕发送内容
ch=logging.StreamHandler()
#自定义日志格式
fm=logging.Formatter("%(asctime)s %(message)s")
#使用fh和ch吃掉日志格式fm
fh.setFormatter(fm)
ch.setFormatter(fm)
#使用logger分别吃掉fh和ch
logger.addHandler(fh)
logger.addHandler(ch)
#设置日志级别
logger.setLevel("DEBUG")
#----------------------->>
logger.debug("debug message")
logger.info("info message")
logger.warning("warning message")
logger.error("error message")
logger.critical("critical message")
PS:logger对象使用比basicConfig更多
再看一个列子logging_test3.py
import logging
##################################################
#默认是root跟用户加参数设置子用户
logger1 = logging.getLogger('mylogger')
logger1.setLevel(logging.DEBUG)
logger2 = logging.getLogger('mylogger')
logger2.setLevel(logging.INFO)
#创建实例化对象可以向文件发送内容
fh=logging.FileHandler("test_new.log")
#创建实例化对象可以向屏幕发送内容
ch=logging.StreamHandler()
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')
我们明明通过logger1.setLevel(logging.DEBUG)将logger1的日志级别设置为了DEBUG,为何显示的时候没有显示出DEBUG级别的日志信息,而是从INFO级别的日志开始显示呢?
原来logger1和logger2对应的是同一个Logger实例,只要logging.getLogger(name)中名称参数name相同则返回的Logger实例就是同一个,且仅有一个,也即name与Logger实例一一对应。在logger2实例中通过logger2.setLevel(logging.INFO)设置mylogger的日志级别为logging.INFO,所以最后logger1的输出遵从了后来设置的日志级别。
再看一个列子
logging_test4.py
import logging
##################################################
#默认是root跟用户加参数设置子用户
logger1 = logging.getLogger('mylogger')
logger1.setLevel(logging.DEBUG)
logger2 = logging.getLogger('mylogger')
logger2.setLevel(logging.INFO)
#创建实例化对象可以向文件发送内容
fh=logging.FileHandler("test_new.log")
#创建实例化对象可以向屏幕发送内容
ch=logging.StreamHandler()
logger1.addHandler(fh)
logger1.addHandler(ch)
logger2.addHandler(fh)
logger2.addHandler(ch)
logger=logging.getLogger()
logger.addHandler(ch)
logger.addHandler(fh)
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')
PS:子对象logger1会重复打印两次,因为子在打印的时候回找父如果存在就多打印一次(知道即可,用的较少)
9,configparser模块
配置文件解析模块
生成配置文件 config.py
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'
with open('example.ini', 'w') as configfile:
#写入的方式会普通打开文件写入的方式不同
config.write(configfile)
生成的配置文件example.ini
[DEFAULT]
compression = yes
serveraliveinterval = 45
compressionlevel = 9
forwardx11 = yes
[bitbucket.org]
user = hg
[topsecret.server.com]
host port = 50022
forwardx11 = no
对配置文件增删改查confile2.py
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
#遍历对应的模块下面的键
#会默认把default下面的键都遍历处理
for key in config['bitbucket.org']:
print(key)
# user
# serveraliveinterval
# compression
# compressionlevel
# forwardx11
#options把键取出来生成一个列表
print(config.options('bitbucket.org'))#['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11']
#items取出key和value组成元祖再放在列表里面
print(config.items('bitbucket.org')) #[('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes'), ('user', 'hg')]
#取对应模块下面对应的键对应的值
#这里bitbucket.org下面是没有compression这个键的
#但是去默认default下面有,就取到了对应的键值为yes
print(config.get('bitbucket.org','compression'))#yes
#---------------------------------------------删,改,增(config.write(open('i.cfg', "w")))
#增加一个yuan的块
config.add_section('yuan')
#移除topsecret.server.com块
config.remove_section('topsecret.server.com')
#移除块bitbucket.org下面的键值为user的配置
config.remove_option('bitbucket.org','user')
#在块bitbucket.org下面新建一个键为k1键值为1111的配置
config.set('bitbucket.org','k1','11111')
#修改为写到一个新的文件
#使用open('i.cfg', "w")代替 with open('i.cfg','w') as f:
#可以这样写,不需要关闭
config.write(open('i.cfg', "w"))
生成的新文件i.cfg
[DEFAULT]
compression = yes
serveraliveinterval = 45
compressionlevel = 9
forwardx11 = yes
[bitbucket.org]
k1 = 11111
[yuan]
10,hashlib模块
用于加密相关操作,3.x里代替了md5模块和sha模块,主要提供SHA1,SHA224,SHA256,SHA384,SHA512,MD5算法
hashlib_test.py
import hashlib
obj=hashlib.md5()
obj.update("admin".encode('utf8'))
print(obj.hexdigest()) #5d41402abc4b2a76b9719d911017c592
#这一步是在字符串admin基础上做的,相当于对字符串'adminroot'加密
obj.update('root'.encode('utf8'))
print(obj.hexdigest()) #4b3626865dc6d5cfe1c60b855e68634a
#sha256和md5用法是一样的
m = hashlib.sha256()
m.update('admin'.encode('utf8'))
print(m.hexdigest())
#8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918