Python自动化开发—Day8

1、模块调用:

      定义:其实模块简单说就是一堆代码实现某个功能,它们是已经写好的.py文件。只需要用import应用即可。

           分类:      

      1、自定义模块

      2、内置标准模块(又称标准库)

      3、开源模块

          1、自定义模块,就是自己写的.py文件为了实现某个功能。

          2、内置模块,就是python自身已经写好的某个功能,例如经常用的sys、os等模块都是内置模块。

          3、开源模块,开源大家都明白吧,就是不收费的别人写好的模块,一般也称第三方模块。

        模块的引用:

      1、import modules

      2、from modules import  函数

      3、如果有多个模块,可以用逗号隔开,如果想把某个模块里面的所有功能都导入,可以用*,这样的话功能都加载道内存里面,占用内存资源,不建议用

2、time &datetime模块:

Python的time模块实现主要调用C库,所以各个平台可能有所不同。time模块表示时间的有三种类型:

  (1)timestamp 时间戳,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。返回时间戳方式的函数主要有time(),clock()等;

  (2)struct_time 时间元组,共有九个元素。返回struct_time的函数主要有gmtime(),localtime(),strptime();

'''在Python中,通常有这几种方式来表示时间:
时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。
我们运行“type(time.time())”,返回的是float类型。
格式化的时间字符串(Format String)
结构化的时间(struct_time):struct_time元组共有9个元素共九个元素:
(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)'''

import time
# print(time.time())#1535340758.6987474
# print(time.strftime("%Y-%m-%d %X")) #格式化的时间字符串:'2017-02-15 11:40:53'
# print(time.localtime()) #本地时区的struct_time
# print(time.gmtime())    #UTC时区的struct_time,相差8小时


'''其中计算机认识的时间只能是'时间戳'格式,
而程序员可处理的或者说人类能看懂的时间有: '格式化的时间字符串','结构化的时间' ,于是有了下图的转换关系'''
'''timestamp--->struct_time:localtime、gmtime
   struct_time-->timestamp: mktime'''
print(time.time())
# gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。
print(time.localtime())#不传参数转换本地时间
print(time.localtime(3443434))#转换成相对应的时间
print(time.gmtime())

print(time.mktime(time.localtime(3443434)))

'''
struct_time-->Format String: strftime
Format String-->struct_time:strptime
'''
print(time.strftime("%Y-%m-%d %X",time.localtime()))
print(time.strptime('2018-08-27 16:37:06', '%Y-%m-%d %X'))

'''
#--------------------------按图2转换时间
# asctime([t]) : 把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993'。
# 如果没有参数,将会将time.localtime()作为参数传入。'''
print(time.asctime())#Mon Aug 27 13:53:43 2018

'''# ctime([secs]) : 把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为
# None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。'''
print(time.ctime())  # Mon Aug 27 13:53:43 2018
print(time.ctime(time.time()))  # Mon Aug 27 13:53:43 2018
View Code
#时间加减
import datetime

# print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925
#print(datetime.date.fromtimestamp(time.time()) )  # 时间戳直接转成日期格式 2016-08-19
# print(datetime.datetime.now() )
# print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间+3天
# print(datetime.datetime.now() + datetime.timedelta(-3)) #当前时间-3天
# print(datetime.datetime.now() + datetime.timedelta(hours=3)) #当前时间+3小时
# print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #当前时间+30分


#
# c_time  = datetime.datetime.now()
# print(c_time.replace(minute=3,hour=2)) #时间替换

datetime模块
View Code

3、random模块:

import random
def make_code(n):
    res=''
    for i in range(n):
        s1=chr(random.randint(65,90))
        s2=str(random.randint(0,9))
        res+=random.choice([s1,s2])
    return res

print(make_code(4))
View Code

 

4、OS模块

os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd
os.curdir  返回当前目录: ('.')
os.pardir  获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2')    可生成多层递归目录
os.removedirs('dirname1')    若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname')    生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname')    删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname')    列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove()  删除一个文件
os.rename("oldname","newname")  重命名文件/目录
os.stat('path/filename')  获取文件/目录信息
os.sep    输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep    输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep    输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command")  运行shell命令,直接显示
os.environ  获取系统环境变量
os.path.abspath(path)  返回path规范化的绝对路径
os.path.split(path)  将path分割成目录和文件名二元组返回
os.path.dirname(path)  返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path)  返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path)  如果path是绝对路径,返回True
os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path)  返回path所指向的文件或者目录的最后存取时间
os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小
View Code
os路径处理
#方式一:推荐使用
import os
#具体应用
import os,sys
possible_topdir = os.path.normpath(os.path.join(
    os.path.abspath(__file__),
    os.pardir, #上一级
    os.pardir,
    os.pardir
))
sys.path.insert(0,possible_topdir)


#方式二:不推荐使用
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
View Code

5、sys模块

 

#=========实现打印进度条函数==========
import sys
import time

def progress(percent,width=50):
    if percent >= 1:
        percent=1
    show_str=('[%%-%ds]' %width) %(int(width*percent)*'#')
    print('\r%s %d%%' %(show_str,int(100*percent)),file=sys.stdout,flush=True,end='')


#=========应用==========
data_size=1025
recv_size=0
while recv_size < data_size:
    time.sleep(0.1) #模拟数据的传输延迟
    recv_size+=1024 #每次收1024

    percent=recv_size/data_size #接收的比例
    progress(percent,width=70) #进度条的宽度70
