zoukankan      html  css  js  c++  java
  • Python的常用模块

    python的常用模块

    一、time模块

    # time模块
    #     python中时间分为三种格式:
    #     1、时间戳(timestamp):从1970年到现在经过的秒数
    #           作用:用于时间间隔的计算
    import time
    print(time.time())
    
    #     2、按某种格式显示的时间(Format String):2020-04-15 09:09:09
    #       作用:用于展示时间
    print(time.strftime('%Y-%m-%d %H:%M:%S %p'))  # 2020-04-15 09:20:27 AM
    print(time.strftime('%Y-%m-%d %X'))  # 2020-04-15 09:20:48
    print(time.strftime('%Y-%m-%d %Y'))  # 2020-04-15 2020
    
    #     3、结构化的时间(struct_time)
    #       作用:用于单独获取时间的某一部分
    res = time.localtime()
    print(res)
    """运行结果:
    time.struct_time(tm_year=2020, tm_mon=4, tm_mday=15, tm_hour=9, 
                    tm_min=27, tm_sec=6, tm_wday=2, tm_yday=106, tm_isdst=0)
    tm_year=2020 当前年
    tm_mon=4     当前月
    tm_mday=15   当前天
    tm_hour=9    当前小时
    tm_min=27    当前分钟
    tm_sec=6     当前秒
    tm_wday=2    当前是周几,从0开始:0代表星期一
    tm_yday=106  当前所在年的天:当前年的第106天。
    tm_isdst=0   是否是夏令时
    """
    print(res.tm_year)  # 获取当前年-->2020
    print(res.tm_yday)  # 当前所在年的天-->106
    %a    Locale’s abbreviated weekday name.     
    %A    Locale’s full weekday name.     
    %b    Locale’s abbreviated month name.     
    %B    Locale’s full month name.     
    %c    Locale’s appropriate date and time representation.     
    %d    Day of the month as a decimal number [01,31].     
    %H    Hour (24-hour clock) as a decimal number [00,23].     
    %I    Hour (12-hour clock) as a decimal number [01,12].     
    %j    Day of the year as a decimal number [001,366].     
    %m    Month as a decimal number [01,12].     
    %M    Minute as a decimal number [00,59].     
    %p    Locale’s equivalent of either AM or PM.    (1)
    %S    Second as a decimal number [00,61].    (2)
    %U    Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0.    (3)
    %w    Weekday as a decimal number [0(Sunday),6].     
    %W    Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0.    (3)
    %x    Locale’s appropriate date representation.     
    %X    Locale’s appropriate time representation.     
    %y    Year without century as a decimal number [00,99].     
    %Y    Year with century as a decimal number.     
    %z    Time zone offset indicating a positive or negative time difference from UTC/GMT of the form +HHMM or -HHMM, where H represents decimal hour digits and M represents decimal minute digits [-23:59, +23:59].     
    %Z    Time zone name (no characters if no time zone exists).     
    %%    A literal '%' character.
    time模块内%含义

     二、datetime模块

    import datetime
    # 获取当前时间
    print(datetime.datetime.now())  # 2020-04-15 09:41:48.551997
    # 在此时间基础上参与时间的运算:当前时间+3天后的时间。3可以是正数也可以是负数。
    print(datetime.datetime.now() + datetime.timedelta(days=3))  # 2020-04-18 09:47:26.094479
    
    """timedelta(days=)语法
    def __init__(self, days: float = ..., seconds: float = ..., microseconds: float = ...,
                 milliseconds: float = ..., minutes: float = ..., hours: float = ...,
                 weeks: float = ...) -> None: ...
    """

     三、时间格式的转换

    计算机认识的时间只能是“时间戳”格式。
    人类能读懂的时间有:格式化的字符串时间 ,机构化的时间
    三种转换关系如下图所示

    import time
    # 时间模块需要掌握的操作
    # 1、时间格式的转换
    # 结构化时间struct_time --> 时间戳Timestamp
    # s_time = time.localtime()
    # print(time.mktime(s_time))  # 1586916748.0
    # print(time.time())          # 1586916748.0209408
    
    # 时间戳Timestamp --> 结构化时间:struct_time
    # tp_time = time.time()
    # print(time.localtime(tp_time))
    # time.struct_time(tm_year=2020, tm_mon=4, tm_mday=15, tm_hour=10, tm_min=13, tm_sec=38, tm_wday=2, tm_yday=106, tm_isdst=0)
    
    # 结构化时间struct_time -->格式化的字符串形式的时间
    s_time = time.localtime()
    print(time.strftime('%Y-%m-%d %H:%M:%S',s_time))  # 2020-04-15 10:27:20
    
    # 格式化的字符串时间-->结构化时间struct_time
    print(time.strptime('2020-04-15 10:27:20','%Y-%m-%d %H:%M:%S'))
    # time.struct_time(tm_year=2020, tm_mon=4, tm_mday=15, tm_hour=10, tm_min=27, tm_sec=20, tm_wday=2, tm_yday=106, tm_isdst=-1)
    # 重点掌握:格式化的字符串时间format string <--> 时间戳timestamp,互相转换,通过结构化中转
    # 假设需求:格式化字符串时间是2020-04-15 10:27:20,该时间是VIP注册的时间,用户又充值7天时间
    # 1、先将格式化字符串时间转换成结构化时间(forma string --> struct_time)
    struct_time = time.strptime('2020-04-15 10:27:20','%Y-%m-%d %H:%M:%S')
    # 2、将结构化时间转换成时间戳(struct_time-->timestamp,一天是时间是=24*60*60=86400秒),加7天时间
    timestamp = time.mktime(struct_time) + 7*86400
    print(timestamp)  # 1587522440.0
    # 3、将时间戳转换成结构化时间(timestamp-->struct_time)
    struct_time_1 = time.localtime(timestamp)
    # 4、将结构化时间转换成格式化字符串时间(struct_time --> Format String)
    format_string = time.strftime('%Y-%m-%d %H:%M:%S',struct_time_1)
    print(format_string)  # 2020-04-22 10:27:20
    # 直接将时间戳直接转换成格式化字符串的时间
    print(datetime.datetime.fromtimestamp(333333)) # 1970-01-05 04:35:33 
    # 补充:世界标准时间与本地时间
    # print(time.localtime())  # 本地时间,tm_hour本地时间与世界标准时间相差8小时
    # print(time.gmtime())  # 世界标准时间  # tm_hour=2世界标准时间
    # print(time.localtime(333333333))  # tm_hour=8
    # print(time.gmtime(333333333))     # tm_hour=0
    # import time
    # 了解知识
    # 休眠
    # time.sleep(3)
    
    # time.strftime()与time.asctime()区别,不用%
    # print(time.asctime())  # Wed Apr 15 12:39:50 2020
    # print(time.strftime())
    
    import datetime
    # 获取当前时间
    print(datetime.datetime.now())  # 2020-04-15 12:43:04.573067
    print(datetime.datetime.utcnow()) # 2020-04-15 04:43:04.573067

    四、random模块

     1 import random
     2  
     3 print(random.random())#(0,1)----float    大于0且小于1之间的小数
     4  
     5 print(random.randint(1,3))  #[1,3]    大于等于1且小于等于3之间的整数
     6  
     7 print(random.randrange(1,3)) #[1,3)    大于等于1且小于3之间的整数
     8  
     9 print(random.choice([1,'23',[4,5]]))#1或者23或者[4,5]
    10  
    11 print(random.sample([1,'23',[4,5]],2))#列表元素任意2个组合
    12  
    13 print(random.uniform(1,3))#大于1小于3的小数,如1.927109612082716 
    14  
    15  
    16 item=[1,3,5,7,9]
    17 random.shuffle(item) #打乱item的顺序,相当于"洗牌" ,应用:随机验证码
    18 print(item)
    random模块
    # 随机验证码实例
    import random
    res=''
    for i in range(6):
        # 获取随机字母或数字
        # 随机字符=random.choice([从26个大写英文字母中随机取出一个,从10个数字中随机取出一个])
        # 从26个大写英文字母中随机取出一个=chr(random.randint(65,90))
        # 从10个数字中随机取出一个=random.rangdint(0,9),得到的是一个整型 str转换成字符串str(random.rangdint(0,9))
        # res += 随机字符
        # 实现如下:
        s1 = chr(random.randint(65,90))
        s2 = str(random.randint(0,9))
        res += random.choice([s1,s2])
    print(res)
    
    
    # 随机验证码实例
    import random
    res=''
    for i in range(6):
        s1 = chr(random.randint(65,90))
        s2 = str(random.randint(0,9))
        res += random.choice([s1,s2])
    print(res)
    
    # 思考:有的验证码是4位,有的验证码是6位,所以参数位置不能写死,修改如下:
    def make_code(size=4):
        res = ''
        for i in range(size):
            s1 = chr(random.randint(65, 90))
            s2 = str(random.randint(0, 9))
            res += random.choice([s1, s2])
        print(res)
    print(make_code()) # 不传参就是默认4位
    # print(make_code(6)) # 传个6位的参数,就是6位
    
    
    # 查看ASCII表中对应的数值
    print(chr(65))  # A
    print(chr(90))  # Z
    print(ord('A')) # 65
    五、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的大小
    OS模块功能
    import os
    # 查看某一个文件夹下有哪些子文件
    # res = os.listdir(r'D:pycharmoldboy_29day022	est022')
    # print(res)
    # 查看当前文件夹下所有的子文件以及子文件夹的名字
    
    # res = os.listdir('.')
    # print(res)
    # 需求:统计某一个文件夹大小的功能,如果查看的是文件统计大小,如果是文件夹需要再次打开
    
    # 获取文件大小 单位字节
    # size = os.path.getsize(r'D:pycharmoldboy_29day022	est022')
    # print(size)
    
    # 运行一条系统命令,
    # dir:windows下查看
    # os.system("dir C:\a")
    # 应用程序--->给操作系统发一条命令ls
    # os.system('dir /')
    
    # environ环境变量
    # PATH = 文件夹
    # sys.path  # 导入模块
    
    # 获取环境变量
    # print(os.environ)  # 运行后都是字典形式:{'ALLUSERSPROFILE': 'C:\ProgramData'
    # key与value必须都为字符串
    # 加入一组key:value,我们后期在系统内可以用到的环境变量
    # os.environ['aaaaaaaaaaaaaaaaaaaaaa'] = '1111111111111111111111'
    # print(os.environ) # 运行如下:...'AAAAAAAAAAAAAAAAAAAAAA': '1111111111111111111111'
    os实例
    import os
    # print(__file__)  # 查看文件所在位置:D:/pycharm/oldboy_29/day022/test022/test022_09ospath.py
    # print(os.path.abspath(__file__))  # 根据平台显示对应的路径分割符格式:D:pycharmoldboy_29day022	est022	est022_09ospath.py
    
    # res = os.path.split('/a/b/c/d.txt')
    # print(res)  # 以元组形式划分文件夹名称和文件名称('/a/b/c', 'd.txt')
    
    # 获取文件夹名称
    # print(os.path.dirname(r'/a/b/c/d.txt'))  # /a/b/c
    # 获取文件名称
    # print(os.path.basename(r'/a/b/c/d.txt'))  # d.txt
    
    # 判断是否是绝对路径
    # print(os.path.isabs('/a/b/c')) # 是返回True
    # print(os.path.isabs('D:Python38python.exe')) # 是返回True
    
    # 判断存在的文件
    # print(os.path.isfile(r'test022_09ospath.py'))  # True
    # print(os.path.isfile(r'test022_09ospath1.py'))  # False
    # print(os.path.isfile(r'test022'))  # 这是个文件夹所以返回False
    
    # 判断是否是文件夹
    print(os.path.isdir(r'day022'))  # True
    
    # 将多个路径组合后返回
    print(os.path.join('a','/','b'))
    在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))
    /Users/jieli/test1

    # 在python3.5后,退出一个新的模块pathlib
    from pathlib import Path
    root = Path(__file__)
    res = root.parent.parent
    print(res)

    # D:pycharmoldboy_29day022
     

     六、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       返回操作系统平台名称
    sys模块
    import sys
    # sys.argv获取的是解释器后参数值
    print(sys.argv)
    # 在交换模式下 python test022_11.py 1 2 3
    # D:pycharmoldboy_29day022	est022>python test022_11.py 1 2 3
    # ['test022_11.py', '1', '2', '3']
    #=========知识储备==========
    #进度条的效果
    # [#             ]
    # [##            ]
    # [###           ]
    # [####          ]
    
    #指定宽度
    # print('[%-15s]' %'#')
    # print('[%-15s]' %'##')
    # print('[%-15s]' %'###')
    # print('[%-15s]' %'####')
    
    import time
    # res = ''
    # for i in range(50):
    #     res+="#"
    #     time.sleep(0.3)
    #     print('
    [%-50s]' % res,end='')
    
    import time
    
    def progress(percent):
        # 进度条的功能
        if percent > 1:
            percent = 1
        res = int(50*percent) * '#'
        print('
    [%-50s] %d%%' % (res,int(percent*100)), end='')
    
    
    recv_size = 0
    total_size = 33333333333
    
    while recv_size < total_size:
        time.sleep(0.001)  # 下载了1024个字节的数据
        recv_size += 1024
        # 打印进度条
    
        # print(recv_size)
        percent = recv_size / total_size  # 1024 / 3333333
        progress(percent)
    七、shutil模块

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

    shutil.copyfileobj(fsrc, fdst[, length])
    将文件内容拷贝到另一个文件中

    1 import shutil
    2  
    3 shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))
    shutil.copyfile(src, dst)
    拷贝文件
    
    1 shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在
     
    
    shutil.copymode(src, dst)
    仅拷贝权限。内容、组、用户均不变
    
    1 shutil.copymode('f1.log', 'f2.log') #目标文件必须存在
    
    shutil.copystat(src, dst)
    仅拷贝状态的信息,包括:mode bits, atime, mtime, flags
    
    1 shutil.copystat('f1.log', 'f2.log') #目标文件必须存在
    
    shutil.copy(src, dst)
    拷贝文件和权限
    
    1 import shutil
    2  
    3 shutil.copy('f1.log', 'f2.log')
     
    shutil.copy2(src, dst)
    拷贝文件和状态信息
    
    1 import shutil
    2  
    3 shutil.copy2('f1.log', 'f2.log')
     
    shutil.ignore_patterns(*patterns)
    shutil.copytree(src, dst, symlinks=False, ignore=None)
    递归的去拷贝文件夹
    
    1 import shutil
    2  
    3 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]])
    递归的去删除文件
    
    1 import shutil
    2  
    3 shutil.rmtree('folder1')
    
    shutil.move(src, dst)
    递归的去移动文件,它类似mv命令,其实就是重命名。
    
    1 import shutil
    2  
    3 shutil.move('folder1', 'folder3')
     
    
    shutil.make_archive(base_name, format,...)
    
    创建压缩包并返回文件路径,例如:zip、tar
    
    创建压缩包并返回文件路径,例如:zip、tar
    
    base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
    如 data_bak                       =>保存至当前路径
    如:/tmp/data_bak =>保存至/tmp/
    format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
    root_dir: 要压缩的文件夹路径(默认当前目录)
    owner: 用户,默认当前用户
    group: 组,默认当前组
    logger: 用于记录日志,通常是logging.Logger对象
    复制代码
    1 #将 /data 下的文件打包放置当前程序目录
    2 import shutil
    3 ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data')
    4   
    5   
    6 #将 /data下的文件打包放置 /tmp/目录
    7 import shutil
    8 ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data') 
    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()
    
    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()

     八、json&pickle模块

      之前我们学过用eval内置方法,可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval重点还是通常用来执行一个字符串表达式,并返回表达式的值

    # 1、什么是序列化&反序列化?
    #   序列化指的是把内存的数据类型转换成一种特定的格式的内容,
    #
    #   内存中的数据类型-->序列化--> 特定的格式(json格式或者pickle格式)
    #   内存中的数据类型<--反序列化<--特定的格式(json格式或者pickle格式)
    #
    #   土办法:
    #   {'a':1} -->序列化str({'a':1})-->"{{'a':1}}"
    #   {'a':1} <--反序列化eval({'a':1})<--"{{'a':1}}"
    #
    # 2、为何要序列化?
    #   序列化得到的结果-->特定的格式的内容有两种用途。
    #   1、可用于存储(变量的值可以记录某种状态)-->用于存档
    #   2、传输给其他平台使用-->跨平台数据交互
    #
    # 例如:同一个软件内有不同的组件,不同的组件使用不用的语言实现。如何进行数据交互。
    #         Python的一个列表给了Java,到java中就是数组,在Python和java之间找个第三方中间格式
    #         Python               java
    #          列表    特殊格式    数组
    # 强调:
    #   针对用途1的特定格式:可以是一种专用的格式-->pickle只有python可以识别
    #   针对用途2的特定格式:应该是一种通用、能够被所有语言识别的格式==>json
    #

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

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

     

     

    # 3、如何使用序列化和反序列化
    import json
    # 示范一
    # 序列化
    # json_res = json.dumps(True)
    # print(res,type(json_res))  # true <class 'str'>
    
    # json_res = json.dumps([1,'a',True,False])
    # print(res,type(json_res))  # 得到json格式:[1, "a", true, false] <class 'str'>
    
    # 反序列化
    # l = json.loads(json_res)
    # print(l,type(l))  # 得到python格式的:[1, 'a', True, False] <class 'list'>
    
    
    # 示范二:
    # 序列化的结果写入文件的复杂方法,dumps
    # json_res = json.dumps([1,'a',True,False])
    # with open('test.json',mode='wt',encoding='utf-8') as f:
    #     f.write(json_res)
    # # 运行结果:[1, "a", true, false]
    
    # 将序列化的结果写入文件的简单方法:dump,一步到位
    # with open('test.json',mode='wt',encoding='utf-8') as f:
    #     json.dump([1,'a',True,False],f)
    # 运行结果:[1, "a", true, false]
    
    # 反序列化:从文件读取json格式的字符串进行序列化操作的复杂方法。loads
    # with open('test.json',mode='rt',encoding='utf-8') as f:
    #     json_res = f.read()
    #     l = json.loads(json_res)
    #     print(l,type(l))
    # 运行结果:[1, 'a', True, False] <class 'list'>
    
    # 反序列化:从文件读取json格式的字符串进行序列化操作的简单方法。load
    # with open('test.json',mode='rt',encoding='utf-8') as f: 
    #     l = json.load(f)
    #     print(l,type(l))
    # 运行结果:[1, 'a', True, False] <class 'list'>
    # json补充
    # json验证:json格式兼容的是所有语言通用的数据类型,不能识别某一语言所独有的类型
    import json
    # json.dumps({1,2,3,4,5})
    
    # json强调:json.loads('[1, "a", true, false]')格式要放json格式的内容
    # l = json.loads('[1, "a", true, false]')
    # print(l[0])
    # 1
    # json格式不能于python混淆,python格式里的True
    # l = json.loads('[1, "a", True, False]')
    # print(l[0])
    # json与python格式混淆后报错,json.decoder.JSONDecodeError: Expecting value: line 1 column 10 (char 9)
    
    # python3.5以前的版本要加入b
    # l = json.loads(b'[1, "a", true, false]')
    # print(l[0])
    
    # with open('test.json',mode='rt') as f:
    #     l = json.load(f)
    #
    # res = json.dumps({'name':'hahaha哈哈哈'})
    # print(res,type(res))  # {"name": "hahahau54c8u54c8u54c8"} <class 'str'>
    
    # res = json.loads('{"name": "hahahau54c8u54c8u54c8"}')
    # print(res,type(res))  # {'name': 'hahaha哈哈哈'} <class 'dict'>

     九、猴子补丁

    # 一.什么是猴子补丁?
          猴子补丁的核心就是用自己的代码替换所用模块的源代码,详细地如下
      1,这个词原来为Guerrilla Patch,杂牌军、游击队,说明这部分不是原装的,在英文里guerilla发音和gorllia(猩猩)相似,再后来就写了monkey(猴子)。
      2,还有一种解释是说由于这种方式将原来的代码弄乱了(messing with it),在英文里叫monkeying about(顽皮的),所以叫做Monkey Patch。
    
    
    # 二. 猴子补丁的功能(一切皆对象)
      1.拥有在模块运行时替换的功能, 例如: 一个函数对象赋值给另外一个函数对象(把函数原本的执行的功能给替换了)
    class Monkey:
        def hello(self):
            print('hello')
    
        def world(self):
            print('world')
    
    
    def other_func():
        print("from other_func")
    
    
    
    monkey = Monkey()
    monkey.hello = monkey.world
    monkey.hello()
    monkey.world = other_func
    monkey.world()
    
    # 三.monkey patch的应用场景
    如果我们的程序中已经基于json模块编写了大量代码了,发现有一个模块ujson比它性能更高,
    但用法一样,我们肯定不会想所有的代码都换成ujson.dumps或者ujson.loads,那我们可能
    会想到这么做
    import ujson as json,但是这么做的需要每个文件都重新导入一下,维护成本依然很高
    此时我们就可以用到猴子补丁了
    只需要在入口处加上
    , 只需要在入口加上:
    
    import json
    import ujson
    
    def monkey_patch_json():
        json.__name__ = 'ujson'
        json.dumps = ujson.dumps
        json.loads = ujson.loads
    
    monkey_patch_json() # 之所以在入口处加,是因为模块在导入一次后,后续的导入便直接引用第一次的成果
    
    #其实这种场景也比较多, 比如我们引用团队通用库里的一个模块, 又想丰富模块的功能, 除了继承之外也可以考虑用Monkey
    Patch.采用猴子补丁之后,如果发现ujson不符合预期,那也可以快速撤掉补丁。个人感觉Monkey
    Patch带了便利的同时也有搞乱源代码的风险!
    
    猴子补丁与ujson

    十、pickle模块

    import pickle
     
    dic={'name':'alvin','age':23,'sex':'male'}
     
    print(type(dic))#<class 'dict'>
     
    j=pickle.dumps(dic)
    print(type(j))#<class 'bytes'>
     
     
    f=open('序列化对象_pickle','wb')#注意是w是写入str,wb是写入bytes,j是'bytes'
    f.write(j)  #-------------------等价于pickle.dump(dic,f)
     
    f.close()
    #-------------------------反序列化
    import pickle
    f=open('序列化对象_pickle','rb')
     
    data=pickle.loads(f.read())#  等价于data=pickle.load(f)
     
     
    print(data['age'])
    # coding:utf-8
    import pickle
    
    with open('a.pkl',mode='wb') as f:
        # 一:在python3中执行的序列化操作如何兼容python2
        # python2不支持protocol>2,默认python3中protocol=4
        # 所以在python3中dump操作应该指定protocol=2
        pickle.dump('你好啊',f,protocol=2)
    
    with open('a.pkl', mode='rb') as f:
        # 二:python2中反序列化才能正常使用
        res=pickle.load(f)
        print(res)
    
    python2与python3的pickle兼容性问题

    Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。  

    十一、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')
    #在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) #打印生成的格式

     十二、configparser模块,加载某种特定格式的配置文件

    配置文件如下:数据准备test.ini,类似于settings.py的样式 
    # 注释1
    ; 注释2
    
    [section1]
    k1 = v1
    k2:v2
    user=egon
    age=18
    is_admin=true
    salary=31
    
    [section2]
    k1 = v1
    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'))
    基于上述方法添加一个ini文档
    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)

     十三、hash介绍

    # 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值长度是固定的

      hash算法就像一座工厂,工厂接收你送来的原材料(可以用m.update()为工厂运送原材料),经过加工返回的产品就是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多次为校验大文件提供了可能。
    '''
    # 如何使用hash
    import hashlib
    m = hashlib.md5() # fc5e038d38a57032085441e7fe7010b0
    # m = hashlib.sha256()  # 936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af
    m.update('hello'.encode('utf-8'))
    m.update('world'.encode('utf-8'))
    res = m.hexdigest() # hello world
    print(res)  # 只要传入的内容一样,得到的hash值必然一样:fc5e038d38a57032085441e7fe7010b0
    
    m1 = hashlib.md5('he'.encode('utf-8'))
    m1.update('llo'.encode('utf-8'))
    m1.update('world'.encode('utf-8'))
    res = m1.hexdigest()
    print(res)  # 只要传入的内容一样,得到的hash值必然一样:fc5e038d38a57032085441e7fe7010b0 

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

    import hashlib
     
    # ######## 256 ########
     
    hash = hashlib.sha256('898oaFs09f'.encode('utf8'))
    hash.update('alvin'.encode('utf8'))
    print (hash.hexdigest())#e79e68f070cdedcfe63eaf1a2e92c83b4cfb1b5c6bc452d214c1b7e77cdfd1c7
    # 撞库的实例:
    
    #模拟撞库:
    # 截获的密文如下
    cryptograph = 'aee949757a2e698417463d47acac93df'
    # 猜测的密码如下
    passwds=[
        'alex3714',
        'alex1313',
        'alex94139413',
        'alex123456',
        '123456alex',
        'a123lex',
        ]
    # 做一个密码字典如下
    import hashlib
    dic = {}
    for p in passwds:
        res = hashlib.md5(p.encode('utf-8'))
        dic[p] = res.hexdigest()
    print(dic)
    
    # 进行比对
    for k,v in dic.items():
        if v == cryptograph:
            print('撞库成功,明文密码是:%s',k)
    # 提示撞库的成本==>密码加盐,拆分密码前后加入混淆数据
    import hashlib
    m = hashlib.md5()
    m.update('天王'.encode('utf-8'))
    m.update('alex3714'.encode('utf-8'))
    m.update('盖地虎'.encode('utf-8'))
    print(m.hexdigest())  # ef606e983c958a13273eaad0b29a054c
    """
    密码加盐:
    'a'天l王e盖x地3虎714
    """
    # 密码加盐的优点:
    # 攻击思路:撞库密码
    
    # md5可以反解

     十四、suprocess模块

    import subprocess
    # 执行系统命令
    obj = subprocess.Popen('ls /root',shell=True,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.PIPE,
                     )
    print(obj)  # <subprocess.Popen object at 0x000001FC3FCF6B80>
    res = obj.stdout.read()  # 正确的结果
    print(res.decode('gbk'),type(res))  # b'' <class 'bytes'>
    # err_res = obj.stderr.read() # 错误结果
    # print(err_res.decode('gbk'),type(err_res))  # windows系统使用gbk
    # print(err_res.decode('utf-8'),type(err_res))  # Linux系统使用utf-8

     十五、logging模块

    一 日志级别
    
    CRITICAL = 50 #FATAL = CRITICAL
    ERROR = 40
    WARNING = 30 #WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0 #不设置
    自下而上输出

     

    import logging
    
    # 一:日志配置
    logging.basicConfig(
        # 1、日志输出位置:1、终端 2、文件
        # filename='access.log', # 不指定,默认打印到终端
    
        # 2、日志格式
        format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
    
        # 3、时间格式
        datefmt='%Y-%m-%d %H:%M:%S %p',
    
        # 4、日志级别
        # critical => 50
        # error => 40
        # warning => 30
        # info => 20
        # debug => 10
        level=30,
    )
    
    # 二:输出日志
    logging.debug('调试debug,工程师调试用想出现的信息')
    logging.info('消息info,正常信息')
    logging.warning('警告warn,可以这样但要注意了')
    logging.error('错误error,程序出现了错误')
    logging.critical('严重critical,可能导致程序崩溃')
    ''' 运行结果如下,默认级别为warning,默认打印到终端
    # 注意下面的root是默认的日志名字 
    WARNING:root:警告warn,可以这样但要注意了
    ERROR:root:错误error,程序出现了错误
    CRITICAL:root:严重critical,可能导致程序崩溃
    '''
    2、日志配置字典
    
    """
    logging配置
    """
    
    import os
    
    # 1、定义三种日志输出格式,日志中可能用到的格式化串如下
    # %(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用户输出的消息
    
    # 2、强调:其中的%(name)s为getlogger时指定的名字
    standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' 
                      '[%(levelname)s][%(message)s]'
    
    simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
    
    test_format = '%(asctime)s] %(message)s'
    
    # 3、日志配置字典
    LOGGING_DIC = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'standard': {
                'format': standard_format
            },
            'simple': {
                'format': simple_format
            },
            'test': {
                'format': test_format
            },
        },
        'filters': {},
        'handlers': {
            #打印到终端的日志
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',  # 打印到屏幕
                'formatter': 'simple'
            },
            #打印到文件的日志,收集info及以上的日志
            'default': {
                'level': 'DEBUG',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,日志轮转
                'formatter': 'standard',
                # 可以定制日志文件路径
                # BASE_DIR = os.path.dirname(os.path.abspath(__file__))  # log文件的目录
                # LOG_PATH = os.path.join(BASE_DIR,'a1.log')
                'filename': 'a1.log',  # 日志文件
                'maxBytes': 1024*1024*5,  # 日志大小 5M
                'backupCount': 5,
                'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
            },
            'other': {
                'level': 'DEBUG',
                'class': 'logging.FileHandler',  # 保存到文件
                'formatter': 'test',
                'filename': 'a2.log',
                'encoding': 'utf-8',
            },
        },
        'loggers': {
            #logging.getLogger(__name__)拿到的logger配置
            '': {
                'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
                'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
                'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
            },
            '专门的采集': {
                'handlers': ['other',],
                'level': 'DEBUG',
                'propagate': False,
            },
        },
    }
    # encoding=utf-8
    # auther:lsj
    """
    logging配置:日志配置字典LOGGING_DIC
    """
    
    import os
    
    # 1、定义三种日志输出格式,日志中可能用到的格式化串如下
    # %(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用户输出的消息
    
    # 2、强调:其中的%(name)s为getlogger时指定的名字,定义格式如下三种
    standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' 
                      '[%(levelname)s][%(message)s]'
    
    simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
    
    test_format = '%(asctime)s] %(message)s'
    
    # 3、日志配置字典
    LOGGING_DIC = {
        'version': 1,# 版本
        'disable_existing_loggers': False, # 关闭已存在的日志
        'formatters': {  # 记住 formatters名不可改
            'standard': {  # standard自定义个名字可以改,标准格式
                'format': standard_format  # format名字不可以改
            },
            'simple': { # simple 自定义名字可以修改,简单格式
                'format': simple_format  # format名字不可以改
            },
            'test': {  # 自定义名字可以修改,最简单的格式
                'format': test_format  # format名字不可以改
            },
        },# 格式化
        'filters': {},
        # handlers是日志的接收者,不同的handler会将日志输出给不同的位置
        'handlers': {
            #打印到终端的日志
            'console': {  # console该key是可以修改的
                'level': 'DEBUG',  # 日志级别,level名字不能改
                'class': 'logging.StreamHandler',  # 打印到屏幕,key名字不能改
                'formatter': 'simple' # key名字不能改
            },
            #打印到文件的日志,收集info及以上的日志
            'default': {
                'level': 'DEBUG',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,日志轮转
                'formatter': 'standard',
                # 可以定制日志文件路径
                # BASE_DIR = os.path.dirname(os.path.abspath(__file__))  # log文件的目录
                # LOG_PATH = os.path.join(BASE_DIR,'a1.log')
                'filename': 'a1.log',  # 日志文件
                'maxBytes': 1024*1024*5,  # 日志大小 5M
                'backupCount': 5,
                'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
            },
            # 打印到其他位置
            'other': {
                'level': 'DEBUG',
                'class': 'logging.FileHandler',  # 保存到文件
                'formatter': 'test',
                'filename': 'a2.log',  # 文件路径,在项目中这里路径os.path.json(os.path.dirname(os.path.dirname(__file__)),'log','a2.log')
                'encoding': 'utf-8',
            },
        },# 记住
        # loggers日志的产生者,产生的日志会传递给handler,然后控制输出
        'loggers': {
            #logging.getLogger(__name__)拿到的logger配置
            '第一个日志的产生者:kkk': {
                'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
                'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
                'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
            },
            '第二个日志的产生者:bbb': {
                'handlers': ['other',],
                'level': 'DEBUG',
                'propagate': False,
            },
        },  # 记住
    }
    test024_05settings.py
    # encoding=utf-8
    # auther:lsj
    
    # 接下来要做到的是:拿到日志的产生者
    # 第一个日志的产生者:kkk
    # 第二个日志的产生者:bbb
    # 如何拿到kkk和bbb?
    
    # (1)但是需要先导入日志配置字典LOGGING_DIC
    import test025_05settings
    import logging
    
    # 以下的两种导入config意义相同
    # import logging.config  # 这种导入在使用的时候注意就得用logging.config
    # from logging import config
    
    from logging import config,getLogger
    
    # 查看config在哪?
    # import logging
    # logging.config  # AttributeError: module 'logging' has no attribute 'config'
    
    # (2)加载配置
    config.dictConfig(test025_05settings.LOGGING_DIC)
    # 使用import logging.config导入方式使用如下
    # logging.config.dictConfig(test025_05settings.LOGGING_DIC)
    # (3)获取日志字典里的某一个方法
    logger1 = getLogger('第一个日志的产生者:kkk')
    # settings.LOGGING_DIC
    
    # (4)产生日志,此时在终端和文件都产生了日志
    logger1.info('这是一条info日志')
    # 终端日志:[INFO][2020-04-17 15:12:49,191][test024_05src.py:32]这是一条info日志
    # a1.log文件日志:[2020-04-17 15:12:49,191][MainThread:11492][task_id:第一个日志的产生者:kkk][test024_05src.py:32][INFO][这是一条info日志]
    
    # 如果我只想往终端输出日志使用
    logger2 = getLogger('第二个日志的产生者:bbb')
    logger2.info('logger2只向终端输出一条info日志')
    # 终端日志输出:[INFO][2020-04-17 15:19:11,047][test024_05src.py:32]这是一条info日志
    test024_05src.py
    
    
    # 日志名的命名
    # 日志名是区分日志业务归属的一种非常重要的标识
    # settings 里设置默认的日志名字
             '': {  # 如果用户找不大就默认使用它默认
                'handlers': ['default', ],
                'level': 'DEBUG',
                'propagate': False,
            },  
    
    # 在src文件中调用一个不存在的名字
    logger4 = getLogger('fsa')
    logger4.info("找不到名字就使用空的默认")

     十六、re正则模块

    1、什么是正则?

      正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符,来描述字符或租字符串的方法,或者说正则就是用来描述一类事物的规则。(在python中,通过re模块实现)。正则表达式模式被编译成一系列的字节码,然后由用C编写的匹配引擎执行。

    2、生活中处处都是正则

      比武我们描述:4条腿。你可能 会想到四条腿的动物或者桌子,椅子等,继续描述:4条腿,活得,就只剩下四条腿的动物这一类了。

    3、常用匹配模式(元字节)

    # encoding=utf-8
    # auther:lsj
    
    # 正则re实例
    import re
    print(re.findall('w','abc123*&^_= '))  # w:字母数字下划线。运行结果:['a', 'b', 'c', '1', '2', '3', '_']
    print(re.findall('W','abc123*&^_= '))  # W:非字母数字下划线。运行结果:['*', '&', '^', '=', ' ']
    print(re.findall('s','abc	
    
    f123*&^_= '))  # s:匹配任意空白字符。运行结果:['	', '
    ', '
    ', 'x0c', ' ']
    print(re.findall('S','abc	
    
    f123*&^_= '))  # s:非空白字符。运行结果:['a', 'b', 'c', '1', '2', '3', '*', '&', '^', '_', '=']
    print(re.findall('d','abcASD123*&^_= '))  # d:匹配任意数字。运行结果:['1', '2', '3']
    print(re.findall('D','abcASD123*&^_= '))  # D:匹配任意非数字。运行结果:['a', 'b', 'c', 'A', 'S', 'D', '*', '&', '^', '_', '=', ' ']
    print(re.findall('Aabc','abcASD123abc*&^_= '))  # A:匹配字符串开头。运行结果:['abc']
    print(re.findall('Aabc',' abcASD123abc*&^_= '))  # A:匹配字符串开头。运行结果:[]
    print(re.findall('abc',' abcASD123abcABC*&^_= '))  # 查找所有匹配的字符,运行结果:['abc', 'abc']
    print(re.findall('a',' abcASD123abcABC*&^_= '))  # 匹配字符串结束,运行结果:[]
    print(re.findall('a',' abcASD123abcABC*&^_= a'))  # 匹配字符串结束,运行结果:['a']
    print(re.findall('a',"""
    abc
    ASD
    123
    abc
    ABC*&^_= 
    a"""))  # 匹配到换行前的字符串结束,运行结果:['a']
    
    print(re.findall('^a',' abcASD123abcABC*&^_= a'))  # 匹配字符串开头,运行结果:[]
    print(re.findall('a$',' abcASD123abcABC*&^_= a'))  # 匹配字符串结尾,运行结果:['a']
    print(re.findall('^ab$',' abcASD123abcABC*&^_= a'))  # 同时匹配字符串的开头和结尾,运行结果:[]
    print(re.findall('^ab$','ab'))  # 同时匹配字符串的开头和结尾,运行结果:['ab']
    print(re.findall('^ab$','a b'))  # 同时匹配字符串的开头和结尾,运行结果:[]
    
    # 重复匹配:|.|*|?|.*|.*?|+|{n,m}|
    print(re.findall('.','abc
    123*&^_= ')) # .:匹配除了
    之外任意一个字符,运行结果:['a', 'b', 'c', '1', '2', '3', '*', '&', '^', '_', '=', ' ']
    print(re.findall('a.b','a1b a
    b a|b a	b'))  # .:匹配除了
    之外任意一个字符,运行结果:['a1b', 'a|b', 'a	b']
    print(re.findall('a.b','a1b a
    b a|b a	b',re.DOTALL))  # .:匹配除了
    之外任意一个字符,使用:re.DOTALL之后才能匹配换行符,运行结果:['a1b', 'a
    b', 'a|b', 'a	b']
    
    print(re.findall('..','abc
    123*&^_= ')) # .:匹配除了
    之外任意两个字符,运行结果:['ab', '12', '3*', '&^', '_=']
    
    # 2、* 左侧字符重复0此或无穷次,性格贪婪
    # ab*:取得b可以是0到无穷,a是必须存在
    print(re.findall('ab*','abc
    123*&^_= absd a abb abbbbbb abbhb bbbbb'))  # 运行结果:['ab', 'ab', 'a',abb', 'abbbbbb', 'abb']
    
    # 3、+:左侧字符重复1次或无穷次,性格贪婪
    # a必须存在,b至少出现1此
    print(re.findall('ab+','ab abb abbb abbbbb')) # 运行结果: ['ab', 'abb', 'abbb', 'abbbbb']
    
    # 4、?:左侧字符重复0次或1次,性格贪婪
    print(re.findall('ab?','a ab abb abbb abbbbb')) # 运行结果:['a', 'ab', 'ab', 'ab', 'ab']
    
    # 5、{n,m},自定义左侧字符重复n次到m次,性格贪婪
    # {0,} = *  0到无穷
    # {1,} = +  1到无穷
    # {0,1} = ? 0到1次
    # {n} 单独一个n代表只出现n次,多一次不行少一次也不行。
    # ab{2,5} = a必须存在,b至少存在2次到5次
    print(re.findall('ab{2,5}','a ab abb abbb abbbbb')) # 运行结果:['abb', 'abbb', 'abbbbb']
    
    # 练习:找出下列字符中所有的整数和小数
    # .的体现.
    print(re.findall("d+.?d*","ahfu9qwn22256.fjar7890t1.215gdgr54"))
    
    # 6、[]匹配指定字符一个
    # 如下字符串,找到ab之间存在1个数字的字符
    print(re.findall('[a]d{1}[b]','a|b a3b a26b a2548b aXb a b a
    b')) # ['a3b']
    print(re.findall('[a]d[b]','a|b a3b a26b a2548b aXb a b a
    b')) # ['a3b']
    
    # 如下字符串,找到ab之间存在0-5个数字的字符
    print(re.findall('[a]d{0,5}[b]','a|b a3b a26b a2548b aXb a b a
    b')) # ['a3b', 'a26b', 'a2548b']
    
    # 如下字符串,找到ab之间存在的是0-5的数字的字符
    print(re.findall('a[501234][b]','a|b a3b a26b a2548b aXb a b a
    b')) # ['a3b']
    print(re.findall('a[0-5][b]','a|b a3b a26b a2548b aXb a b a
    b')) # ['a3b']
    
    
    # 如下字符串,找到ab之间存在的是0-9的数字或者a-z的字母的字符
    print(re.findall('a[0-9a-zA-Z]b','a|b a3b a26b a2548b aXb a b a
    b')) # ['a3b', 'aXb']
    
    # 如下字符串,找到ab之间存在的是0-9的数字或者a-z的字母的字符,
    # []内有^代表取反
    # ^代表以匹配的字符开头。
    print(re.findall('a[^0-9a-zA-Z]b','a|b a3b a26b a2548b aXb a b a
    b',re.DOTALL)) # ['a|b', 'a b', 'a
    b']
    
    
    # 如下字符串,找到a-b的字符,
    print(re.findall('a-b',' a-b a|b a3b a26b a2548b aXb a b a
    b',re.DOTALL)) # ['a-b']
    
    # 找出a-b 以及ab之间存在一个数字的字符
    # -在[]内最左侧或者最右侧代表普通字符
    print(re.findall('a[-0-9-
    ]b',' a-b a|b a3b a26b a2548b aXb a b a
    b',re.DOTALL)) # ['a-b', 'a3b', 'a
    b']

     

     

  • 相关阅读:
    java内存泄漏的几种情况
    关于ajax请求,在参数中添加时间戳的必要性
    Linux启动界面切换:图形界面-字符界面(转)
    setTimeout 和 setInterval 的区别
    【域渗透】利用S4U2self提权
    【大数据之Hadoop篇】【1】hadoop集成环境搭建
    《windows核心编程》笔记(API)
    判断是64位操作系统还是32位系统
    centos7中搭建mysql5.7数据库
    Metasploit学习笔记(一) Samba服务 usermap_script安全漏洞相关信息
  • 原文地址:https://www.cnblogs.com/liunaixu/p/12703170.html
Copyright © 2011-2022 走看看