• Python 基础之-常用模块


    一 time & datetime

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

    • 时间戳(timestamp):  通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行"type(time.time())",返回的是float类型。
    • 格式化的时间字符串(Format String)
    • 结构化的时间(struct_time):  struct_time元祖共有9个元素(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)
    >>> import time
    
    #-------------------------以下分别是三种形式的时间-----------------------#
    >>> print(time.time())    #时间戳
    1509802396.6130548
    >>> print(time.strftime('%Y-%m-%d %X'))    #格式化的时间字符串,默认按当前时间(time.localtime())进行格式化
    2017-11-04 21:34:03
    >>> print (time.strftime('%a %b %d %H:%M:%S %Y'))    #格式化的时间字符串,同上一个
    Sat Nov 04 21:35:40 2017
    >>> print(time.localtime())    #本地时区的struct_time
    time.struct_time(tm_year=2017, tm_mon=11, tm_mday=4, tm_hour=21, tm_min=34, tm_sec=40, tm_wday=5, tm_yday=308, tm_isdst=0)
    >>> print(time.gmtime())    #UTC时区的struct_time
    time.struct_time(tm_year=2017, tm_mon=11, tm_mday=4, tm_hour=13, tm_min=34, tm_sec=57, tm_wday=5, tm_yday=308, tm_isdst=0)
    %y 去掉世纪的年份表示(00 - 99%Y 完整的年份表示(0000 - 9999%m 月份(01 - 12%d 一个月中的第几天(01 - 31%H 24小时制小时数(00 - 23%I 12小时制小时数(01 - 12%M 分钟数(00 - 59%S 秒(00 - 59%a 本地(locale)简化星期名称
    %A 本地完整星期名称
    %b 本地简化的月份名称
    %B 本地完整的月份名称
    %c 本地相应的日期表示和时间表示
    %j 一年中的第几天(001 - 366%p 本地A.M.或P.M.的等价符
    %U 一年中的星期数(00 - 53)星期天为星期的开始
    %w 一个星期中的第几天(0 - 6),星期天为星期的开始
    %W 和%U基本相同,不同的是%W是以星期一为一个星期的开始
    %x 本地相应的日期表示
    %X 本地相应的时间表示
    %Z 当前时区的名称(如果不存在为空字符)
    %% %号本身
    格式化字符串的时间格式

    其中计算机认识的时间只能是'时间戳'格式,而程序员可处理的或者说人类能看懂的时间有: '格式化的时间字符串','结构化的时间' ,于是有了下图的转换关系

              

    >>> import time
    
    #-------------------------------------按图1转换时间------------------------------------------#
    # localtime([secs]):将一个时间戳转换为当前时区(UTC+8)的struct_time。secs参数未提供,则以当前时间为准。
    >>> time.localtime()
    time.struct_time(tm_year=2017, tm_mon=11, tm_mday=4, tm_hour=21, tm_min=57, tm_sec=41, tm_wday=5, tm_yday=308, tm_isdst=0)
    >>> x = time.localtime(1509802396.6130548)
    >>> print(x)
    time.struct_time(tm_year=2017, tm_mon=11, tm_mday=4, tm_hour=21, tm_min=33, tm_sec=16, tm_wday=5, tm_yday=308, tm_isdst=0)
    >>> print(x.tm_year)
    2017
    >>> print(x.tm_yday)
    308
    
    # gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。
    
    # mktime(t) : 将一个struct_time转化为时间戳。
    >>> print(time.mktime(time.localtime()))
    1509803970.0
    
    
    # strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和time.gmtime()返回)转化为格式化的时间字符串。
      如果t未指定,将传入time.localtime()。如果元组中任何一个元素越界,ValueError的错误将会被抛出。
    >>> print(time.strftime("%Y-%m-%d %X", time.localtime()))
    2017-11-04 22:00:32
    >>> print(time.strftime("%X %Y-%m-%d", time.localtime()))
    22:00:32 2017-11-04
    
    # time.strptime(string[, format]):把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
    >>> print(time.strptime('2017-11-04 22:00:32', '%Y-%m-%d %X'))
    time.struct_time(tm_year=2017, tm_mon=11, tm_mday=4, tm_hour=22, tm_min=0, tm_sec=32, tm_wday=5, tm_yday=308, tm_isdst=-1)
    #在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。
    >>> import time
    
    #将格式字符串转换为时间戳
    >>> string_to_struct = time.strptime("2017-10-30 14:48:44","%Y-%m-%d %H:%M:%S")     #将 日期字符串 转成 struct时间对象格式
    >>> print(string_to_struct)
    time.struct_time(tm_year=2017, tm_mon=10, tm_mday=30, tm_hour=14, tm_min=48, tm_sec=44, tm_wday=0, tm_yday=303, tm_isdst=-1)
    >>> struct_to_stamp = time.mktime(string_to_struct)     #将struct时间对象格式转成时间戳
    >>> print(struct_to_stamp)
    1509346124.0
    
    或者一步到位
    >>> print(time.mktime(time.strptime("2017-10-30 14:48:44","%Y-%m-%d %H:%M:%S")) )
    1509346124.0
    
    
    #将时间戳转换为格式字符串
    >>> print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(1509346124.0)) )
    2017-10-30 14:48:44
    格式字符串和时间戳互转

                

    >>> import time
    
    #-----------------------------------------按图2转换时间-------------------------------------------#
    # asctime([t]) : 把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993'。如果没有参数,将会将time.localtime()作为参数传入。
    >>> print(time.asctime())
    Sat Nov  4 22:19:37 2017
    
    # ctime([secs]) : 把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为None的时候,将会默认time.time()为参数。
    它的作用相当于time.asctime(time.localtime(secs))。
    >>> print(time.ctime()) Sat Nov 4 22:19:56 2017 >>> print(time.ctime(time.time())) Sat Nov 4 22:20:35 2017 #---------------------------------------其它用法---------------------------# # sleep(secs):线程推迟指定的时间运行,单位为秒。
    #时间加减
    >>> import datetime
    
    >>> print(datetime.datetime.now())    #返回当前时间
    2017-11-04 22:28:16.976757
    >>> print(datetime.date.fromtimestamp(time.time()) )    # 时间戳直接转成日期格式
    2017-11-04
    
    >>> print(datetime.datetime.now() )
    2017-11-04 22:29:12.067908
    >>> print(datetime.datetime.now() + datetime.timedelta(3))    #当前时间+3天
    2017-11-07 22:29:24.544621
    >>> print(datetime.datetime.now() + datetime.timedelta(-3))   #当前时间-3天 
    2017-11-01 22:29:38.412414
    >>> print(datetime.datetime.now() + datetime.timedelta(hours=3))    #当前时间+3小时
    2017-11-05 01:29:50.667115
    >>> print(datetime.datetime.now() + datetime.timedelta(minutes=30))    #当前时间+30分
    2017-11-04 23:00:03.260836
    
    
    >>> c_time  = datetime.datetime.now()
    >>> print(c_time.replace(minute=3,hour=2))    #时间替换
    2017-11-04 02:03:37.749808
    datetime模块

    二 random

    随机数

    >>> import random
    
    >>> print(random.random())    #(0,1)----float    大于0且小于1之间的小数。也可以指定区间,看下一个
    0.4389206383156363
    >>> print(random.uniform(1,3))    #大于1小于3的小数
    1.8623602068930234
    >>> print(random.randint(1,3))    #[1,3]    大于等于1且小于等于3之间的整数
    1
    >>> print(random.randrange(1,3))    #[1,3)    大于等于1且小于3之间的整数
    2
    >>> print(random.choice([1,'23',[4,5]]))    #1或者23或者[4,5]
    23
    >>> print(random.sample([1,'23',[4,5]],2))    #列表元素任意2个组合
    ['23', 1]
    
    
    >>> item=[1,3,5,7,9]
    >>> random.shuffle(item)    #打乱item的顺序,相当于"洗牌"
    >>> print(item)
    [7, 3, 1, 5, 9]
    >>> 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(9))
    5Z126T88M
    生成随机验证码

    三 OS模块

    OS模块是于操作系统交互的一个接口

    import 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下为"
    ",Linux下为"
    "
    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的大小
    常用方法

    更多猛击这里

    >>> import os
    
    # 在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
    >>> os.path.normcase('c:/windows\system32\')
    'c:\windows\system32\'
    
    
    # 规范化路径,如..和/
    >>> os.path.normpath('c://windows\System32\../Temp/')
    'c:\windows\Temp'
    
    >>> a='/Users/jieli/test1/\a1/\\aa.py/../..'
    >>> print(os.path.normpath(a))
    Usersjieli	est1
    os路径处理
    
    #方式一:推荐使用
    import os,sys
    >>> possible_topdir = os.path.normpath(os.path.join(
        os.path.abspath(os.__file__),
        os.pardir,
        os.pardir,
        os.pardir
    ))
    >>> sys.path.insert(0,possible_topdir)
    
    
    #方式二:不推荐使用
    import os
    >>> os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(os.__file__))))
    'C:\Users\Administrator\AppData\Local\Programs\Python'

      

    四 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]
    #=========知识储备==========
    #进度条的效果
    [#             ]
    [##            ]
    [###           ]
    [####          ]
    
    #指定宽度
    print('[%-15s]' %'#')
    print('[%-15s]' %'##')
    print('[%-15s]' %'###')
    print('[%-15s]' %'####')
    
    #打印%
    print('%s%%' %(100)) #第二个%号代表取消第一个%的特殊意义
    
    #可传参来控制宽度
    print('[%%-%ds]' %50) #[%-50s]
    print(('[%%-%ds]' %50) %'#')
    print(('[%%-%ds]' %50) %'##')
    print(('[%%-%ds]' %50) %'###')
    
    
    #=========实现打印进度条函数==========
    import sys
    import time
    
    def progress(percent,width=50):
        if percent >= 1:
            percent=1
        show_str=('[%%-%ds]' %width) %(int(width*percent)*'#')
        print('
    %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
    打印进度条

    五 shutil模块

    高级的文件、文件夹、压缩包处理模块。包括复制、移动、重命名、删除等等。

    shutil.copyfileobj(fsrc, fdst[, length])

    将文件内容拷贝到另一个文件中

    >>> import shutil
    
    >>> shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))

    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)
    拷贝文件和权限

    >>> import shutil
    
    >>> shutil.copy('f1.log', 'f2.log')

    shutil.copy2(src, dst)
    拷贝文件和状态信息

    >>> import shutil
    
    >>> shutil.copy2('f1.log', 'f2.log')

    shutil.ignore_patterns(*patterns)
    shutil.copytree(src, dst, symlinks=False, ignore=None)
    递归的去拷贝文件夹

    >>> import shutil
    
    >>> shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))    #目标目录不能存在,
    注意对folder2目录父级目录要有可写权限,ignore的意思是排除
    >>> import shutil
    
    >>> shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
    '''
    通常的拷贝都把软连接拷贝成硬链接,即对待软连接来说,创建新的文件
    '''
    拷贝软连接

    shutil.rmtree(path[, ignore_errors[, onerror]])
    递归的去删除文件

    >>> import shutil
    
    >>> shutil.rmtree('folder1')

    shutil.move(src, dst)
    递归的去移动文件,它类似mv命令,其实就是重命名。

    >>> import shutil
    
    >>> shutil.move('folder1', 'folder3')

    shutil.make_archive(base_name,format,...)

    创建压缩包并返回文件路径,例如:zip、tar

    • base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,

         如:data_bak                        =>保存至当前路径
         如:/tmp/data_bak           =>保存至/tmp/test/

    • format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
    • root_dir: 要压缩的文件夹路径(默认当前目录)
    • owner: 用户,默认当前用户
    • group: 组,默认当前组
    • logger: 用于记录日志,通常是logging.Logger对象
    #将 /data 下的文件打包放置当前程序目录
    >>> import shutil
    >>> shutil.make_archive('data_bak','tar',root_dir='/data')
    '/root/data_bak.tar'
    
    
    #将 /data下的文件打包放置 /tmp/ 目录
    >>> shutil.make_archive('/tmp/data_bak','tar',root_dir='/data')
    '/tmp/data_bak.tar'
    

    shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:

    import zipfile
    
    # 压缩
    z = zipfile.ZipFile('laxi.zip', 'w')
    z.write('a.log')
    z.write('data.data')
    z.close()
    
    # 解压
    z = zipfile.ZipFile('laxi.zip', 'r')
    z.extractall(path='.')
    z.close()
    zipfile压缩解压缩
    import tarfile
    
    # 压缩
    >>> t=tarfile.open('/tmp/egon.tar','w')
    >>> t.add('/test1/a.py',arcname='a.bak')
    >>> t.add('/test1/b.py',arcname='b.bak')
    >>> t.close()
    
    
    # 解压
    >>> t=tarfile.open('/tmp/egon.tar','r')
    >>> t.extractall('/egon')
    >>> t.close()
    tarfile压缩解压缩

    六 json & pickle模块

    用于序列化的两个模块

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

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

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

    >>> import pickle
      
    >>> data = {'k1':123,'k2':'Hello'}
      
    # pickle.dumps 将数据通过特殊的形式装换为只有python语言认识的字符串
    >>> p_str = pickle.dumps(data)
    >>> print(p_str)
    b'x80x03}qx00(Xx02x00x00x00k1qx01K{Xx02x00x00x00k2qx02Xx05x00x00x00Helloqx03u.'
      
    # pickle.dump 将数据通过特殊的形式装换为只有python语言认识的字符串,并写入文件
    >>> with open(r'D:
    esult.pk','wb') as fp:
        pickle.dump(data,fp)
      
          
    #读取pickle文件
    >>> with open(r'D:
    esult.pk','rb') as fp:
        pickle.load(fp)
      
          
    {'k2': 'Hello', 'k1': 123}
      
      
    >>> import json
    # json.dumps 将数据通过特殊的形式转换为所有程序语言都认识的字符串
    >>> j_str = json.dumps(data)
    >>> print(j_str)
    {"k2": "Hello", "k1": 123}
      
    # json.dumps 将数据通过特殊的形式转换为所有程序语言都认识的字符串,并写入文件
    >>> with open(r'D:
    esult.json','w') as fp:
        json.dump(data,fp)
      
     
    #读取json文件 
    >>> with open(r'D:
    esult.json','r') as fp:
        json.load(fp)
      
          
    {'k2': 'Hello', 'k1': 123}

    七 shelve模块

    shelve模块是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式,并且可以多次 dump 和 load

    >>> import shelve
    >>> import datetime
     
    #持久化数据
    >>> info = {'name': 'bigberg', 'age': 22}
    >>> name = ['Apoll', 'Zous', 'Luna']
    >>> t = datetime.datetime.now()
    >>> with shelve.open('/tmp/shelve.txt') as f:     #执行代码后会生成3个文件:shelve.txt.bak、shelve.txt.dat、shelve.txt.dir。
    ...     f['name'] = name     #持久化列表
    ...     f['info'] = info     #持久化字典
    ...     f['time'] = t        #持久化时间类型
    ...
     
    #读取数据
    >>> with shelve.open('shelve.txt') as f:     #打开文件
    ...     print(f.get('name'))     #使用get获取数据
    ...     print(f.get('info'))
    ...     print(f.get('time'))
    ...
    ['Apoll', 'Zous', 'Luna']
    {'name': 'bigberg', 'age': 22}
    2017-11-01 16:07:29.261414

    八 xml模块

    xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是xml。

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

    <?xml version="1.0"?>
    <data>
        <country name="Liechtenstein">
            <rank updated="yes">2</rank>
            <year>2008</year>
            <gdppc>141100</gdppc>
            <neighbor name="Austria" direction="E"/>
            <neighbor name="Switzerland" direction="W"/>
        </country>
        <country name="Singapore">
            <rank updated="yes">5</rank>
            <year>2011</year>
            <gdppc>59900</gdppc>
            <neighbor name="Malaysia" direction="N"/>
        </country>
        <country name="Panama">
            <rank updated="yes">69</rank>
            <year>2011</year>
            <gdppc>13600</gdppc>
            <neighbor name="Costa Rica" direction="W"/>
            <neighbor name="Colombia" direction="E"/>
        </country>
    </data>
    xml数据

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

    print(root.iter('year'))    #全文搜索
    print(root.find('country'))    #在root的子节点找,只找一个
    print(root.findall('country'))    #在root的子节点找,找所有
    import xml.etree.ElementTree as ET
     
    tree = ET.parse("xmltest.xml")
    root = tree.getroot()
    print(root.tag)
     
    #遍历xml文档
    for child in root:
        print('========>',child.tag,child.attrib,child.attrib['name'])
        for i in child:
            print(i.tag,i.attrib,i.text)
     
    #只遍历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')
        node.set('version','1.0')
    tree.write('test.xml')
     
     
    #删除node
    for country in root.findall('country'):
       rank = int(country.find('rank').text)
       if rank > 50:
         root.remove(country)
     
    tree.write('output.xml')
    View Code
    #在country内添加(append)节点year2
    import xml.etree.ElementTree as ET
    tree = ET.parse("a.xml")
    root=tree.getroot()
    for country in root.findall('country'):
        for year in country.findall('year'):
            if int(year.text) > 2000:
                year2=ET.Element('year2')
                year2.text='新年'
                year2.attrib={'update':'yes'}
                country.append(year2) #往country节点下添加子节点
    
    tree.write('a.xml.swap')

    自己创建xml文档:

    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

    九 configparser模块

    用于生成和修改常见配置文档。

    一个典型的Mysql配置文件如下:

    [mysqld]
    port = 3306
    socket = /var/lib/mysql/mysql.sock
    key_buffer = 384M
    myisam_sort_buffer_size = 64M
    thread_cache_size = 8
    query_cache_size = 32M
    max_connections=500
    thread_concurrency = 8
    
    [client]
    user = root
    password = 123456
    port = 3306
    socket = /var/lib/mysql/mysql.sock

    读取

    >>> import configparser
    
    >>> config=configparser.ConfigParser()
    >>> config.read('my.cnf')
    ['my.cnf']
    
    #查看所有的标题
    >>> res=config.sections()
    >>> print(res)
    ['mysqld', 'client']
    
    #判断是否存在某个标题
    >>> 'mysqld' in config
    True
    
    >>> print(config.has_section('mysqld'))    #同上一个
    True
    
    #判断标题mysqld下是否有user
    >>> print(config.has_option('mysqld','user'))
    False
    
    #查看标题client下所有key=value的key
    >>> options=config.options('client')
    >>> print(options)
    ['user', 'password', 'port', 'socket']
    
    >>> for key in config['client']:print(key)    #同上一个
    ... 
    user
    password
    port
    socket
    
    #查看标题client下所有key=value的(key,value)格式
    >>> item_list=config.items('client')
    >>> print(item_list)
    [('user', 'root'), ('password', '123456'), ('port', '3306'), ('socket', '/var/lib/mysql/mysql.sock')]
    
    #查看标题client下user的值=>字符串格式
    >>> val=config.get('client','user')
    >>> print(val)
    root
    
    >>> config['client']['user']    #同上一个
    'root'
    
    #查看标题client下port的值=>整数格式
    >>> val1=config.getint('client','port')
    >>> print(val1)
    3306
    
    #查看标题mysqld下mysql_update的值=>布尔值格式
    val2=config.getboolean('mysqld','mysql_update')
    print(val2)
    
    #查看标题mysqld下max_connections的值=>浮点型格式
    val3=config.getfloat('mysqld','max_connections')
    print(val3)

    改写

    >>> import configparser
    
    >>> config=configparser.ConfigParser()
    >>> config.read('my.cnf',encoding='utf-8')
    ['my.cnf']
    
    #删除整个标题client
    >>> config.remove_section('client')
    True
    
    删除标题mysqld下的key_buffer和thread_cache_size
    >>> config.remove_option('mysqld','key_buffer')
    True
    >>> config.remove_option('mysqld','thread_cache_size')
    True
    
    #添加一个标题
    >>> config.add_section('mysql')
    
    #在标题mysqld下添加read_buffer_size=2M,thread_concurrency=8的配置
    >>> config.set('mysqld','read_buffer_size','2M')
    >>> config.set('mysqld','thread_concurrency','8')
    
    
    #最后将修改的内容写入文件,完成最终的修改
    >>> config.write(open('my.cnf','w'))
    >>> 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)
    ... 
    基于上述方法添加一个ini文档

    十 hashlib模块

    hash:一种算法 ,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法

    三个特点:

    1. 内容相同则hash运算结果相同,内容稍微改变则hash值则变
    2. 不可逆推
    3. 相同算法:无论校验多长的数据,得到的哈希值长度固定。
    >>> import hashlib
    
    >>> m = hashlib.md5()    # m = hashlib.sha256()
    
    >>> m.update('hello'.encode('utf-8'))
    >>> print(m.digest())    #2进制格式hash
    b']A@*xbcK*vxb9qx9dx91x10x17xc5x92'
    >>> print(m.hexdigest())    #16进制格式hash
    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多次为校验大文件提供了可能。
    '''

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

    >>> import hashlib
    
    ######## 256 #########
    
    >>> hash = hashlib.sha256('898oaFs09f'.encode('utf8'))
    >>> hash.update('alvin'.encode('utf8'))
    >>> print (hash.hexdigest())
    e79e68f070cdedcfe63eaf1a2e92c83b4cfb1b5c6bc452d214c1b7e77cdfd1c7
    import hashlib
    passwds=[
        'alex3714',
        'alex1313',
        'alex94139413',
        'alex123456',
        '123456alex',
        'a123lex',
        ]
    def make_passwd_dic(passwds):
        dic={}
        for passwd in passwds:
            m=hashlib.md5()
            m.update(passwd.encode('utf-8'))
            dic[passwd]=m.hexdigest()
        return dic
    
    def break_code(cryptograph,passwd_dic):
        for k,v in passwd_dic.items():
            if v == cryptograph:
                print('密码是===>33[46m%s33[0m' %k)
    
    cryptograph='aee949757a2e698417463d47acac93df'
    break_code(cryptograph,make_passwd_dic(passwds))
    模拟撞库破解密码

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

    >>> import hmac
    
    >>> h = hmac.new(b'898oaFs09f','alvin'.encode('utf8'))
    >>> h.update('hello'.encode('utf8'))
    >>> print (h.hexdigest())
    6b1bc37749ebe91b01e07685221d38ef
    #要想保证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())
    f1bf38d054691688f89dcd34ac3c27f2
    
    >>> h2=hmac.new(b'egon')
    >>> h2.update(b'helloworld')
    >>> print(h2.hexdigest())
    f1bf38d054691688f89dcd34ac3c27f2
    
    >>> h3=hmac.new(b'egonhelloworld')
    >>> print(h3.hexdigest())
    bcca84edd9eeb86f30539922b28f3981
    注意!注意!注意!

    十一 subprocess模块

    常用subprocess方法示例

    >>> import subprocess
    
    #执行命令,返回命令执行状态 , 0 or 非0
    >>> retcode = subprocess.call('ls -l',shell=True)    #shell = True ,允许 shell 命令是字符串形式
    total 20
    -rw-r--r-- 1 root root 20480 Nov  1 14:13 tmp_file.tar
    >>> print(retcode)
    0
    
    >>> retcode = subprocess.call('aaa',shell=True)     #如果输入一个错误的命令,Python解释器不会提示任何信息
    /bin/sh: aaa: command not found     #这里是系统执行命令返回的系统报错
    >>> print(retcode)
    127
    
    #执行命令,如果命令结果为0,就正常返回,否则抛异常
    >>> subprocess.check_call('ls -l',shell=True)
    total 20
    -rw-r--r-- 1 root root 20480 Nov  1 14:13 tmp_file.tar
    0
    
    >>> subprocess.check_call('aaa',shell=True)
    /bin/sh: aaa: command not found     #这里是系统执行命令返回的系统报错
    Traceback (most recent call last):     #这里是Python解释器返回的报错
      File "<stdin>", line 1, in <module>
      File "/usr/local/python3/lib/python3.6/subprocess.py", line 291, in check_call
        raise CalledProcessError(retcode, cmd)
    subprocess.CalledProcessError: Command 'aaa' returned non-zero exit status 127.
    
    #接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结果
    >>> subprocess.getstatusoutput('ls /bin/ls')
    (0, '/bin/ls')
    
    #接收字符串格式命令,并返回结果
    >>> subprocess.getoutput('ls /bin/ls')
    '/bin/ls'
    
    #执行命令,并返回结果,注意是返回结果,不是打印,下例结果返回给res
    >>> res=subprocess.check_output('ls -l',shell=True)
    >>> res
    b'total 20
    -rw-r--r-- 1 root root 20480 Nov  1 14:13 tmp_file.tar
    '
    
    
    ##上面那些方法,底层都是封装的subprocess.Popen
    poll()
    Check if child process has terminated. Returns returncode
    
    wait()
    Wait for child process to terminate. Returns returncode attribute.
    
    
    terminate() 杀掉所启动进程
    communicate() 等待任务结束
    
    stdin 标准输入
    
    stdout 标准输出
    
    stderr 标准错误
    
    pid
    The process ID of the child process.
    
    
    #例子
    >>> p = subprocess.Popen('df -h | grep sdb1',stdin=subprocess.PIPE,stdout=subprocess.PIPE,shell=True)
    >>> p.stdout.read()
    b'/dev/sdb1              4.8G   20M  4.6G   1% /usr/local/mysql/data
    '

    subprocess.run(...)

    >>> subprocess.run('ls -l',shell=True)
    total 20
    -rw-r--r-- 1 root root 20480 Nov  1 14:13 tmp_file.tar
    CompletedProcess(args='ls -l', returncode=0)
    
    >>> subprocess.run('exit 1', shell=True, check=True)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/local/python3/lib/python3.6/subprocess.py", line 418, in run
        output=stdout, stderr=stderr)
    subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1.
    
    >>> subprocess.run('ls -l /dev/null',shell=True,stdout=subprocess.PIPE)
    CompletedProcess(args='ls -l /dev/null', returncode=0, stdout=b'crw-rw-rw- 1 root root 1, 3 Nov  2 09:48 /dev/null
    ')

    调用subprocess.run(...)是推荐的常用方法,在大多数情况下能满足需求,但如果你可能需要进行一些复杂的与系统的交互的话,你还可以用subprocess.Popen(),语法如下:

    >>> p = subprocess.Popen('ping -c5 127.0.0.1',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    >>> print(p.stdout.read())
    

      

    可用参数:

    • args:shell命令,可以是字符串或者序列类型(如:list,元组)
    • bufsize:指定缓冲。0 无缓冲,1 行缓冲,其他 缓冲区大小,负值 系统缓冲
    • stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
    • preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
    • close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会继承父进程的输入、输出、错误管道。

       所以不能将close_fds设置为True同时重定向子进程的标准输入、输出与错误(stdin, stdout, stderr)。

    • shell:同上
    • cwd:用于设置子进程的当前目录
    • env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
    • universal_newlines:不同系统的换行符不同,True -> 同意使用
    • startupinfo与createionflags只在windows下有效

         将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等

    终端输入的命令分为两种:

    • 输入即可得到输出,如:ifconfig
    • 输入进行某环境,依赖再输入,如:python

    需要交互的命令示例

    十二 logging模块

           很多程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还可能有错误、警告等信息输出。Python的logging模块提供了标准的日志接口,可以通过它存储各种格式的日志,logging的日志可以分为5个级别:

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

    说明:

    • 上面列表中的日志等级是从上到下依次升高的,即:DEBUG < INFO < WARNING < ERROR < CRITICAL,而日志的信息量是依次减少的;
    • 当为某个应用程序指定一个日志级别后,应用程序会记录所有日志级别大于或等于指定日志级别的日志信息,而不是仅仅记录指定级别的日志信息,同样,logging模块也可以指定日志记录器的日志级别,只有级别大于或等于该指定日志级别的日志记录才会被输出,小于该等级的日志记录将会被丢弃。

     最简单的日志输出,默认打印到终端

    >>> import logging
    >>> logging.debug('This is a debug log.')
    >>> logging.info('This is a info log.')
    >>> logging.warning('This is a warning log.')
    WARNING:root:This is a warning log.
    >>> logging.error('This is a error log.')
    ERROR:root:This is a error log.
    >>> logging.critical('This is a critical log.')
    CRITICAL:root:This is a critical log.
    
    '''
    为什么前面两条日志没有被打印出来???
    
    这是因为logging模块提供的日志记录函数所使用的日志器设置的日志级别是WARNING,因此只有WARNING级别的日志记录以及大于它的ERROR和CRITICAL级别的
    日志记录被输出了,而小于它的DEBUG和INFO级别的日志记录被丢弃了。
    '''

    把日志写到文件里

    >>> import logging
    >>> logging.basicConfig(filename=r'd:access.log',
                    format="%(asctime)s [%(filename)s:%(lineno)d] %(levelname)s %(message)s",
                    datefmt='%Y-%m-%d %H:%M:%S %p',
                    level=logging.INFO)
    >>> logging.debug('调试debug')
    >>> logging.info('消息info')
    >>> logging.warning('警告warn')
    >>> logging.error('错误error')
    >>> logging.critical('严重critical')
    
    
    #access.log内容:
    2017-11-15 14:15:09 [<pyshell#7>:2] INFO 消息info
    2017-11-15 14:15:32 [<pyshell#8>:2] WARNING 警告warn
    2017-11-15 14:16:15 [<pyshell#9>:2] ERROR 错误error
    2017-11-15 14:16:55 [<pyshell#10>:2] CRITICAL 严重critical

    可在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:

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

    format参数中可能用到的格式化串

    %(asctime)s          日志事件发生的时间--人类可读时间,默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
    %(created)f          日志事件发生的时间--时间戳,就是当时调用time.time()函数返回的值
    %(relativeCreated)d  日志事件发生的时间相对于logging模块加载时间的相对毫秒数(一般不用)
    %(msecs)d            日志事件发生事件的毫秒部分
    %(levelname)s        该日志记录的文字形式的日志级别('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'%(levelno)s          该日志记录的数字形式的日志级别(10, 20, 30, 40, 50%(name)s             所使用的日志器名称,默认是'root',因为默认使用的是 rootLogger
    %(message)s          用户输出的消息
    %(pathname)s         调用日志输出函数的模块的完整路径名,可能没有
    %(filename)s         调用日志输出函数的模块的文件名,包含文件后缀
    %(module)s           调用日志输出函数的模块名,不包含后缀
    %(lineno)d           调用日志输出函数的语句所在的代码行
    %(funcName)s         调用日志输出函数的函数名
    %(process)d          进程ID。可能没有
    %(processName)s      进程名称,Python 3.1新增
    %(thread)d           线程ID。可能没有
    %(threadName)s       线程名。可能没有
    View Code

    如果想同时把LOG打印到屏幕和文件日志里,可以使用logging模块提供的四个主要类来实现:

    1. logger  提供了应用程序可以直接使用的接口;
    2. handler   将(logger创建的)日志记录发送到合适的目的输出;
    3. filter     提供了细度设备来决定输出哪条日志记录;
    4. formatter   决定日志记录的最终输出格式。
    Logger类
    每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块可以这样获得它的Logger:
    LOG=logging.getLogger(”chat.gui”)
    而核心模块可以这样:
    LOG=logging.getLogger(”chat.kernel”)
    
    Logger.setLevel(lel):指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高
    Logger.addFilter(filt)、Logger.removeFilter(filt):添加或删除指定的filter
    Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或删除指定的handler
    Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以设置的日志级别
    
    
    Handler类
    handler对象负责发送相关的信息到指定目的地。Python的日志系统有多种Handler可以使用。有些Handler可以把信息输出到控制台,有些Logger可以把信息输出到文件,还有些 Handler可以把信息发送到网络上。如果觉得不够用,还可以编写自己的Handler。可以通过addHandler()方法添加多个多handler
    Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略
    Handler.setFormatter():给这个handler选择一个格式
    Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象
    
    每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:
    1) logging.StreamHandler
    使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:
    StreamHandler([strm])
    其中strm参数是一个文件对象。默认是sys.stderr
    
    2) logging.FileHandler
    和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:
    FileHandler(filename[,mode])
    filename是文件名,必须指定一个文件名。
    mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。
    
    3) logging.handlers.RotatingFileHandler
    这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的构造函数是:
    RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
    其中filename和mode两个参数和FileHandler一样。
    maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
    backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。
    
    4) logging.handlers.TimedRotatingFileHandler
    这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
    TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
    其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
    interval是时间间隔。
    when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
    S 秒
    M 分
    H 小时
    D 天
    W 每星期(interval==0时代表星期一)
    midnight 每天凌晨
    
    5) logging.handlers.HTTPHandler
    将日志消息以GET或POST的方式发送给一个HTTP服务器
    
    6) logging.handlers.SMTPHandler
    将日志消息发送给一个指定的email地址
    
    7) logging.NullHandler
    该Handler实例会忽略error messages,通常被想使用logging的library开发者使用来避免'No handlers could be found for logger XXX'信息的出现。
    
    
    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表示可以通过过滤。
    
    
    Formater类
    Formater对象用于配置日志信息的最终顺序、结构和内容。与logging.Handler基类不同的是,应用代码可以直接实例化Formatter类。另外,如果你的应用程序需要一些特殊的处理行为,也可以实现一个Formatter的子类来完成。
    
    Formatter类的构造方法定义如下:
    logging.Formatter.__init__(fmt=None, datefmt=None, style='%')
    详细的各类使用方法

    logging模块就是通过这些组件来完成日志处理的,上面所使用的logging模块级别的函数也是通过这些组件对应的类来实现的

     这些组件之间的关系描述:

    • 日志器(logger)需要通过处理器(handler)将日志信息输出到目标位置,如:文件、sys.stdout、网络等;
    • 不同的处理器(handler)可以将日志输出到不同的位置;
    • 日志器(logger)可以设置多个处理器(handler)将同一条日志记录输出到不同的位置;
    • 每个处理器(handler)都可以设置自己的过滤器(filter)实现日志过滤,从而只保留感兴趣的日志;
    • 每个处理器(handler)都可以设置自己的格式器(formatter)实现同一条日志以不同的格式输出到不同的地方。

    简单点说就是:日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。

    >>> import logging
    >>> from logging.handlers import RotatingFileHandler
    
    # 创建一个日志器logger并设置其日志级别为WARNING
    >>> logger = logging.getLogger('LOG')
    >>> logger.setLevel(logging.WARNING)
    
    # 创建一个流处理器ch_handler并设置其日志级别为DEBUG,还创建一个格式器
    >>> ch_handler = logging.StreamHandler()
    >>> ch_handler.setLevel(logging.DEBUG)
    >>> ch_formatter = logging.Formatter("%(asctime)s [%(filename)s:%(lineno)d] %(levelname)s %(message)s",
                         datefmt='%Y-%m-%d %H:%M:%S %p')
    
    # 创建一个文件处理器fh_handler并设置其日志级别为INFO,还创建一个格式器
    >>> fh_handler = RotatingFileHandler(r'd:log_test.log',maxBytes=20*1024*1024,backupCount=10)
    >>> fh_handler.setLevel(logging.INFO)
    >>> fh_formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    
    # 将流格式器添加到处理器ch_handler
    >>> ch_handler.setFormatter(ch_formatter)
    # 将文件格式器添加到处理器fh_handler
    >>> fh_handler.setFormatter(fh_formatter)
    
    #添加ch_handler和fh_handler处理器到日志器logger
    >>> logger.addHandler(ch_handler)
    >>> logger.addHandler(fh_handler)
    
    #屏幕输出
    >>> logger.debug('debug message')
    >>> logger.info('info message')
    >>> logger.warn('warn message')
    2017-11-16 15:37:03 PM [<pyshell#26>:2] WARNING warn message
    >>> logger.error('error message')
    2017-11-16 15:37:20 PM [<pyshell#27>:2] ERROR error message
    >>> logger.critical('critical message')
    2017-11-16 15:37:27 PM [<pyshell#28>:2] CRITICAL critical message
    
    # log_test.log文件内容:
    2017-11-16 15:37:03,055 - LOG - WARNING - warn message
    2017-11-16 15:37:20,433 - LOG - ERROR - error message
    2017-11-16 15:37:27,371 - LOG - CRITICAL - critical message
    将日志同时输出到文件和屏幕

    十三 re模块

    常用匹配模式(元字符)

    'w'       匹配字母数字及下划线
    'W'       匹配非字母数字下划线
    's'       匹配任意空白字符,等价于 [	
    
    f]
    'S'       匹配任意非空字符
    'd'       匹配任意数字,等价于 [0-9]
    'D'       匹配任意非数字
    'A'       匹配字符串开始
    ''       匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串
    'z'       匹配字符串结束
    'G'       匹配最后匹配完成的位置
    '
    '       匹配一个换行符
    '	'       匹配一个制表符
    '^'        匹配字符串的开头
    '$'        匹配字符串的末尾
    '.'        默认匹配除换行符(
    )以外的任意字符,若指定flag DOTALL,则可以匹配包括换行符的任意字符
    '[...]'    用来表示一组字符,单独列出:[amk]匹配'a''m''k'
    '[^...]'   不在[]中的字符:[^abc]匹配除了a,b,c之外的字符。
    '*'        匹配前一个字符或表达式0次或多次
    '+'        匹配前一个字符或表达式1次或多次
    '?'        匹配前一个字符或表达式1次或0次,非贪婪方式
    '{n}'      精确匹配前一个字符或表达式n次
    '{n,m}'    匹配前一个字符或表达式n次到m次,贪婪模式
    'a|b'      匹配a或者b
    '()'       匹配括号内的表达式,也表示一个

    re.search()

     扫描整个字符串,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。

     语法格式:

    re.search(pattern,string,flags=0)

    >>> import re
     
    #常规匹配
    >>> result = re.search('he','hi! hello world,good')
    >>> print(result)
    <_sre.SRE_Match object at 0x020E6058>
    >>> print(result.group())    #获取匹配的结果
    he
    >>> print(result.span())    #获取匹配字符串的长度范围
    (4, 6)
     
     
    # ()匹配目标
    >>> import re
     
    >>> result = re.search('w+s(w*)','hi! hello world,good')    #为了匹配字符串中具体的目标,则需要通过()括起来
    >>> result.group()
    'hello world'
    >>> result.group(1)    #获取第一个括号中匹配的结果
    'world'
    >>> result.groups()    #返回的是一个元组形式
    ('world',)
     
     
    # .*贪婪匹配
    >>> import re
     
    >>> result = re.search('he.*(d+).*','hi! hello 123456 world')
    >>> result.group(1)
    '6'
     
    '''
    从结果中可以看出只匹配到了6,并没有匹配到123456,出现这种情况的原因是前面的.* 给匹配掉了, .*在这里会尽可能的匹配多的内容,也就是我们所说的贪婪匹配
    '''
    #如果想要匹配到123456,可以把正则表达式改为:
    >>> result = re.search('he.*?(d+).*','hi! hello 123456 world')
     
     
    # re.S匹配模式
    >>> content = """hi! hello 123456 world
    my name is tbb
    """
    >>> result = re.search('he.*?(d+).*?tbb$',content,re.S)    #用匹配模式re.S来匹配换行的内容
    >>> result.group()
    'hello 123456 world
    my name is tbb'
    >>> print(result.group())
    hello 123456 world
    my name is tbb
    >>> print(result.group(1))
    123456
     
     
    # 转义
    >>> import re
     
    >>> content = 'hello! price is $5.00'
    >>> result = re.search('price is $5.00',content)
    >>> print(result.group())
    price is $5.00
     
    #如果要匹配,可以使用如下方法:
    >>> re.search(r'a\c','ac').group()    #r代表告诉解释器使用rawstring,即原生字符串,把我们正则内的所有符号都当普通字符处理,不要转义
    'a\c'>>> re.search('a\\c','ac').group()
    'a\c'
     
    '''
    当我们要匹配的内容中存在特殊字符的时候,就需要用到转移符号
    '''

    re.match()

    尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配的话,match()就会返回None

    同search,不过在字符串开始处进行匹配,完全可以用search+^代替match,如下所示:

    >>> result = re.match('world','hello world')
    >>> print(result)
    None
    >>> result = re.search('world','hello world')
    >>> print(result)
    <_sre.SRE_Match object; span=(6, 11), match='world'>
    >>> result = re.search('^world','hello world')
    >>> print(result)
    None
    

      

    re.findall()

    搜索字符串,以列表的形式返回全部能匹配的子串

    >>> re.findall('a[+*(]b','a*b a+b a-b a=b')
    ['a*b', 'a+b']

    re.split()

    >>> re.split('[ab]','abcd')    #先按'a'分割得到''和'bcd',再对''和'bcd'分别按'b'分割
    ['', '', 'cd']

    re.sub()

    替换字符串中每一个匹配的子串后返回替换后的字符串

    re.sub(正则表达式,替换成的字符串,原字符串)

    >>> re.sub('l','L','hello world')    #不指定n,默认替换所有
    'heLLo worLd'
    >>> re.sub('l','L','hello world',1)
    'heLlo world'
    >>> re.sub('l','L','hello world',2)
    'heLLo world'
    >>> re.sub('(d+)',r'1 7890','hello 123456 world')    #获取匹配的字符串后面添加些内容,1是获取第一个匹配的结果。为了防止转义字符的问题,需要在前面加上r
    'hello 123456 7890 world'
    >>> re.sub('(w*)(s*)(d+)(s*)(w*)',r'54321','hello 123456 world')    #把匹配到的结果按照顺序对原有字符串进行组合,返回新的字符串
    'world 123456 hello'
    
    >>> re.subn('l','L','hello world')    #结果带有总共替换的个数
    ('heLLo worLd', 3)

     re.compile()

    将正则表达式编译成正则表达式对象,方便复用该正则表达式

    >>> content = 'hello 123456 world'
    >>> obj = re.compile('d{3}')
    >>> obj.search(content).group()
    '123'
    >>> obj.findall(content)    #重用了obj
    ['123', '456']

    对上面的一个小结:
    尽量使用泛匹配,使用括号得到匹配目标,尽量使用非贪婪模式,有换行符就用re.S
    强调re.match是从字符串的起始位置匹配一个模式

  • 相关阅读:
    BZOJ 3160 万径人踪灭
    BZOJ 2160 拉拉队排练
    模板 manacher算法
    [Tjoi2016&Heoi2016]求和
    [HZOI 2015]疯狂的机器人
    [BZOJ3456]城市规划
    BZOJ 4372 烁烁的游戏
    洛谷3794 签到题IV
    BZOJ 3730 震波
    BZOJ 4916 神犇和蒟蒻
  • 原文地址:https://www.cnblogs.com/cyfiy/p/7754284.html
Copyright © 2020-2023  润新知