View Code

 

'''
# 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       返回操作系统平台名称'''

import  sys
print(sys.argv)
print(sys.version)
print(sys.path)
print(sys.platform)
View Code

6、hashlib模块

 

# 1、什么叫hash:hash是一种算法(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法),该算法接受传入的内容,经过运算得到一串hash值
# 2、hash值的特点是:
#2.1 只要传入的内容一样,得到的hash值必然一样=====>要用明文传输密码文件完整性校验
#2.2 不能由hash值返解成内容=======》把密码做成hash值,不应该在网络传输明文密码
#2.3 只要使用的hash算法不变,无论校验的内容有多大,得到的hash值长度是固定的


import hashlib
 
m=hashlib.md5()# m=hashlib.sha256()
 
m.update('hello'.encode('utf8'))
print(m.hexdigest())  #5d41402abc4b2a76b9719d911017c592
 
m.update('alvin'.encode('utf8'))
 
print(m.hexdigest())  #92a7e713c30abbb0319fa07da2a5c4af
 
m2=hashlib.md5()
m2.update('helloalvin'.encode('utf8'))
print(m2.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af

'''
注意:把一段很长的数据update多次,与一次update这段长数据,得到的结果一样
但是update多次为校验大文件提供了可能。
'''
View Code
#python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 进行进一步的处理然后再加密
#要想保证hmac最终结果一致,必须保证:
#1:hmac.new括号内指定的初始key一样
#2:无论update多少次,校验的内容累加到一起是一样的内容

import hmac

h1=hmac.new(b'egon')
h1.update(b'hello')
h1.update(b'world')
print(h1.hexdigest())

h2=hmac.new(b'egon')
h2.update(b'helloworld')
print(h2.hexdigest())

h3=hmac.new(b'egonhelloworld')
print(h3.hexdigest())

'''
f1bf38d054691688f89dcd34ac3c27f2
f1bf38d054691688f89dcd34ac3c27f2
bcca84edd9eeb86f30539922b28f3981
'''

注意!注意!注意
View Code

 

7、shutil模块 

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

import shutil
#shutil.copyfileobj(fsrc, fdst[, length])将文件内容拷贝到另一个文件中
# f = open('xiaoming.txt','w',encoding='utf-8')
# f.write('小明你在哪里')
# f.close()
shutil.copyfileobj(open('xiaoming.txt','r',encoding='utf-8'),open('xiaoming02.txt','w',encoding='utf-8'))

#shutil.copyfile(src, dst)拷贝文件
#shutil.copyfile('f1.log', 'f2.log')  # 目标文件无需存在

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

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

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

#shutil.copy2(src, dst)拷贝文件和状态信息
shutil.copy2('f1.log', 'f2.log')

'''shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹'''
shutil.copytree('folder1', 'folder2',
                ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))  
# 目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除 
shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
'''
通常的拷贝都把软连接拷贝成硬链接,即对待软连接来说,创建新的文件
'''
#shutil.rmtree(path[, ignore_errors[, onerror]])递归的去删除文件
shutil.rmtree('folder1')

#shutil.move(src, dst)递归的去移动文件,它类似mv命令,其实就是重命名。
shutil.move('folder1', 'folder3')
View Code
'''shutil.make_archive(base_name, format,...)
创建压缩包并返回文件路径,例如:zip、tar
base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
如:www                =>保存至当前路径
如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/
format:压缩包种类,“zip”, “tar”, “bztar”,“gztar”
root_dir:要压缩的文件夹路径(默认当前目录)
owner:用户,默认当前用户
group:    组,默认当前组
logger:用于记录日志,通常是logging.Logger对象'''

import shutil
shutil.make_archive('xiaomingejjj','zip')
View Code

 

8、shelve模块

 

'''
shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,
可读可写;key必须为字符串,而值可以是python所支持的数据类型

'''

import shelve

f= shelve.open(r'sheve.txt')
f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']}
# f['stu2_info']={'name':'gangdan','age':53}
# f['school_info']={'website':'http://www.pypy.org','city':'beijing'}

print(f['stu1_info']['hobby'])#['piao', 'smoking', 'drinking']
f.close()
View Code

 

9、xml模块

'''
xml的格式如下,就是通过<>节点来区别数据结构的:
# print(root.iter('year')) #全文搜索
# print(root.find('country')) #在root的子节点找,只找一个
# print(root.findall('country')) #在root的子节点找,找所有
'''
#1、解析XML
from xml.etree import cElementTree as ET
tree = ET.parse("xmltest.xml")
# 获取xml文件的根节点
root = tree.getroot()
print(root)

#遍历xml:查   attrib:标签属性
for child in root:
    print('========>', child.tag, child.attrib, child.attrib['name'])
    for i in child:
        print(i.tag, i.attrib, i.text)
print('---------------------------------------')
# 只遍历year 节点
for node in root.iter('year'):
    print(node.tag, node.text)
print('---------------------------------------')
#修改的节点,均是在内存中进行,其不会影响文件中的内容。所以,如果想要修改,则需要重新将内存中的内容写到文件。
for note in root.iter('year'):
    new_year = int(note.text)+1#更改属性
    note.text = str(new_year)
    note.set('update','yes')#设置属性
    note.set('version','1.0')
