zoukankan      html  css  js  c++  java
  • python--常见模块

    本节大纲:

    1.模块介绍

    2.time&datetime

    3.random.

    4.os

    5.sys

    6.shutil

    7.json&picle

    8.shelve

    9.xml处理

    10.yaml处理

    11.configparser

    12.hashlib

    13.subprocess

    14.logging模块

    15.re正则表达式

    模块的定义:用一堆代码实现了某个功能的代码集合

    类似与函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合,而对于一个复杂的功能来说,可能需要多个函数才能完成(函数又可以在不同的.py文件中),n个.py文件组成的代码集合就称为模块

    如:os是系统相关的模块,file是文件操作相关的模块

    模块分为三种:

    自定义模块

    内置模块

    开源模块(第三方模块)

    自定义模块

    1.定义模块

    情景一

    情景二

     2.导入模块

    在python中,要想使用模块,需要先导入,导入模块有以下几种方式:

    如要导入一个名为module的模块

    1 import module
    2 from module.xx.xx import xx
    3 from module.xx.xx import xx as rename  
    4 from module.xx.xx import *
    #*号这种导入模式会导入一个模块中的所有项目,这种方法虽然很简单,便利,但是不推荐使用,
    #因为引入的其他来源的命令,很可能覆盖了已有的定义,存在一定的安全隐患

    导入模块其实就是在告诉Python解释器去解释那个py文件

    如果导入的是一个py文件,解释器就解释该py文件

    如果导入的是一个包,解释器就解释该包下的__init__.py文件

    Python中,导入模块时是根据那个路径作为基准来进行的呢?

    可通过sys模块中的sys.path来查看

    import sys
    print(sys.path)
    
    #['D:\PycharmProjects\fullstack\homework_oneday\module\module_file', 'D:\PycharmProjects\fullstack', 'C:\Program Files\Python35\python35.zip', 'C:\Program Files\Python35\DLLs', 'C:\Program Files\Python35\lib', 'C:\Program Files\Python35', 'C:\Program Files\Python35\lib\site-packages']

    如果sys.path路径列表中没有你想要的路径,可以通过sys.path.append('路径')添加

    通过os模块可以获取各种目录

    import sys
    import os
    
    pre_path = os.path.abspath('../')
    sys.path.append(pre_path)

    包(package)的概念

    我们先设想一下,如果不同的人编写的模块名相同怎么办?为了避免冲突,Python又引进了按目录来组织模块的方法,称为包(package)。

    假设,如下图,我的两个time_file.py模块名字重名了,但是这两个模块的功能都不相同,如果这两个模块都在同一级目录中,那么我在其他地方要调用这个time_file.py模块,那么这个时候就会发生冲突,在这里我们就可以通过包来组织模块,避免冲突,

    方法是:选择一个顶层包名,引入包以后,只要顶层的包名不与别人冲突,那这个包里面的模块都不会与别人冲突了。

    请注意:每个包目录下来都会有一个__init__.py的文件,这个文件必须是存在的,否则,Python就不把这个目录当成普通目录,而不是一个包,__init__.py可以是空文件,也可以有python代码,__init__.py本身就是一个文件,它的模块命就是对应的包名,它一般由于做接口文件

    开源模块(第三方模块) 

    一.下载安装

    下载安装的两种方式

    1 yum
    2 pip
    3 apt-get
    4 ...
    1 下载源码
    2 解压源码
    3 进入目录
    4 编译源码  python setup.py build
    5 安装源码  python setup.py install

    注:在使用源码安装时,需要使用到gcc编译和Python开发环境,所以,要事先将环境安装上

    1 yum install gcc
    2 yum install python-devel
    3 4 apt-get python-dev

    安装成功后,模块会自动安装到sys.path中的某个目录中,如:

    1 /usr/lib/python3.5/site-packages/

    导入模块的方式同自定义模块导入的方式一样

     三.模块paramiko(晚上回家补齐)

    内置模块

    一.time()模块

    在python中,通常有以下几种方式来表示时间:

    时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量,

    格式化的时间字符串:

    元组(struct_time):struct_time元组共有9个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)

    1 import time
    2 
    3 print(time.time())  # 返回当前时间的时间戳 1481597763.3750336
    4 print(time.localtime())  # 将一个时间戳转换为当前时区
    5 #  time.struct_time(tm_year=2016, tm_mon=12, tm_mday=13, tm_hour=10, tm_min=57, tm_sec=31, tm_wday=1, tm_yday=348, tm_isdst=0)
    6 print(time.gmtime())  # localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。
    7 #  time.struct_time(tm_year=2016, tm_mon=12, tm_mday=13, tm_hour=3, tm_min=0, tm_sec=47, tm_wday=1, tm_yday=348, tm_isdst=0)
     1 print(time.ctime())  # Tue Dec 13 21:29:55 2016
     2 
     3 print(time.gmtime(time.time()-9000))
     4 #返回utc时间的struc时间对象格式
     5 #time.struct_time(tm_year=2016, tm_mon=12, tm_mday=13, tm_hour=11, tm_min=2, tm_sec=17, tm_wday=1, tm_yday=348, tm_isdst=0)
     6 
     7 
     8 
     9 #日期转换成时间戳
    10 time_struct = time.strptime("2016-12-12 18:24:30","%Y-%m-%d %X")
    11 print(time_struct) 
    12 #time.struct_time(tm_year=2016, tm_mon=12, tm_mday=12, tm_hour=18, tm_min=24, tm_sec=30, tm_wday=0, tm_yday=347, tm_isdst=-1)
    13 #将日期字符串转换struct时间对象格式
    14 
    15 
    16 #将struct时间对象转换成时间戳
    17 time_struct = time.strptime("2016-12-12 18:24:30","%Y-%m-%d %X")
    18 time_one_struct = time.mktime(time_struct)
    19 print(time_one_struct)
    20 #1481538270.0
    21 
    22 #将时间戳转换为字符串格式
    23 print(time.gmtime(time.time()-99999)) # 将utc时间戳转换成struct_time格式
    24 
    25 #将utc struct_time格式转换为指定的字符串格式
    26 print(time.strftime("%Y-%m-%d %X",time.gmtime()))

    #sleep() #线程推迟自定的时间运行,单位为秒

    #clock()
    #这个需要注意啦,在不同的系统上含义不同,在unix系统上,它返回的是'进程时间',用秒表示的浮点数(时间戳)
    #在windows中,第一次调用,返回的是进程运行的实际时间,而第二次之后的调用是自第一次调用后到现在的运行
    #的时间,即两次的时间差

     1 import datetime
     2 
     3 #显示当前时间日期
     4 print(datetime.datetime.now())
     5 #  2016-12-13 21:58:43.911173
     6 
     7 #当前时间+3天
     8 print(datetime.datetime.now() + datetime.timedelta(3))
     9 #2016-12-16 22:01:17.556961
    10 
    11 #当前时间-3天
    12 print(datetime.datetime.now() + datetime.timedelta(-3))
    13 #2016-12-10 22:04:18.496310
    14 
    15 #当前时间+30分
    16 print(datetime.datetime.now() + datetime.timedelta(hours=3))
    17 #2016-12-14 01:05:43.915196
    18 
    19 #时间替换
    20 c_time = datetime.datetime.now()
    21 print(c_time.replace(minute=3,hour=2))
    22 #2016-12-13 02:03:14.949403  将小时数与分钟数替换
    23 
    24 #时间戳直接转换为日期格式
    25 print(datetime.date.fromtimestamp(time.time()))  # 2016-12-13

     二random模块

     1 import random
     2 
     3 #0,1之间时间生成的浮点数  float
     4 print(random.random())
     5 
     6 #随机生成传入参数范围内的数字 即 1,2,3
     7 print(random.randint(1,3))
     8 
     9 #随机生成传入参数范围内的数字,range顾头不顾尾
    10 print(random.randrange(1,3))
    11 
    12 #随机选择任意一个数字
    13 print(random.choice([1,'23',[4,5]]))
    14 
    15 #随机选择任意两个数字
    16 print(random.sample([1,'23',[4,5]],2))

    小测试:随机生成一个5位数的验证码

     1 import random
     2 
     3 def v_code():
     4     code = ''
     5     for i in range(5):
     6         num = random.randint(0,9)
     7         alf = chr(random.randint(65,90))
     8         add = random.choice([num,alf])
     9         code += str(add)
    10     return code
    11 result = v_code()
    12 print(result)

     三.os模块

    os模块提供对操作系统进行调用的接口

    1 import os
    2 print(os.getcwd())
    3 获取当前的工作目录,即当前Python脚本工作的目录路径,相当于Linux中的pwd
    4 
    5 print(os.chdir("当前目录名称/../../"))  # 改变当前脚本工作目录,相当于shell下的cd
    6 
    7 os.makedirs("dirname1/dirname2")  # 可生成多层递归目录
    8 os.removedirs("dirname1/dirname2")  # 若目录为空,则删除,并递归到上一级目录,如也为空则删除,以此类推
     1 import os
     2 
     3 # 获取当前的工作目录,即当前Python脚本工作的目录路径,相当于Linux中的pwd
     4 print(os.getcwd())
     5 
     6 
     7 print(os.chdir("D:\PycharmProjects\fullstack"))  # 改变当前脚本工作目录,相当于shell下的cd
     8 
     9 os.makedirs("dirname1/dirname2")  # 可生成多层递归目录
    10 os.removedirs("dirname1//dirname2")  # 若目录为空,则删除,并递归到上一级目录,如也为空则删除,以此类推
    11 os.mkdir("dirname")  # 生成当级目录,相当于shell中的mkdir dirname
     1 os.rmdir("namedir")  # 删除单级空目录,若目录不为空则无法删除,报错,相当于shell中的rm dirname
     2 print(os.listdir("dirname")) # 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表的方式打印
     3 os.remove("filename")  # 删除一个文件
     4 os.rename("oldname","newname")  # 重命名文件/目录
     5 os.stat("path/filename")  # 获取文件/目录信息
     6 print(os.sep)  #  输出操作系统特定的路径分隔符,win下为'\',Linux下为'/'
     7 print(os.linesep)  # 输出当前平台使用的行终止符,win下为'	
    ',Linux下为'
    '
     8 print(os.pathsep)  # 输入用户分割文件路径的字符串
     9 print(os.name)  # 输出字符串指示当前使用平台,win->'nt',Linux->'posix'
    10 print(os.system("bash command"))  # 运行shell命令,直接显示
    11 print(os.environ)  # 获取系统环境变量
    12 print(os.path.abspath(path))  # 返回path规范化的绝对路径
    13 print(os.path.split(path))  # 将path分割成目录和文件名,二元组返回
    14 print(os.path.dirname(path)) # 返回path的目录,其实就是os.path.split(path)的第一个元素
    15 print(os.path.basename(path))  # 返回path最后的文件名,如果path以/或结尾,就会返回空值
    16 print(os.path.exists(path)) # 如果path存在,返回True,如果不存在,就返回False
    17 print(os.path.isabs(path))  # 如果path是绝对路径返回True,不存在返回False
    18 print(os.path.join(path1[,path2[,path3]])) # 将多个路劲组合后返回,
    19 print(os.path.join(path1,path2,**)) # 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
    20 
    21 #返回path所指向的文件或者目录的最后存取时间,可通过time模块,转换时间格式
    22 a = os.path.getatime(r"D:PycharmProjectsfullstackhomework_onedaymodulemodule_file")
    23 print(time.gmtime(a))
    24 
    25 print(os.path.getmtime(path))  #返回path指向的文件或者目录的最后修改时间

    四.sys模块

    1 import sys
    2 sys.argv  # 命令行参数List,第一个元素是程序本身路径
    3 sys.version  # 获取Python解释程序的版本信息
    4 sys.exit(n)  # 退出程序,正常退出时exit(0)
    5 sys.path  # 返回模块的搜索路劲,初始话时使用PYTHONPATH环境变量的值
    6 sys.platform  # 返回操作系统平台名称
    7 sys.stdout.write('please:')  # 标志输出
    8 val = sys.stdin.readline()[:-1]

    小测试:进度条

    1 import sys, time
    2 for i in range(10):
    3     sys.stdout.write("#")
    4     time.sleep(1)
    5     sys.stdout.flush()

    五.json&pickle

    在Python中有一个eval内置方法,可以还原对象原始的数据类型,不过,eval方法是有局限性的,不是任何场合都可以使用,对应普通的数据类型,json.loads和eval都能用,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值

    1 x = "[null,true,false]"
    2 print(eval(x))  # eval会报错
    3 print(json.loads(x))

    什么是序列化

    我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化。在Python中叫picking,在其他语言为

    serialization,marshalling,flattening等等,都是一个意思。

    序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。

    反过来,把变量内容从序列化的对象从新读到内存里称之为反序列化,即unpicking.

    json

    如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如xml,但更好的方法是序列化为json,因为json表示出来就是一个字符串,可以被所有语言读取,也可以方便的存储到磁盘或者通过网络传输,json不仅是标准格式,并且比xml更快,而且可以直接在web页面中读取,非常方便

    json表示的对象就是标准的JavaScript语言的对象,json和Python内置的数据类型对应如下:

     1 import json
     2 
     3 dic = {"name":"alex","age":23,"sex":"male"}
     4 j = json.dumps(dic)
     5 print(type(j))  # <class 'str'>
     6 
     7 
     8 f = open('json_file.txt','w',encoding='utf-8')
     9 f.write(j)   #----------等价于json.dump(dic,f)
    10 f.close()
    11 
    12 
    13 #----------------反序列化
    14 f = open('json_file.txt','r',encoding='utf-8')
    15 data = json.loads(f.read())
    16 print(data,type(data))
    17 f.close()
    18 # {'sex': 'male', 'name': 'alex', 'age': 23} <class 'dict'>
    19 
    20 注意事项:json 不认单引号,如果你要将你的代码,转为json类型,那么在你的代码中请使用双引号
    21 dic = '{"a":"abc"}'
    22 print(json.loads(dic))

    pickle

     1 import pickle
     2 
     3 dic = {"name":"alex","age":23,"sex":"male"}
     4 print(type(dic))  # <class 'dict'>
     5 
     6 j = pickle.dumps(dic)
     7 print(type(j))  # <class 'bytes'>
     8 
     9 f = open('test_pickle.txt','wb')  #注意w是写入str,wb是写入bytes,j是'bytes'
    10 f.write(j)  #-------------------等价于pickle.dump(dic,f)
    11 f.close()
    12 
    13 #------------------反序列化
    14 f = open("test_pickle.txt","rb")
    15 data = pickle.loads(f.read())  # 等价于data = pickle.load(f)
    16 f.close()
    17 print(data["age"])  # 23

    pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此

    都不兼容,因此,只能用pickle保存那些不重要的数据,不能成功地反序列化也没关系

     六 shelve模块

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

    1 import shelve
    2 f = shelve.open('shelve_file.txt')
    3 # f["stu1_info"] = {"name":"jack","age":"18"}
    4 # f["stu2_info"] = {"name":"rain","age":"21"}
    5 # f["stu3_info"] = {"name":"tom","age":"34"}
    6 # f.close()
    7 print(f.get("stu1_info"))  # {'name': 'jack', 'age': '18'}
    8 print(f.get("stu1_info")["age"])  # 18

    7 xml模块

    xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但是json使用起来更简单,因为json还没有诞生,大家只能选择用xml,至今很多传统公司和金融行业的很多系统的接口还主要是xml

    xml格式如下,就是通过<>节点来区别数据结构的:

     1 <?xml version="1.0"?>
     2 <data>
     3     <country name="Liechtenstein">
     4         <rank updated="yes">2</rank>
     5         <year>2008</year>
     6         <gdppc>141100</gdppc>
     7         <neighbor name="Austria" direction="E"/>
     8         <neighbor name="Switzerland" direction="W"/>
     9     </country>
    10     <country name="Singapore">
    11         <rank updated="yes">5</rank>
    12         <year>2011</year>
    13         <gdppc>59900</gdppc>
    14         <neighbor name="Malaysia" direction="N"/>
    15     </country>
    16     <country name="Panama">
    17         <rank updated="yes">69</rank>
    18         <year>2011</year>
    19         <gdppc>13600</gdppc>
    20         <neighbor name="Costa Rica" direction="W"/>
    21         <neighbor name="Colombia" direction="E"/>
    22     </country>
    23 </data>

    xml协议在各个语言里的都是支持的,在Python中可以用以下模块操作xml:

     1 import xml.etree.ElementTree as ET
     2 tree = ET.parse("xml_file.xml")
     3 root = tree.getroot()  #获取xml文件对象
     4 print(root.tag)  # data
     5 
     6 # 遍历xml文档
     7 for item in root:
     8     print(item.tag,item.attrib)
     9     for i in item:
    10         print(i.tag,i.attrib)
    11 
    12 # 只遍历year节点
    13 for node in root.iter("year"):
    14     print(node.tag,node.text)
    15 
    16 
    17 # 修改
    18 for node in root.iter("year"):
    19     new_year = int(node.text) +1
    20     node.text = str(new_year)
    21     node.set("updated","yes")
    22 tree.write("xml_file.xml")
    23 
    24 # 删除
    25 for country in root.findall('country'):
    26     rank = int(country.find('rank').text)
    27     if rank > 50:
    28         root.remove(country)
    29 
    30 tree.write('output.xml')

    自己创建xml文档

     1 import xml.etree.ElementTree as ET
     2 new_xml = ET.Element("namelist")
     3 name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
     4 age = ET.SubElement(name,"age",attrib={"checked":"no"})
     5 sex = ET.SubElement(name,"sex")
     6 sex.text = "33"
     7 name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
     8 age = ET.SubElement(name2,"age")
     9 age.text = "19"
    10 et = ET.ElementTree(new_xml)  # 生成文档格式
    11 et.write("test.xml",encoding="utf-8",xml_declaration=True)
    12 ET.dump(new_xml)  # 打印生成格式

     8 configparser模块

    用于对特定的配置进行操作,当前模块的名称在Python3.x版本中变更为configparser

    我们来看一下Linux中常见软件,配置格式如下:

     1 [DEFAULT]
     2 ServerAliveInterval = 45
     3 Compression = yes
     4 CompressionLevel = 9
     5 ForwardX11 = yes
     6   
     7 [bitbucket.org]
     8 User = hg
     9   
    10 [topsecret.server.com]
    11 Port = 50022
    12 ForwardX11 = no

    如果想用Python生成一个这样的文档怎么做呢

     1 import configparser
     2 
     3 config = configparser.ConfigParser()
     4 config["DEFAULT"] = {"ServerAliveInterval":"45",
     5                         "Compression":"yes",
     6                         "CompressionLevel":"9"}
     7 config["bitbucket.org"] = {}
     8 config["bitbucket.org"]["User"] = "jack"
     9 config["topsecret.server.com"] = {}
    10 topsecret = config["topsecret.server.com"]
    11 topsecret["Host Port"] = "5002"
    12 topsecret["Forwardx11"] = "no"
    13 config["DEFAULT"]["Forwardx11"] = "yes"
    14 with open("example.ini" ,"w",encoding="utf-8") as configfile:
    15     config.write(configfile)

    增删改查

     1 import configparser
     2 config = configparser.ConfigParser()
     3 #
     4 print(config.sections())  # []
     5 config.read("example.ini")
     6 print(config.sections())  # ['bitbucket.org', 'topsecret.server.com']
     7 print("bytebong.com" in config)  # False
     8 print(config["bitbucket.org"]["User"])  # jack
     9 print(config["topsecret.server.com"]["Forwardx11"])  # no
    10 for key in config["bitbucket.org"]:
    11     print(key)
    12 
    13 #user
    14 #compressionlevel
    15 #serveraliveinterval
    16 #compression
    17 #forwardx11
    18 
    19 print(config.options("bitbucket.org"))
    20 # ['user', 'compressionlevel', 'serveraliveinterval', 'compression', 'forwardx11']
    21 print(config.items("bitbucket.org"))
    22 # [('compressionlevel', '9'), ('serveraliveinterval', '45'), ('compression', 'yes'), ('forwardx11', 'yes'), ('user', 'jack')]
    23 print(config.get("bitbucket.org","compression"))  # yes
     1 #---------------------------------------------删,改,增
     2 (config.write(open('i.cfg', "w")))
     3 
     4 
     5 config.add_section('yuan')
     6 
     7 config.remove_section('topsecret.server.com')
     8 config.remove_option('bitbucket.org','user')
     9 
    10 config.set('bitbucket.org','k1','11111')
    11 
    12 config.write(open('i.cfg', "w"))

    9 hashlib

    用于加密相关的操作,代替了md5模块和sha模块,只要提供SHA1,SHA224,SHA256,SHA384,SHA512,MD5算法

    import md5
    hash = md5.new()
    hash.update('admin')
    print hash.hexdigest()
    import sha
    
    hash = sha.new()
    hash.update('admin')
    print hash.hexdigest()
     1 import hashlib
     2 m = hashlib.md5()  # m = hashlib.sha256
     3 m.update("admin".encode("utf-8"))
     4 print(m.hexdigest())  # 21232f297a57a5a743894a0e4a801fc3
     5 
     6 m.update("jack".encode("utf-8"))
     7 print(m.hexdigest())  # f75c16c62166e263e5f8d84881c15de9
     8 
     9 m2 = hashlib.md5()
    10 m2.update("jack".encode("utf-8"))
    11 print(m2.hexdigest())  # 4ff9fc6e4e5d5f590c4f2134a8cc96d1
    12 
    13 
    14 m3 = hashlib.md5()
    15 m3.update("hellejack".encode("utf-8"))
    16 print(m3.hexdigest())  # 7a477fa1d4918d6af53fc6115e5b4376

    以上的加密算法虽然非常厉害,但还是存在缺陷,即:通过撞库可以反解,所以,有必要对加密算法中添加自定义key再来做加密

    1 import hashlib
    2 m = hashlib.md5("dfs9Ys".encode("utf-8"))
    3 m.update("jack".encode("utf-8"))
    4 print(m.hexdigest())  # 3566e566a677ba0fb8b7ec637ff707a9

    python中还有一个hmac模块,它对我们创建key和内容再进行处理然后再加密

    1 import hmac
    2 h = hmac.new("hello".encode("utf-8"))
    3 h.update("jack".encode("utf-8"))  # 8570e3f986ef9099bfcd2e46181d0be7
    4 print(h.hexdigest())

    10.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
    默认的日志格式
    
    WARNING:root:warning message
    日志级别:logger名称:用户输出消息

    二.灵活配置日志级别,日志格式,输出位置

     1 import logging  
     2 logging.basicConfig(level=logging.DEBUG,  
     3                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',  
     4                     datefmt='%a, %d %b %Y %H:%M:%S',  
     5                     filename='/tmp/test.log',  
     6                     filemode='w')  
     7   
     8 logging.debug('debug message')  
     9 logging.info('info message')  
    10 logging.warning('warning message')  
    11 logging.error('error message')  
    12 logging.critical('critical message')

    查看输出

    Sat, 12 Nov 2016 05:58:47 logg.py[line:9] DEBUG debug message
    Sat, 12 Nov 2016 05:58:47 logg.py[line:10] INFO info message
    Sat, 12 Nov 2016 05:58:47 logg.py[line:11] WARNING warning message
    Sat, 12 Nov 2016 05:58:47 logg.py[line:12] ERROR error message
    Sat, 12 Nov 2016 05:58:47 logg.py[line:13] CRITICAL critical message

    在logging.bashicConfit()函数可通过具体参数来更改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对象

    上述几个例子中,我们了解到了logging.debug(),logging.info(),logging.warning(),logging.error(),

    logging.critical()分别用以记录不同级别的日志信息,logging.basicConfig()用默认日志格式(Formatter)为日志

    系统建立一个默认的流处理器(StreamHandler),设置基于配置(如日志级别等),并加到root logger(根logger中)这几个logging模块级别的函数,另外还有一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger)

    在这里我们先来看一个最简单的过程:

     1 import logging
     2 
     3 logger = logging.getLogger()
     4 # 创建一个handler,用于写入日志文件
     5 fh = logging.FileHandler('test.log')
     6 
     7 # 再创建一个handler,用于输出到控制台
     8 ch = logging.StreamHandler()
     9 
    10 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    11 
    12 fh.setFormatter(formatter)
    13 ch.setFormatter(formatter)
    14 
    15 logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
    16 logger.addHandler(ch)
    17 
    18 logger.debug('logger debug message')
    19 logger.info('logger info message')
    20 logger.warning('logger warning message')
    21 logger.error('logger error message')
    22 logger.critical('logger critical message')

    先简单介绍一下,logging库提供了多个组件:

    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()分别输出不同级别的日志,只有日志等级大于或等于设置的日志级别的日志才会被输出

    1 logger.debug('logger debug message')  
    2 logger.info('logger info message')  
    3 logger.warning('logger warning message')  
    4 logger.error('logger error message')  
    5 logger.critical('logger critical message') 

    只输出了

    2016-12-15 16:32:57,329 - root - WARNING - logger warning message
    2016-12-15 16:32:57,329 - root - ERROR - logger error message
    2016-12-15 16:32:57,330 - root - CRITICAL - logger critical message

    从这个输出可以看出logger = logging.getLogger()返回的Logger名为root。这里没有用logger.setLevel(logging.Debug)显示的为logger设置日志级别,所以使用默认的日志级别WARNIING,故结果只输出了大于等于WARNIING级别的信息。

    2.如果我们在创建两个logger对象

     1 logger1 = logging.getLogger('mylogger')
     2 logger1.setLevel(logging.DEBUG)
     3 
     4 logger2 = logging.getLogger('mylogger')
     5 logger2.setLevel(logging.INFO)
     6 
     7 logger1.addHandler(fh)
     8 logger1.addHandler(ch)
     9 
    10 logger2.addHandler(fh)
    11 logger2.addHandler(ch)
    12 
    13 logger1.debug('logger1 debug message')
    14 logger1.info('logger1 info message')
    15 logger1.warning('logger1 warning message')
    16 logger1.error('logger1 error message')
    17 logger1.critical('logger1 critical message')
    18   
    19 logger2.debug('logger2 debug message')
    20 logger2.info('logger2 info message')
    21 logger2.warning('logger2 warning message')
    22 logger2.error('logger2 error message')
    23 logger2.critical('logger2 critical message')

    输出结果

    2016-12-15 17:22:34,837 - mylogger - INFO - logger1 info message
    2016-12-15 17:22:34,837 - mylogger - INFO - logger1 info message
    2016-12-15 17:22:34,837 - mylogger - WARNING - logger1 warning message
    2016-12-15 17:22:34,837 - mylogger - WARNING - logger1 warning message
    2016-12-15 17:22:34,837 - mylogger - ERROR - logger1 error message
    2016-12-15 17:22:34,837 - mylogger - ERROR - logger1 error message
    2016-12-15 17:22:34,837 - mylogger - CRITICAL - logger1 critical message
    2016-12-15 17:22:34,837 - mylogger - CRITICAL - logger1 critical message
    2016-12-15 17:22:34,838 - mylogger - INFO - logger2 info message
    2016-12-15 17:22:34,838 - mylogger - INFO - logger2 info message
    2016-12-15 17:22:34,838 - mylogger - WARNING - logger2 warning message
    2016-12-15 17:22:34,838 - mylogger - WARNING - logger2 warning message
    2016-12-15 17:22:34,838 - mylogger - ERROR - logger2 error message
    2016-12-15 17:22:34,838 - mylogger - ERROR - logger2 error message
    2016-12-15 17:22:34,838 - mylogger - CRITICAL - logger2 critical message
    2016-12-15 17:22:34,838 - mylogger - CRITICAL - logger2 critical message

    这里有两个个问题:

          <1>我们明明通过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的输出遵从了后来设置的日志级别。

          <2>为什么logger1、logger2对应的每个输出分别显示两次?
           这是因为我们通过logger = logging.getLogger()显示的创建了root Logger,而logger1 = logging.getLogger('mylogger')创建了root Logger的孩子(root.)mylogger,logger2同样。而孩子,孙子,重孙……既会将消息分发给他的handler进行处理也会传递给所有的祖先Logger处理。

            ok,那么现在我们把

    # logger.addHandler(fh)

    # logger.addHandler(ch)  注释掉,我们再来看效果:

    2016-12-15 17:24:09,250 - mylogger - INFO - logger1 info message
    2016-12-15 17:24:09,251 - mylogger - WARNING - logger1 warning message
    2016-12-15 17:24:09,251 - mylogger - ERROR - logger1 error message
    2016-12-15 17:24:09,251 - mylogger - CRITICAL - logger1 critical message
    2016-12-15 17:24:09,251 - mylogger - INFO - logger2 info message
    2016-12-15 17:24:09,251 - mylogger - WARNING - logger2 warning message
    2016-12-15 17:24:09,251 - mylogger - ERROR - logger2 error message
    2016-12-15 17:24:09,251 - mylogger - CRITICAL - logger2 critical message

    因为我们注释了logger对象显示的位置,所以才用了默认方式,即标准输出方式。因为它的父级没有设置文件显示方式,所以在这里只打印了一次。

    孩子,孙子,重孙……可逐层继承来自祖先的日志级别、Handler、Filter设置,也可以通过Logger.setLevel(lel)、Logger.addHandler(hdlr)、Logger.removeHandler(hdlr)、Logger.addFilter(filt)、Logger.removeFilter(filt)。设置自己特别的日志级别、Handler、Filter。若不设置则使用继承来的值。

    <3>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对象都会进行筛选。

    完整代码1:

     1 import logging
     2 
     3 logger = logging.getLogger()
     4 # 创建一个handler,用于写入日志文件
     5 fh = logging.FileHandler('test.log')
     6 
     7 # 再创建一个handler,用于输出到控制台
     8 ch = logging.StreamHandler()
     9 
    10 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    11 
    12 fh.setFormatter(formatter)
    13 ch.setFormatter(formatter)
    14 
    15 # 定义一个filter
    16 filter = logging.Filter('mylogger')
    17 fh.addFilter(filter)
    18 ch.addFilter(filter)
    19 
    20 # logger.addFilter(filter)
    21 logger.addHandler(fh)
    22 logger.addHandler(ch)
    23 
    24 
    25 
    26 
    27 logger.setLevel(logging.DEBUG)
    28 
    29 logger.debug('logger debug message')
    30 logger.info('logger info message')
    31 logger.warning('logger warning message')
    32 logger.error('logger error message')
    33 logger.critical('logger critical message')
    34 
    35 ##################################################
    36 logger1 = logging.getLogger('mylogger')
    37 logger1.setLevel(logging.DEBUG)
    38 
    39 logger2 = logging.getLogger('mylogger')
    40 logger2.setLevel(logging.INFO)
    41 
    42 logger1.addHandler(fh)
    43 logger1.addHandler(ch)
    44 
    45 logger2.addHandler(fh)
    46 logger2.addHandler(ch)
    47 
    48 logger1.debug('logger1 debug message')
    49 logger1.info('logger1 info message')
    50 logger1.warning('logger1 warning message')
    51 logger1.error('logger1 error message')
    52 logger1.critical('logger1 critical message')
    53 
    54 logger2.debug('logger2 debug message')
    55 logger2.info('logger2 info message')
    56 logger2.warning('logger2 warning message')
    57 logger2.error('logger2 error message')
    58 logger2.critical('logger2 critical message')

    完整代码2

    #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')  

    应用示例

    import os
    import time
    import logging
    from config import settings
    
    
    def get_logger(card_num, struct_time):
    
        if struct_time.tm_mday < 23:
            file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon, 22)
        else:
            file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon+1, 22)
    
        file_handler = logging.FileHandler(
            os.path.join(settings.USER_DIR_FOLDER, card_num, 'record', file_name),
            encoding='utf-8'
        )
        fmt = logging.Formatter(fmt="%(asctime)s :  %(message)s")
        file_handler.setFormatter(fmt)
    
        logger1 = logging.Logger('user_logger', level=logging.INFO)
        logger1.addHandler(file_handler)
        return logger1

    11.re

    re模块用于对Python的正则表达式的操作

    1.普通字符:大多数字字符额字母都会和自身匹配

    re.findall('laiying','jacklaiyinghduekdf')

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

    #########

    字符:

    . 匹配除换行符以外的任意字符
    w 匹配字母或数字或下划线或汉字
    s 匹配任意的空白符
    d 匹配数字
     匹配单词的开始或结束
    ^ 匹配字符串的开始
    $ 匹配字符串的结束

    次数:

    * 重复零次或更多次
    + 重复一次或更多次
    ? 重复零次或一次
    {n} 重复n次
    {n,} 重复n次或更多次
    {n,m} 重复n到m次

     1 import re
     2 # result = re.findall('j..k','helljldklivi')
     3 # print(result)  # ['jldk'] . 匹配除换行符以外的任意字符
     4 
     5 # result = re.findall('^a...n','adhinhellakn')
     6 # print(result)  # ['adhin']  ^    匹配字符串的开始
     7 
     8 # result = re.findall('a.n$','adhinhellakn')
     9 # print(result)  # ['akn']  $    匹配字符串的结束
    10 
    11 # result = re.findall('abc*','abcabcabcccccc')
    12 # print(result)  # ['abc', 'abc', 'abcccccc']  * 重复零次或更多次,贪婪模式
    13 
    14 # result = re.findall('abc+','abcabccccc')  # ['abc', 'abccccc'] +    重复一次或更多次
    15 # print(result)
    16 
    17 # result = re.findall('abc?','abcabccccc') # ['abc', 'abc']  ?    重复零次或一次
    18 # print(result)
    19 
    20 # result = re.findall('abc{2}','abcadcabccc')  # ['abcc']
    21 # print(result)
    22 #{n}    重复n次
    23 #{n,}    重复n次或更多次
    24 #{n,m}    重复n到m次

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

    1 result = re.findall('abc*?','abcabcabccccc')
    2 print(result)  # ['ab', 'ab', 'ab']

    元字符之字符集[]

     1 #-----------字符集[],匹配[]字符集中的任意字符
     2 result = re.findall('a[bc]d','abdcabcadbacdccddd')
     3 print(result)  # ['abd', 'acd']
     4 
     5 result = re.findall('[a-z]','ahdnz')
     6 print(result)  # ['a', 'h', 'd', 'n', 'z']
     7 
     8 result = re.findall('[.*+]','a.bcd+d*d')
     9 print(result)  # ['.', '+', '*']
    10 
    11 #在字符集里有功能的符号: - ^ 
    12 result = re.findall('[1-9]','65dhadj3')
    13 print(result)  # ['6', '5', '3']
    14 
    15 result = re.findall('[^abc]','aidhabcy2')
    16 print(result)  # ['i', 'd', 'h', 'y', '2']  ^或
    17 
    18 result = re.findall('[d]','14adb8')
    19 print(result)  # ['1', '4', '8']  d只查找数字

    元字符之转义符

    d匹配任何十进制数,它相当于类[0-9]

    D匹配任何非数字字符,它相当于类[^0-9]

    s匹配任何空白字符,它相当于类[ fv]

    S匹配任何非空白字符,它相当于类[^ fv]

    w匹配任何字母数字字符,它相当于类[a-zA-Z0-9]

    W匹配任何非字母数字字符,它相当于类[^a-zA-Z0-9]

    匹配一个特殊字符边界,比如空格,&,#等

     我们现在来看看

     1 # -------------------eg1
     2 result = re.findall('I','I am LIST')
     3 print(result)  # []
     4 result = re.findall(r'I','I am LIST')
     5 print(result)  # ['I']
     6 
     7 result = re.findall('c1','abcle')
     8 print(result)  # []
     9 
    10 result = re.findall('c\l','abcle')
    11 print(result)  # []
    12 
    13 result = re.findall('c\\l','abcle')
    14 print(result)  # ['c\l']
    15 
    16 result = re.findall(r'c\l','abcle')
    17 print(result)  # ['c\l']
    18 
    19 # ------------------eg2
    20 #之所以选择是因为在ASCII表中是有意义的
    21 m = re.findall('blow','blow')
    22 print(m)  # []
    23 
    24 m = re.findall(r'blow','blow')
    25 print(m)  # ['blow']

    元字符之分组()

    1 result = re.search('(?P<id>d{2})/(?P<name>w{3})','23/com')
    2 print(result.group())   # 23/com
    3 print(result.group('id'))  # 23
    4 print(result.group('name')) # com

    元字符之| 或

    1 result = re.search('(ab)|d','dyabhy34dabyab')
    2 print(result.group())  # ab

    re模块下的常用方法

     1 #re.findall() 返回所有满足匹配条件的结果,放到列表中
     2 # result = re.findall('a','laiavie')
     3 # print(result)  # ['a', 'a']
     4 
     5 
     6 #函数会在字符串内查找模式匹配,直到找到第一个匹配的字符,就不在往下找了
     7 #通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None
     8 # result = re.search('a','laiavie')
     9 # print(result.group())  # a
    10 
    11 
    12 #同search,不过只在字符串开始处进行匹配,如果没有匹配的字符串就报错
    13 # result = re.match('a','abc')
    14 # print(result.group())  # a
    15 
    16 # result = re.split('[ab]','abcd')
    17 # print(result)  # ['', '', 'cd']
    18 #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
    19 
    20 
    21 #sub替代字符串的内容,subn也是匹配,他会告诉你匹配了几次
    22 # result = re.sub('d','abc','alvin5yuan6',1)
    23 # print(result)  # alvinabcyuan6
    24 
    25 # result = re.subn('d','abc','alvin5yuan6')
    26 # print(result) # ('alvinabcyuanabc', 2)
    27 
    28 #编译compile
    29 # obj = re.compile('d{2}')
    30 # ret = obj.search('abc123eeee')
    31 # print(ret.group())  # 12
    32 
    33 # result = re.finditer('d','ys34ys3ad35')
    34 # print(result)  # <callable_iterator object at 0x0000000001194B38>
    35 # print(next(result).group())  # 3

    注意:

    1 result = re.findall('www.(baidu|oldboy).com','www.oldboy.com')
    2 print(result)
    3 # ['oldboy']因为findall会优先把匹配结果组里的内容返回,如果想要匹配结果,取消权限即可
    4 
    5 result = re.findall('www.(?:baidu|oldboy).com','www.oldboy.com')
    6 print(result)  # ['www.oldboy.com']
  • 相关阅读:
    MySQL运维案例分析:Binlog中的时间戳
    身边有位“别人家的程序员”是什么样的体验?
    苹果收取30%过路费_你是顶是踩?
    1019 数字黑洞 (20 分)C语言
    1015 德才论 (25 分)C语言
    1017 A除以B (20 分)C语言
    1014 福尔摩斯的约会 (20 分)
    求n以内最大的k个素数以及它们的和、数组元素循环右移问题、求最大值及其下标、将数组中的数逆序存放、矩阵运算
    1005 继续(3n+1)猜想 (25 分)
    爬动的蠕虫、二进制的前导的零、求组合数、Have Fun with Numbers、近似求PI
  • 原文地址:https://www.cnblogs.com/YingLai/p/6166319.html
Copyright © 2011-2022 走看看