tree.write('xmltest.xml')
for node in root.iter('year'):
    print(node.tag, node.text)

#删除
for country in root.findall('country'):
    rank =int(country.find('rank').text)
    if rank > 50:
        root.remove(country)
tree.write('xmltest.xml')
View Code
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) #打印生成的格式
View Code

10、configparser模块

import configparser

config=configparser.ConfigParser()
config.read('a.cfg')

#查看所有的标题
res=config.sections() #['section1', 'section2']
print(res)

#查看标题section1下所有key=value的key
options=config.options('section1')
print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary']

#查看标题section1下所有key=value的(key,value)格式
item_list=config.items('section1')
print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')]

#查看标题section1下user的值=>字符串格式
val=config.get('section1','user')
print(val) #egon

#查看标题section1下age的值=>整数格式
val1=config.getint('section1','age')
print(val1) #18

#查看标题section1下is_admin的值=>布尔值格式
val2=config.getboolean('section1','is_admin')
print(val2) #True

#查看标题section1下salary的值=>浮点型格式
val3=config.getfloat('section1','salary')
print(val3) #31.0




import configparser

config=configparser.ConfigParser()
config.read('a.cfg',encoding='utf-8')


#删除整个标题section2
config.remove_section('section2')

#删除标题section1下的某个k1和k2
config.remove_option('section1','k1')
config.remove_option('section1','k2')

#判断是否存在某个标题
print(config.has_section('section1'))

#判断标题section1下是否有user
print(config.has_option('section1',''))


#添加一个标题
config.add_section('egon')

#在标题egon下添加name=egon,age=18的配置
config.set('egon','name','egon')
config.set('egon','age',18) #报错,必须是字符串


#最后将修改的内容写入文件,完成最终的修改
config.write(open('a.cfg','w'))
View Code

 

11、re模块

    re.match 从头开始匹配
    re.search 匹配包含
    re.findall 把所有匹配到的字符放到以列表中的元素返回
    re.splitall 以匹配到的字符当做列表分隔符
    re.sub      匹配字符并替换

 

import re
'''
^元字符:字符串开始位置与匹配规则符合就匹配,否则不匹配,匹配字符串开头。在多行模式中匹配每一行的开头
^元字符如果写到[]字符集里就是反取
'''
print(re.findall('^h','hello world xiao123ming'))#['h']
print(re.findall('^e','hello world xiao123ming'))#[]
print(re.findall('[^a-z]','hello world xiao123ming'))#[' ', ' ', '1', '2', '3']

'''
$元字符:字符串结束位置与匹配规则符合就匹配,否则不匹配,匹配字符串末尾,在多行模式中匹配每一行的末尾
'''
print(re.findall('g$','hello world xiao123ming'))#['g']
print(re.findall('a$','hello world xiao123ming'))#[]

'''
*元字符:需要字符串里完全符合,匹配规则,就匹配,(规则里的*元字符)前面的一个字符可以是0个或多个原本字符
匹配前一个字符0或多次,贪婪匹配前导字符有多少个就匹配多少个很贪婪
如果规则里只有一个分组,尽量避免用*否则会有可能匹配出空字符串'''
print(re.findall('oa*','hello world xiao123mingoa'))#['o', 'o', 'o', 'oa']
print(re.findall("匹配规则*", "这个字符串是否匹配规则则则则则"))#['匹配规则则则则则']

'''
+元字符:需要字符串里完全符合,匹配规则,就匹配,(规则里的+元字符)前面的一个字符可以是1个或多个原本字符
匹配前一个字符1次或无限次,贪婪匹配前导字符有多少个就匹配多少个很贪婪
'''
print(re.findall('oa+','hello world xiao123mingoa'))#['oa']

'''
?元字符,和防止贪婪匹配:需要字符串里完全符合,匹配规则,就匹配,(规则里的?元字符)前面的一个字符可以是0个或1个原本字符
匹配一个字符0次或1次,还有一个功能是可以防止贪婪匹配,详情见防贪婪匹配
'''
print(re.findall('oa?','hello world xiao123mingoa'))#['o', 'o', 'o', 'oa']

'''
{}元字符,范围:
需要字符串里完全符合,匹配规则,就匹配,(规则里的 {} 元字符)前面的一个字符,是自定义字符数,位数的原本字符
{m}匹配前一个字符m次,{m,n}匹配前一个字符m至n次,若省略n,则匹配m至无限次
{0,}匹配前一个字符0或多次,等同于*元字符
{+,}匹配前一个字符1次或无限次,等同于+元字符
{0,1}匹配前一个字符0次或1次,等同于?元字符
'''
print(re.findall('oa{2}','hello world xiao123mingoaaaaa'))#['oaa']

'''
[]元字符,字符集:
需要字符串里完全符合,匹配规则,就匹配,(规则里的 [] 元字符)对应位置是[]里的任意一个字符就匹配
字符集。对应的位置可以是字符集中任意字符。字符集中的字符可以逐个列出,
也可以给出范围,如[abc]或[a-c]。[^abc]表示取反,即非abc。
所有特殊字符在字符集中都失去其原有的特殊含义。用\反斜杠转义恢复特殊字符的特殊含义。
'''
print(re.findall("匹配[a,b,c]规则", "匹配a规则这个字符串是否匹配b规则则则则则"))#['匹配a规则', '匹配b规则']

print('<<<<<<============================>>>>>>>')
'''
反斜杠后边跟普通字符实现特殊功能;(即预定义字符)
预定义字符是在字符集和组里都是有用的
'''
#\d匹配任何十进制数,它相当于类[0-9]
print(re.findall("\d", "匹配规则这2个字符串3是否匹配规则5则则则7则"))#['2', '3', '5', '7']
#\d+如果需要匹配一位或者多位数的数字时用
print(re.findall("\d+", "匹配规则这2个字符串134444是否匹配规则5则则则7则") )#['2', '134444', '5', '7']
#\D匹配任何非数字字符,它相当于类[^0-9]
print(re.findall("\D", "匹则这2个串3是否5则7则"))#['匹', '则', '这', '个', '串', '是', '否', '则', '则']
#\s匹配任何空白字符,它相当于类[\t\n\r\f\v]
print(re.findall("\s", "匹配规则   这2个字符串3是否匹\n配规则5则则则7则"))#[' ', ' ', ' ', '\n']
#\S匹配任何非空白字符,它相当于类[^\t\n\r\f\v]
print(re.findall("\S", "匹则   这2串3匹\n配则7则"))#['匹', '则', '这', '2', '串', '3', '匹', '配', '则', '7', '则']
#\w匹配包括下划线在内任何字母数字字符,它相当于类[a-zA-Z0-9_]
print(re.findall('\w',"hps://ww.c12b.c/"))#['h', 'p', 's', 'w', 'w', 'c', '1', '2', 'b', 'c']
#\W匹配非任何字母数字字符包括下划线在内,它相当于类[^a-zA-Z0-9_]
print(re.findall('\W',"hps://ww.c12b.c/"))#[':', '/', '/', '.', '.', '/']
'''
()元字符,分组:也就是分组匹配,()里面的为一个组也可以理解成一个整体
如果()后面跟的是特殊元字符如   (adc)*   那么*控制的前导字符就是()里的整体内容,不再是前导一个字符'''
print(re.search("(a4)+", "a4a4a4a4a4dg4g654gb").group())#a4a4a4a4a4
print(re.search("a(\d+)", "a466666664a4a4a4dg4g654gb").group())#a466666664
#|元字符,或 |或,或就是前后其中一个符合就匹配
print(re.findall(r"你|好", "a4a4a你4aabc4a4dgg好dg4g654g"))#['你', '好']
'''
r原生字符:
将在python里有特殊意义的字符如\b,转换成原生字符(就是去除它在python的特殊意义),
不然会给正则表达式有冲突,为了避免这种冲突可以在规则前加原始字符r
'''
View Code
'''
match()函数(以后常用)
match,从头匹配一个符合规则的字符串,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None
match(pattern, string, flags=0)
# pattern: 正则模型
# string : 要匹配的字符串
# falgs : 匹配模式
注意:match()函数 与 search()函数基本是一样的功能,不一样的就是match()匹配字符串开始位置的一个符合规则的字符串,
      search()是在字符串全局匹配第一个合规则的字符串

?P<n1>  #?P<>定义组里匹配内容的key(键),<>里面写key名称,值就是匹配到的内容(只对正则函数返回对象的有用)
取出匹配对象方法,只对正则函数返回对象的有用
group() # 获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来,有参取匹配到的第几个如2
groups() # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果
groupdict() # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果
'''
import re
origin = "hello egon bcd egon lge egon acd 19"
#无分组
r1 = re.match("h\w+", origin)
print(r1.group())#hello
print(r1.groups())#()
print(r1.groupdict())#{}
#有分组
r2 = re.match("h(\w+)", origin)
print(r2.group())#hello
print(r2.groups())#('ello',)
print(r2.groupdict())#{}

r3 =re.match("(?P<n1>h)(?P<n2>\w+)", origin)
print(r3.group())#hello
print(r3.groups())#('h', 'ello')
print(r3.groupdict())#{'n2': 'ello', 'n1': 'h'}
View Code
'''
search()函数
search,浏览全部字符串,匹配第一符合规则的字符串,浏览整个字符串去匹配第一个,未匹配成功返回None
search(pattern, string, flags=0)
# pattern: 正则模型
# string : 要匹配的字符串
# falgs : 匹配模式
注意:match()函数 与 search()函数基本是一样的功能,
不一样的就是match()匹配字符串开始位置的一个符合规则的字符串,search()是在字符串全局匹配第一个合规则的字符串
'''

import re
origin = "hello alex bcd alex lge alex acd 19"
#无分组
r = re.search("a\w+", origin)
print(r.group())#alex
print(r.groups())#()
print(r.groupdict())#{}
#有分组
r = re.search("a(\w+).*(\d)", origin)
print(r.group())#alex bcd alex lge alex acd 19
print(r.groups())#('lex', '9')
print(r.groupdict())#{}

r = re.search("a(?P<n1>\w+).*(?P<n2>\d)", origin)
print(r.group())#alex bcd alex lge alex acd 19
print(r.groups())#('lex', '9')
print(r.groupdict())#{'n1': 'lex', 'n2': '9'}
View Code
'''findall()函数(以后常用)
findall(pattern, string, flags=0)
# pattern: 正则模型
# string : 要匹配的字符串
# falgs : 匹配模式
浏览全部字符串,匹配所有合规则的字符串,匹配到的字符串放到一个列表中,未匹配成功返回空列表
注意:一旦匹配成,再次匹配,是从前一次匹配成功的,后面一位开始的,也可以理解为匹配成功的字符串,不在参与下次匹配'''
import re
str = "a2b3c4d5"
print(re.findall("\d+\w\d+",str))#['2b3', '4d5']
print(re.findall("",str))#['', '', '', '', '', '', '', '', '']
#注意:如果没写匹配规则,也就是空规则,返回的是一个比原始字符串多一位的,空字符串列表


origin = "hello alex bcd alex lge alex acd 19"
print(re.findall("a\w+", origin) )#['alex', 'alex', 'alex', 'acd']
print(re.findall("a(\w+)", origin) )#['lex', 'lex', 'lex', 'cd']
# 有分组:只将匹配到的字符串里,组的部分放到列表里返回,相当于groups()方法
print(re.findall("a(?:\w+)", origin))#['alex', 'alex', 'alex', 'acd']
#?:在有分组的情况下,不只拿分组里的字符串,拿所有匹配到的字符串,注意?:只用于不是返回正则对象的函数如findall()

print(re.findall("(a)(\w+)", origin))#[('a', 'lex'), ('a', 'lex'), ('a', 'lex'), ('a', 'cd')]
#多个分组:只将匹配到的字符串里,组的部分放到一个元组中,最后将所有元组放到一个列表里返
#相当于在group()结果里再将组的部分,分别,拿出来放入一个元组,最后将所有元组放入一个列表返回

print(re.findall("(a)(\w+(e))", origin))#[('a', 'le', 'e'), ('a', 'le', 'e'), ('a', 'le', 'e')]
'''
多个分组:只将匹配到的字符串里,组的部分放到一个元组中,最后将所有元组放到一个列表里返
相当于在group()结果里再将组的部分,分别,拿出来放入一个元组,最后将所有元组放入一个列表返回
'''
View Cod正则表达式重点一、
r原生字符
将在python里有特殊意义的字符如\b,转换成原生字符(就是去除它在python的特殊意义),不然会给正则表达式有冲突,
为了避免这种冲突可以在规则前加原始字符r

二、
正则表达式,返回类型为表达式对象的
如:<_sre.SRE_Match object; span=(6, 7), match='a'>
返回对象的,需要用正则方法取字符串,
方法有
group() # 获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来,有参取匹配到的第几个如2
groups() # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果
groupdict() # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果

三、
匹配到的字符串里出现空字符
注意:正则匹配到空字符的情况,如果规则里只有一个组,而组后面是*就表示组里的内容可以是0个或者多过,这样组里就有了两个意思,
一个意思是匹配组里的内容,二个意思是匹配组里0内容(即是空白)所以尽量避免用*否则会有可能匹配出空字符串

四、()分组
注意:分组的意义,就是在匹配成功的字符串中,在提取()里,组里面的字符串

五、
?:在有分组的情况下findall()函数,不只拿分组里的字符串,拿所有匹配到的字符串,
注意?:只用于不是返回正则对象的函数如findall()


12、logging模块

'''
1、logging介绍:
DEBUG:      最详细的日志信息,典型应用场景是 问题诊断
INFO:       信息详细程度仅次于DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作
WARNING:    当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的
ERROR:      由于一个更严重的问题导致某些功能不能正常运行时记录的信息
CRITICAL:   当发生严重错误,导致应用程序不能继续运行时记录的信息

日志级别顺序:DEBUG < INFO < WARNING < ERROR < CRITICAL

日志级别应用场景:
开发应用程序或部署开发环境时,可以使用DEBUG或INFO级别的日志获取尽可能详细的日志信息来进行开发或部署调试;
应用上线或部署生产环境时,应该使用WARNING或ERROR或CRITICAL级别的日志来降低机器的I/O压力和提高获取错误日志信息的效率。
日志级别的指定通常都是在应用程序的配置文件中进行指定的。

注意:
当为某个应用程序指定一个日志级别后,应用程序会记录所有日志级别大于或等于指定日志级别的日志信息,
而不是仅仅记录指定级别的日志信息,nginx、php等应用程序以及这里的python的logging模块都是这样的。
同样,logging模块也可以指定日志记录器的日志级别,只有级别大于或等于该指定日志级别的日志记录才会被输出,
小于该等级的日志记录将会被丢弃

2、logging模块的使用方式介绍
    logging模块提供了两种记录日志的方式:
        第一种方式是使用logging提供的模块级别的函数
        第二种方式是使用Logging日志系统的四大组件
其实,logging所提供的模块级别的日志记录函数也是对logging日志系统相关类的封装而已。
logging模块定义的模块级别的常用函数
            函数                                            说明
logging.debug(msg, *args, **kwargs)    创建一条严重级别为DEBUG的日志记录
logging.info(msg, *args, **kwargs)    创建一条严重级别为INFO的日志记录
logging.warning(msg, *args, **kwargs)    创建一条严重级别为WARNING的日志记录
logging.error(msg, *args, **kwargs)    创建一条严重级别为ERROR的日志记录
logging.critical(msg, *args, **kwargs)    创建一条严重级别为CRITICAL的日志记录
logging.log(level, *args, **kwargs)    创建一条严重级别为level的日志记录
logging.basicConfig(**kwargs)    对root logger进行一次性配置
其中logging.basicConfig(**kwargs)函数用于指定“要记录的日志级别”、“日志格式”、“日志输出位置”、“日志文件的打开模式
'''

import logging

#简单配置
logging.debug("debug_msg")
logging.info("info_msg")
logging.warning("warning_msg")
logging.error("error_msg")
logging.critical("critical_msg")
'''
WARNING:root:warning_msg
ERROR:root:error_msg
CRITICAL:root:critical_msg
输出内容描述:
默认情况下Python的logging模块将日志打印到了标准输出中,
且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING
日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG
默认输出格式为:默认的日志格式为日志级别:Logger名称:用户输出消息
'''

logging.basicConfig(level=logging.DEBUG,
                    format="%(asctime)s %(name)s %(levelname)s %(message)s",
                    datefmt = '%Y-%m-%d  %H:%M:%S %a')
logging.debug("debug_msg1")
logging.info("info_msg1")
logging.warning("warning_ms1")
logging.error("error_msg1")
logging.critical("critical_msg1")
'''
2018-08-29  10:45:07 Wed root DEBUG debug_msg1
2018-08-29  10:45:07 Wed root INFO info_msg1
2018-08-29  10:45:07 Wed root WARNING warning_ms1
2018-08-29  10:45:07 Wed root ERROR error_msg1
2018-08-29  10:45:07 Wed root CRITICAL critical_msg1
'''
'''
logging.basicConfig()函数包含参数说明
参数名称                    描述
filename     指定日志输出目标文件的文件名(可以写文件名也可以写文件的完整的绝对路径,写文件名日志放执行文件目录下,
            写完整路径按照完整路径生成日志文件),指定该设置项后日志信心就不会被输出到控制台了

filemode     指定日志文件的打开模式,默认为'a'。需要注意的是,该选项要在filename指定时才有效

format        指定日志格式字符串,即指定日志输出时所包含的字段信息以及它们的顺序。
           logging模块定义的格式字段下面会列出。

datefmt        指定日期/时间格式。需要注意的是,该选项要在format中包含时间字段%(asctime)s时才有效

level        指定日志器的日志级别

stream        指定日志输出目标stream,如sys.stdout、sys.stderr以及网络stream。
           需要说明的是,stream和filename不能同时提供,否则会引发 ValueError异常

style        Python 3.2中新添加的配置项。指定format格式字符串的风格,可取值为'%'、'{'和'$',默认为'%'

handlers    Python 3.3中新添加的配置项。该选项如果被指定,它应该是一个创建了多个Handler的可迭代对象,
        这些handler将会被添加到root logger。 需要说明的是:filename、stream和handlers
        这三个配置项只能有一个存在,不能同时出现2个或3个,否则会引发ValueError异常。



logging模块中定义好的可以用于format格式字符串说明

字段/属性名称    使用格式                    描述
asctime                %(asctime)s将日志的时间构造成可读的形式,默认情况下是‘2016-02-08 12:00:00,123’精确到毫秒
name                %(name)s    所使用的日志器名称,默认是'root',因为默认使用的是 rootLogger
filename            %(filename)s    调用日志输出函数的模块的文件名; pathname的文件名部分,包含文件后缀
funcName            %(funcName)s    由哪个function发出的log, 调用日志输出函数的函数名
levelname            %(levelname)s    日志的最终等级(被filter修改后的)
message                %(message)s    日志信息, 日志记录的文本内容
lineno                %(lineno)d    当前日志的行号, 调用日志输出函数的语句所在的代码行
levelno                %(levelno)s    该日志记录的数字形式的日志级别(10, 20, 30, 40, 50)
pathname            %(pathname)s    完整路径 ,调用日志输出函数的模块的完整路径名,可能没有
process                %(process)s    当前进程, 进程ID。可能没有
processName        %(processName)s    进程名称,Python 3.1新增
thread                %(thread)s    当前线程, 线程ID。可能没有
threadName            %(thread)s    线程名称
module                %(module)s    调用日志输出函数的模块名filename的名称部分,不包含后缀即不包含文件后缀的文件名
created                %(created)f    当前时间,用UNIX标准的表示时间的浮点数表示; 
                    日志事件发生的时间--时间戳,就是当时调用time.time()函数返回的值
relativeCreated     %(relativeCreated)d    输出日志信息时的,自Logger创建以 来的毫秒数; 
                    日志事件发生的时间相对于logging模块加载时间的相对毫秒数
msecs                %(msecs)d    日志事件发生事件的毫秒部分。
                   logging.basicConfig()中用了参数datefmt,将会去掉asctime中产生的毫秒部分,可以用这个加上
'''

LOG_FORMAT = "%(asctime)s %(name)s %(levelname)s %(pathname)s %(message)s "#配置输出日志格式
DATE_FORMAT = '%Y-%m-%d  %H:%M:%S %a ' #配置输出时间的格式,注意月份和天数不要搞乱了
logging.basicConfig(level=logging.DEBUG,
                    format=LOG_FORMAT,
                    datefmt = DATE_FORMAT ,
                    filename=r"f:\test.log" #有了filename参数就不会直接输出显示到控制台,而是直接写入文件
                    )
logging.debug("msg1")
logging.info("msg2")
logging.warning("msg3")
logging.error("msg4")
logging.critical("msg5")
'''
2018-08-29  11:12:00 Wed  root DEBUG F:/PycharmProjects/untitled/Day8/logging模块.py msg1 
2018-08-29  11:12:00 Wed  root INFO F:/PycharmProjects/untitled/Day8/logging模块.py msg2 
2018-08-29  11:12:00 Wed  root WARNING F:/PycharmProjects/untitled/Day8/logging模块.py msg3 
2018-08-29  11:12:00 Wed  root ERROR F:/PycharmProjects/untitled/Day8/logging模块.py msg4 
2018-08-29  11:12:00 Wed  root CRITICAL F:/PycharmProjects/untitled/Day8/logging模块.py msg5 
'''
View Code
'''
logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()(分别用以记录不同级别的日志信息)
logging.basicConfig()(用默认日志格式(Formatter)为日志系统建立一个默认的流处理器(StreamHandler),
设置基础配置(如日志级别等)并加到root logger(根Logger)中)这几个logging模块级别的函数。

第二种是一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger)。
logging日志模块四大组件:在介绍logging模块的日志流处理流程之前,我们先来介绍下logging模块的四大组件:

组件名称    对应类名    功能描述
日志器        Logger        提供了应用程序可一直使用的接口
处理器        Handler        将logger创建的日志记录发送到合适的目的输出
过滤器        Filter        提供了更细粒度的控制工具来决定输出哪条日志记录,丢弃哪条日志记录
格式器        Formatter    决定日志记录的最终输出格式
logging模块就是通过这些组件来完成日志处理的,上面所使用的logging模块级别的函数也是通过这些组件对应的类来实现的。
这些组件之间的关系描述:
    日志器(logger)需要通过处理器(handler)将日志信息输出到目标位置,如:文件、sys.stdout、网络等;
    不同的处理器(handler)可以将日志输出到不同的位置;
    日志器(logger)可以设置多个处理器(handler)将同一条日志记录输出到不同的位置;
    每个处理器(handler)都可以设置自己的过滤器(filter)实现日志过滤,从而只保留感兴趣的日志;
    每个处理器(handler)都可以设置自己的格式器(formatter)实现同一条日志以不同的格式输出到不同的地方。
简单点说就是:日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)
还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。

logging日志模块相关类及其常用方法介绍:与logging四大组件相关的类:Logger, Handler, Filter, Formatter。
Logger类
Logger对象有3个任务要做:
1)向应用程序代码暴露几个方法,使应用程序可以在运行时记录日志消息;
2)基于日志严重等级(默认的过滤设施)或filter对象来决定要对哪些日志进行后续处理;
3)将日志消息传送给所有感兴趣的日志handlers。
Logger对象最常用的方法分为两类:配置方法 和 消息发送方法

最常用的配置方法如下:
方法                                                    描述
Logger.setLevel()                                    设置日志器将会处理的日志消息的最低严重级别
Logger.addHandler() 和 Logger.removeHandler()        为该logger对象添加 和 移除一个handler对象
Logger.addFilter() 和 Logger.removeFilter()            为该logger对象添加 和 移除一个filter对象
 
logger对象配置完成后,可以使用下面的方法来创建日志记录:
方法                                                                                            描述
Logger.debug()info()warning()error()critical()    创建一个与它们的方法名对应等级的日志记录
Logger.exception()                                创建一个类似于Logger.error()的日志消息
Logger.log()                                    需要获取一个明确的日志level参数来创建一个日志记录
一个Logger对象呢?一种方式是通过Logger类的实例化方法创建一个Logger类的实例,
但是我们通常都是用第二种方式--logging.getLogger()方法。
logging.getLogger()方法有一个可选参数name,
该参数表示将要返回的日志器的名称标识,如果不提供该参数,则其值为'root'。
若以相同的name参数值多次调用getLogger()方法,将会返回指向同一个logger对象的引用。
多次使用注意不能创建多个logger,否则会出现重复输出日志现象。

关于logger的层级结构与有效等级的说明:
logger的名称是一个以'.'分割的层级结构,每个'.'后面的logger都是'.'前面的logger的children,
例如,有一个名称为 foo 的logger,其它名称分别为 foo.bar, foo.bar.baz 和 foo.bam都是 foo 的后代。
logger有一个"有效等级(effective level)"的概念
如果一个logger上没有被明确设置一个level,那么该logger就是使用它parent的level;
如果它的parent也没有明确设置level则继续向上查找parent的parent的有效level,
依次类推,直到找到个一个明确设置了level的祖先为止。需要说明的是,root logger总是会有一个明确的level设置(默认为 WARNING)
当决定是否去处理一个已发生的事件时,logger的有效等级将会被用来决定是否将该事件传递给该logger的handlers进行处理。
child loggers在完成对日志消息的处理后,默认会将日志消息传递给与它们的祖先loggers相关的handlers。
因此,我们不必为一个应用程序中所使用的所有loggers定义和配置handlers,只需要为一个顶层的logger配置handlers,
然后按照需要创建child loggers就可足够了。我们也可以通过将一个logger的propagate属性设置为False来关闭这种传递机制。


Handler类
Handler对象的作用是(基于日志消息的level)将消息分发到handler指定的位置(文件、网络、邮件等)。
Logger对象可以通过addHandler()方法为自己添加0个或者更多个handler对象。比如,一个应用程序可能想要实现以下几个日志需求:
1)把所有日志都发送到一个日志文件中;
2)把所有严重级别大于等于error的日志发送到stdout(标准输出);
3)把所有严重级别为critical的日志发送到一个email邮件地址。
    这种场景就需要3个不同的handlers,每个handler复杂发送一个特定严重级别的日志到一个特定的位置。

Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略
Handler.setFormatter():给这个handler选择一个格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象
需要说明的是,应用程序代码不应该直接实例化和使用Handler实例。
因为Handler是一个基类,它只定义了素有handlers都应该有的接口,同时提供了一些子类可以直接使用或覆盖的默认行为。
下面是一些常用的Handler:

Handler                                    描述
logging.StreamHandler                    将日志消息发送到输出到Stream,如std.out, std.err或任何file-like对象。
logging.FileHandler                        将日志消息发送到磁盘文件,默认情况下文件大小会无限增长
logging.handlers.RotatingFileHandler    将日志消息发送到磁盘文件,并支持日志文件按大小切割
logging.hanlders.TimedRotatingFileHandler    将日志消息发送到磁盘文件,并支持日志文件按时间切割
logging.handlers.HTTPHandler                将日志消息以GET或POST的方式发送给一个HTTP服务器
logging.handlers.SMTPHandler                将日志消息发送给一个指定的email地址
logging.NullHandler                            该Handler实例会忽略error messages,通常被想使用logging的library开发者使用来
                                            避免'No handlers could be found for logger XXX'信息的出现。
 

Formater类
Formater对象用于配置日志信息的最终顺序、结构和内容。
与logging.Handler基类不同的是,应用代码可以直接实例化Formatter类。
另外,如果你的应用程序需要一些特殊的处理行为,也可以实现一个Formatter的子类来完成。
Formatter类的构造方法定义如下:
logging.Formatter.__init__(fmt=None, datefmt=None, style='%')

可见,该构造方法接收3个可选参数:
fmt:指定消息格式化字符串,如果不指定该参数则默认使用message的原始值
datefmt:指定日期格式字符串,如果不指定该参数则默认使用"%Y-%m-%d %H:%M:%S"
style:Python 3.2新增的参数,可取值为 '%', '{'和 '$',如果不指定该参数则默认使用'%'
一般直接用logging.Formatter(fmt, datefmt)

 Filter类(暂时了解)
Filter可以被Handler和Logger用来做比level更细粒度的、更复杂的过滤功能。
Filter是一个过滤器基类,它只允许某个logger层级下的日志事件通过过滤。该类定义如下:
class logging.Filter(name='')
      filter(record)
比如,一个filter实例化时传递的name参数值为'A.B',那么该filter实例将只允许名称为类似如下规则的loggers产生的日志记录
通过过滤:'A.B','A.B,C','A.B.C.D','A.B.D',而名称为'A.BB', 'B.A.B'的loggers产生的日志则会被过滤掉。
如果name的值为空字符串,则允许所有的日志事件通过过滤。
filter方法用于具体控制传递的record记录是否能通过过滤,如果该方法返回值为0表示不能通过过滤,返回值为非0表示可以通过过滤。

说明:
如果有需要,也可以在filter(record)方法内部改变该record,比如添加、删除或修改一些属性。
我们还可以通过filter做一些统计工作,比如可以计算下被一个特殊的logger或handler所处理的record数量等。
'''



'''
日志流处理简要流程
1、创建一个logger
2、设置下logger的日志的等级
3、创建合适的Handler(FileHandler要有路径)
4、设置下每个Handler的日志等级
5、创建下日志的格式
6、向Handler中添加上面创建的格式
7、将上面创建的Handler添加到logger中
8、打印输出logger.debug\logger.info\logger.warning\logger.error\logger.critical
'''
import logging
def log(msg):
    logger = logging.getLogger("logging")
    logger.setLevel(logging.DEBUG)

    fh = logging.FileHandler('test.log',encoding='utf-8')
    ch = logging.StreamHandler()

    formatter = logging.Formatter(  fmt="%(asctime)s %(name)s %(filename)s %(message)s",datefmt="%Y/%m/%d %X" )

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

    logger.addHandler(fh)
    logger.addHandler(ch)

    logger.info(msg)
    # 解决方案 添加removeHandler语句,每次用完之后移除Handler
    logger.removeHandler(fh)
    logger.removeHandler(ch)

# logger.warning("泰拳警告")
# logger.info("提示")
# logger.error("错误")
log("小明")
log("小民")
View Code
import logging
def log():
    logger = logging.getLogger("dashuang.gu")
    logger.setLevel(logging.DEBUG)
    if not logger.handlers:
        fh = logging.FileHandler('example.log',encoding='utf-8')
        ch = logging.StreamHandler()

        formatter = logging.Formatter(fmt="%(asctime)s %(name)s %(filename)s %(message)s",datefmt="%Y/%m/%d %X")

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

        logger.addHandler(fh)
        logger.addHandler(ch)
    return logger

logger = log()
logger.debug('查错')
logger.info('错误')
logger.warning('一般')
logger.error('严重')
logger.critical('shutdown')
View Code

 



posted @ 2018-08-28 17:05  Dashuang  阅读(240)  评论(0编辑  收藏  举报