• 【笔记】Python基础六:模块module介绍及常用模块


    一,module模块和包的介绍

    1,在Python中,一个.py文件就称之为一个模块(Module)。

    2,使用模块的好处?

    最大的好处是大大提高了代码的可维护性

    其次,编写代码不必从零开始,我们编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块

    另外,使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,不必考虑名字会与其他模块冲突。但是也要尽量不与内置函数名字冲突。

    3,种类

    1)python标准库

    2)第三方模块

    3)自定义模块

    4,文件夹和包的区别是,包里面有__init__.py文件。包可以用来组织有关系的一组文件,放在不同包里还可以避免模块名字冲突

    5,使用import导入模块

    1)例子

    cal.py文件

    print("ok1")
    def  add(x,y):
        return x+y
    
    def sub(x,y):
        return x-y
    print("ok2")

    main.py文件

    import cal
    print(cal.add(3,7))

    执行main.py文件输出

    ok1
    ok2
    10

    说明import一个文件,首先会执行里面的代码。但是一般我们在cal.py里面定义功能性代码,执行放到一个文件里面

    2)作用

    a,执行里面的代码

    b,导入变量名:cal

    3)导入多个模块import module1,module2,module3

    4)加入from语句作用,导入具体函数可以不使用cal.add(3,7)形式,而直接使用add(3,7)

    from cal import add
    
    print(add(3,7))

    from module1 import *代表导入所有函数,但是这种方法不推荐。不推荐的理由在于,这样使用会导入一些自己不知道的函数名,如果在调用文件里自己起了重名函数,具体调用哪个将取决于from module1 import *和定义同名函数的相对位置。

    使用from语句后,虽然可以导入某个具体函数,但是该py文件也和上面一样会全部执行

    5)路径

    运行某个py文件,会自动把其路径加入到sys.path里面,这样在这个路径下面的文件都可以使用import找到。而sys.path还包含一些python库的路径等等。有个需要注意的地方是Pycharm还会在sys.path里面添加工程文件的路径,更方便使用吧。

    需要注意的是上面提到的路径只是执行文件的路径,如果导入的文件在其下一层,则需要把下一层的文件夹(或者包)加入到import语句中来。举个例子:目录结构如下,这里面my_module是一个文件夹

    bin.py

    my_module--cal.py

                       --main.py

    在bin.py导入main.py使用的是这样的语句:from my_module import main

    在main.py导入cal.py应该使用的是这样的语句:from my_module import cal,这里面虽然main.py和cal.py同级,但是直接用import cal会报错,因为系统只认bin.py(执行文件)所在的路径,而不管main.py和cal.py是否同级

    多级路径情况下,使用点.来表示层级,举例:

    bin.py--

       web--web1--web3--__init.py

                                   --cal.py

    from web.web1.web3 import cal
    from web.web1.web3.cal import add #可以直接使用add(2,6)

    错误示例:

    from web.web1 import web3   #执行web3的__init__文件,
    print(web3.cal.add(2,6))    #执行会报错,唯一不支持的调用方式

    解决上面错误示例的方法:在web3文件夹的__init__.py里面加入

    from . import cal

    则会正确执行 web3.cal.add(2,6) 

    提示:如果我们的自定义模块和Python里的模块重名,由于在sys.path里面我们执行文件的路径在前,Python库的路径在后,首先会搜索执行文件的路径,这样就会把自定义模块导入而不会继续向后搜索系统模块。

    修改路径的方法和实效

    临时修改:

    import sys
    sys.path.append()

    永久修改:

    windows:系统属性--高级--环境变量--系统变量--Path

    在工程上的实际应用中目录结构如下,一般bin是执行的起点:

     fatherdir--bin--bin.py

                  --my_module--main.py

    import sys,os
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    
    #通过BASE_DIR得到整个项目根目录。可以适应拷贝到其他机器运行的情况,但目录结构仅限往上一层的情况

    6,相关知识点:__name__系统变量,取值依据其在不同的文件里而定

    1,在执行文件其值为字符串:__main__

    2,在被调用文件其值为:该文件的路径,例如:web.web1.web3.cal

    使用方法 if __name__=='__main__'

    1,在调用文件里使用,后面是测试代码。这样被其他文件调用的时候这些测试代码不会执行。

    2,在执行文件里使用,就是不想让这个文件成为其他文件调用的对象。比如这种情况,这个执行文件里的函数需要被其他人调用,其他人引用这个文件,使用其中某个具体的函数。如果没有这句话,则会把不需要执行的部分也执行一遍。

    二,Python内置模块

    (一)time模块

    import time
    
    #时间戳,从1970年UNIX诞生到现在的秒数,做计算使用
    print(time.time())    #1481321748.481654秒
    #输出:1549155273.7783637
    
    #当前时间戳的结构化时间---当地时间
    print(time.localtime(1549152782))
    #输出:time.struct_time(tm_year=2019, tm_mon=2, tm_mday=3, tm_hour=8, tm_min=13, tm_sec=2, tm_wday=6, tm_yday=34, tm_isdst=0)
    t=time.localtime()
    print(t.tm_year)
    #输出:2019
    print(t.tm_wday)
    #输出:6
    #当前时间戳的结构化时间---UTC格林尼治
    print(time.gmtime())
    #输出:time.struct_time(tm_year=2019, tm_mon=2, tm_mday=3, tm_hour=0, tm_min=54, tm_sec=33, tm_wday=6, tm_yday=34, tm_isdst=0)
    
    #结构化时间转换成时间戳
    print(time.mktime(time.localtime()))
    #输出:1549155273.0
    
    #结构化时间转成字符串时间strftime
    print(time.strftime('%Y---%m-%d %X',time.localtime()))
    #输出:2019---02-03 08:54:33
    #字符串时间转成结构化时间strptime
    print(time.strptime("2016:12:24:17:50:36","%Y:%m:%d:%X"))
    #输出:time.struct_time(tm_year=2016, tm_mon=12, tm_mday=24, tm_hour=17, tm_min=50, tm_sec=36, tm_wday=5, tm_yday=359, tm_isdst=-1)
    
    #省事的方法直接使用asctime和ctime,但是格式是固定的,如:Sun Feb  3 08:48:31 2019
    print(time.asctime())#asctime是从结构化时间转换成格式化字符串
    #输出:Sun Feb  3 08:54:33 2019
    print(time.ctime())  #ctime是从时间戳转换成格式化字符串
    #输出:Sun Feb  3 08:54:33 2019
    
    #线程推迟指定时间运行,单位:秒
    time.sleep(1)
    
    #clock() 时间差
    
    
    #另外一个时间模块datetime,看起来更直观一点
    import datetime
    print(datetime.datetime.now())
    #输出:2019-02-03 08:54:34.882426

    (二)random模块

    import random
    #0~1的浮点随机数
    ret=random.random()
    #输出:0.11582781711340728
    
    #1~3的整形数,包含3
    ret=random.randint(1,3)
    #输出:3
    #1~3的整形数,不包含3
    ret=random.randrange(1,3)
    #输出:2
    
    #列表中取值
    ret=random.choice([11,22,33,44,55])
    #输出:55
    
    #选择多个,2代表2个
    ret=random.sample([11,22,33,44,55],2)
    #输出:[22, 33]
    
    #任意范围浮点数,如1~4
    ret=random.uniform(1,4)
    #输出:2.792166379341647
    
    #打乱顺序
    ret=[1,2,3,4,5]
    random.shuffle(ret)
    #输出:[5, 2, 1, 4, 3]
    
    print(ret)
    
    #产生随机4位验证码,数字字母都可能
    def v_code():
        ret=""
        for i in range(4):
            num=random.randint(0,9)
            alf=chr(random.randint(65,122))
            s=str(random.choice([num,alf]))
            ret+=s
        return ret
    print(v_code())
    #输出:94Ve

    (三)os模块

    #当前运行文件的工作目录
    print(os.getcwd())
    #输出:D:3Studyday22day22课件代码
    #改变目录,相当于cd
    os.chdir("..")   #..向上一级目录,如工作目录下有名为“dir1”的目录可以写成os.chdir("dir1")
    print(os.getcwd())
    #输出:D:3Studyday22
    
    #返回当前目录
    print(os.curdir)
    #输出:.
    #返回当前目录的父目录
    print(os.pardir)
    #输出:..
    #可生成多层递归目录,如果有同名文件夹报错
    os.makedirs('dirname1/dirname2')
    #若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依次类推。如果目录有文件报错
    os.removedirs("dirname1/dirname2")
    #生成单级目录,相当于shell中的mkdir dirname
    os.mkdir('dirname')
    #删除单极空目录,若目录为不为空则无法删除,报错,相当于shell中的rmdir dirname
    os.rmdir('dirname')
    #列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
    print(os.listdir())
    #输出:['json&pickle.py', 'newname', 'os_test.py', 'output.xml', 're_lesson.py', 'sys_test.py', 'test.xml', 'xml_lesson', 'xml_test.py', '__init__.py', '序列化对象_pickle']
    
    #删除一个文件
    os.remove('dirname/we')
    #重命名文件/目录
    os.rename('dirname','newname')
    #获取文件/目录信息
    print(os.stat("newname/we"))
    #输出:os.stat_result(st_mode=33206, st_ino=10977524091731226, st_dev=1692480672, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1549285018, st_mtime=1549285018, st_ctime=1549285018)
    #操作系统特定的路径分隔符,win下为‘\’,Linux下为‘/’
    print(os.sep)
    
    #当前平台使用的行终止符,win下为‘
    ’,Linux下为'
    '
    print(os.linesep)
    
    #用于分割文件路径的字符串win下为;Linux下为:。比如在path系统环境变量里面分割项与项
    print(os.pathsep)
    
    #输出字符串只是当前使用平台,win下为'nt',Linux为'posix'
    print(os.name)
    
    #终端执行shell命令
    print(os.system("dir"))
    #获取系统环境变量
    print(os.environ)
    #输出:environ({'PATH': 'D:\03Study\venv\Scripts;D:\Python35\Scripts\;D:\Python35\;D:\Python27\;D:\Python27\Scripts;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;D:\Program Files (x86)\Rational\common;D:\Program Files (x86)\Rational\Common', 'PROMPT': '(venv) $P$G', 'NUMBER_OF_PROCESSORS': '2', 'PROCESSOR_ARCHITECTURE': 'AMD64', 'HOMEDRIVE': 'C:', 'USERPROFILE': 'C:\Users\fudonghai', 'COMMONPROGRAMFILES': 'C:\Program Files\Common Files', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 15 Stepping 13, GenuineIntel', 'ONEDRIVE': 'D:\OneDrive', 'PYTHONUNBUFFERED': '1', 'LOCALAPPDATA': 'C:\Users\fudonghai\AppData\Local', 'APPDATA': 'C:\Users\fudonghai\AppData\Roaming', '_OLD_VIRTUAL_PATH': 'D:\Python35\Scripts\;D:\Python35\;D:\Python27\;D:\Python27\Scripts;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;D:\Program Files (x86)\Rational\common;D:\Program Files (x86)\Rational\Common', 'WINDOWS_TRACING_FLAGS': '3', 'PROCESSOR_LEVEL': '6', 'TMP': 'C:\Users\FUDONG~1\AppData\Local\Temp', '_OLD_VIRTUAL_PROMPT': '$P$G', 'PYCHARM_MATPLOTLIB_PORT': '49323', 'SYSTEMDRIVE': 'C:', 'HOMEPATH': '\Users\fudonghai', 'COMPUTERNAME': 'FUDONGHAI-NOTE', 'FP_NO_HOST_CHECK': 'NO', 'PROCESSOR_REVISION': '0f0d', 'SESSIONNAME': 'Console', 'PROGRAMFILES(X86)': 'C:\Program Files (x86)', 'WINDIR': 'C:\Windows', 'USERDOMAIN': 'fudonghai-Note', 'USERNAME': 'fudonghai', 'PYCHARM_HOSTED': '1', 'TEMP': 'C:\Users\FUDONG~1\AppData\Local\Temp', 'PROGRAMDATA': 'C:\ProgramData', 'PYTHONPATH': 'D:\03Study;C:\Program Files\JetBrains\PyCharm 2018.3.3\helpers\pycharm_matplotlib_backend', 'WINDOWS_TRACING_LOGFILE': 'C:\BVTBin\Tests\installpackage\csilogfile.log', 'VIRTUAL_ENV': 'D:\03Study\venv', 'PYTHONIOENCODING': 'UTF-8', 'PROGRAMFILES': 'C:\Program Files', 'ALLUSERSPROFILE': 'C:\ProgramData', 'SYSTEMROOT': 'C:\Windows', '__COMPAT_LAYER': 'DisableUserCallbackException', 'TFS_DIR': 'D:\Program Files (x86)\ThinkVantage Fingerprint Software\', 'LOGONSERVER': '\\FUDONGHAI-NOTE', 'OS': 'Windows_NT', 'PROGRAMW6432': 'C:\Program Files', 'PSMODULEPATH': 'C:\Windows\system32\WindowsPowerShell\v1.0\Modules\;C:\Program Files\Intel\', 'PUBLIC': 'C:\Users\Public', 'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW', 'COMMONPROGRAMW6432': 'C:\Program Files\Common Files', 'COMSPEC': 'C:\Windows\system32\cmd.exe', 'COMMONPROGRAMFILES(X86)': 'C:\Program Files (x86)\Common Files', 'PYCHARM': 'C:\Program Files\JetBrains\PyCharm 2018.3.3\bin;'})
    
    
    #把path分割成目录和文件名二元组返回
    print(os.path.split(r"C:UsersAdministrator脱产三期day22sss.py"))
    #输出:('C:\Users\Administrator\脱产三期\day22', 'sss.py')
    #返回path的目录,其实就是os.path.split的第一个元素
    print(os.path.dirname(r"C:UsersAdministrator脱产三期day22sss.py"))
    #输出:C:UsersAdministrator脱产三期day22
    #返回path最后的文件名,如path以/或者结尾,那么就会返回空值。即os.path.split的第二个元素
    print(os.path.basename(r"C:UsersAdministrator脱产三期day22sss.py"))
    #输出:sss.py
    
    #如果path存在,返回True;如果不存在,返回False
    print(os.path.exists('D:\03Studyday22\day22课件代码\newname'))
    #输出:True
    
    #路径拼接
    a="C:\Users\Administrator"
    b="脱产三期\day22\sss.py"
    print(os.path.join(a,b))
    #输出:C:UsersAdministrator脱产三期day22sss.py
    #和文件时间相关的函数,原来上面讲过stat可以看到三个时间
    print(os.stat("newname/we"))
    #st_atime=1549375382, st_mtime=1549375382, st_ctime=1549285018
    
    #返回path所指向的文件或者目录的最后存取时间
    print(os.path.getatime("newname/we"))
    #输出:1549375382.7303739
    #返回path所指向的文件或者目录的最后修改时间
    print(os.path.getmtime("newname/we"))
    #输出:1549375382.731374
    #返回path所指向的文件或者目录的建立时间
    print(os.path.getctime("newname/we"))
    #输出:1549285018.1002722

    (四)sys模块

    import sys
    #命令行参数List,用于在程序初始化时接受参数,第一个元素是程序本身文件名
    #在终端里面输入:python sys_test.py post D:/03Study/day22/day22课件代码/sys_test.py
    print(sys.argv)
    command=sys.argv[1]
    path=sys.argv[2]
    
    if command=="post":
        print('post')
    
    elif command=="get":
        print('get')
    '''输出:
    ['sys_test.py', 'post', 'D:/03Study/day22/day22课件代码/sys_test.py']
    post
    '''
    
    #获取Python解释程序的版本信息
    print(sys.version)
    
    #获取最大的Int值
    print(sys.maxsize)
    #输出:9223372036854775807
    
    #返回模块的搜素路径,初始化时使用PYTHONPATH环境变量的值
    print(sys.path)
    #输出:['D:\03Study\day22\day22课件代码', 'D:\03Study', 'D:\03Study\venv\Scripts\python35.zip', 'D:\Python35\DLLs', 'D:\Python35\lib', 'D:\Python35', 'D:\03Study\venv', 'D:\03Study\venv\lib\site-packages', 'D:\03Study\venv\lib\site-packages\setuptools-39.1.0-py3.5.egg', 'D:\03Study\venv\lib\site-packages\pip-10.0.1-py3.5.egg', 'C:\Program Files\JetBrains\PyCharm 2018.3.3\helpers\pycharm_matplotlib_backend']
    
    #获取操作系统平台名称
    print(sys.platform)
    #输出:win32
    
    #进度条功能sys.stdout
    import time
    for i in range(100):
        sys.stdout.write("#")
        time.sleep(0.1)
        sys.stdout.flush()
    #输出进度条
    
    #退出程序,正常退出时exit(0)
    sys.exit(1)
    #输出:Process finished with exit code 1

    (五)json & pickle 模块

    import json
    
    #json.dumps会把所有的单引号变成双引号,再把数据变成json字符串
    dic={'name':'alex'}#---->{"name":"alex"}----->'{"name":"alex"}'
    i=8                #---->'8'
    s='hello'          #---->"hello"------>'"hello"'
    l=[11,22]          #---->"[11,22]"
    
    f=open("new_hello","w")
    dic_str=json.dumps(dic)
    f.write(dic_str)   #上面两句等效一句:json.dump(dic,f),注意这个dump没有s
    f.close()
    
    #json.loads把字符串还原成原数据格式
    f_read=open("new_hello","r")
    data=json.loads(f_read.read()) #上面两句等效一句:data=json.load(f),注意这个load没有s
    
    print(data)
    print(type(data))
    #输出:{'name': 'alex'}
    #输出:<class 'dict'>
    
    #注意:loads前不是必须dump,只要符合json字符串的格式,可以直接loads
    import json
    
    with open("Json_test","r") as f:
        data=f.read()
        data=json.loads(data)
        print(data["name"])

    pickle模块比json模块能处理更多的数据类型,但是对人来说可读性不好,所以使用范围并没有json广泛。

    序列化:把对象从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,序列化之后,就可以把序列化之后的内容写入磁盘,或者通过网络传输到别的机器上。

    反序列化:把变量的内容从序列化的对象重新读取到内存里称之为反序列化,即unpickling。

    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()
    
    # --------反序列化
    f = open('序列化对象_pickle', 'rb')
    data = pickle.loads(f.read())  # 等价于data=pickle.load(f)
    print(data['age'])
    #输出:23

    (六)shelve模块

    shelve模块把所有操作都变成字典。 会生成三个文件,后缀为bak,dat,dir

    import shelve
    
    f = shelve.open(r'shelve1')  # 目的:将一个字典放入文本 f={}
    
    f['stu1_info']={'name':'alex','age':'18'}
    f['stu2_info']={'name':'alvin','age':'20'}
    f['school_info']={'website':'oldboyedu.com','city':'beijing'}
    f.close()
    
    # print(f.get('stu1_info')['age'])
    # print(f.get('school_info')['website'])
    '''输出:
    18
    oldboyedu.com
    '''

    (七)xml模块

    xml比json早,在很多领域已经使用,不容易替换。

    import xml.etree.ElementTree as ET
    
    #解析xml文件,得到文档树
    tree = ET.parse("xml_lesson")
    #得到根节点
    root = tree.getroot()
    #打印tag即为xml标签
    print(root.tag)
    #输出:data
    
    for i in root:
        #标签名字
        print(i.tag)
        #属性
        print(i.attrib)
        for j in i:
            #print(j.tag)
            #print(j.attrib)
            #内容
            print(j.text)
    '''输出:
    data
    country
    {'add': 'yes', 'name': 'Liechtenstein'}
    2
    2010
    141100
    None
    None
    country
    {'name': 'Singapore'}
    5
    2013
    59900
    None
    country
    {'name': 'Panama'}
    69
    2013
    13600
    None
    None
    '''
    
    
    
    # 遍历xml文档
    for child in root:
        print(child.tag, child.attrib)
        for i in child:
            print(i.tag, i.text)
    
    只遍历标签为year的节点
    for node in root.iter('year'):
        print(node.tag, node.text)
    '''输出:
    year 2010
    year 2013
    year 2013
    '''
    
    # 修改
    for node in root.iter('year'):
        new_year = int(node.text) + 1
        node.text = str(new_year)
        node.set("updated", "yes")
    #写入文件才会生效
    tree.write("xml_lesson")
    
    # 删除node
    for country in root.findall('country'):
        rank = int(country.find('rank').text)
        if rank > 4:
            root.remove(country)
    
    tree.write('output.xml')
    
    #创建XML文件
    new_xml = ET.Element("namelist") #创建根节点
    #new_xml:处理对象,name:标签,attrib:属性
    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)  # 打印生成的格式
    '''输出:test.xml
    <?xml version='1.0' encoding='utf-8'?>
    <namelist>
        <name enrolled="yes">
            <age checked="no" />
            <sex>33</sex>
        </name>
        <name enrolled="no">
            <age>19</age>
        </name>
    </namelist>
    '''

     (八)logging模块

    1,默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),默认的日志格式为日志级别:Logger名称:用户输出消息。

    一般调试程序使用DEBUG输出大量日志信息,而生产环境使用WARNING往上减少无用信息

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

    2,使用logging.basicConfig()进行初步配置,缺点是只能在屏幕或者文件择其一输出

    logging.basicConfig(
        level=logging.DEBUG,      #设置输出级别
        filename="loger.log",     #输出到文件而不是到标准输出,默认采用追加模式
        filemode="w",             #把模式改为清空重写模式
        format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
            #   时间          源文件名    [line:源文件行号]     级别          信息
        datefmt='%a, %d %b %Y %H:%M:%S', #Wed, 13 Feb 2019 11:17:38
    )
    logging.debug('debug message')
    logging.info('info message')
    logging.warning('warning message')
    logging.error('error message')
    logging.critical('critical message')
    '''输出:
    Wed, 13 Feb 2019 11:17:38 s1.py[line:12] DEBUG debug message
    Wed, 13 Feb 2019 11:17:38 s1.py[line:13] INFO info message
    Wed, 13 Feb 2019 11:17:38 s1.py[line:14] WARNING warning message
    Wed, 13 Feb 2019 11:17:38 s1.py[line:15] ERROR error message
    Wed, 13 Feb 2019 11:17:38 s1.py[line:16] CRITICAL critical message
    '''

     

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

    filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
    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用户输出的消息

    3,logger对象:可以在屏幕和文件同时输出

    例子一:

    Logger是一个树形层级结构,输出信息之前都要获得一个Logger(如果没有显示的获取则自动创建并使用root Logger,如第一个例子所示)。
    logger = logging.getLogger()返回一个默认的Logger也即root Logger,并应用默认的日志级别、Handler和Formatter设置。
    当然也可以通过Logger.setLevel(lel)指定最低的日志级别,可用的日志级别有"DEBUG"、"INFO"、"WARNING"、"ERROR"、"CRITICAL"。
    最后使用Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()输出不同级别的日志,只有日志等级大于或等于设置的日志级别的日志才会被输出。

    一般来说

    def logger():
        #创建logger对象
        logger=logging.getLogger()
    
        #创建向文件里发送内容fh句柄
        fh=logging.FileHandler("test_log")
        #创建向屏幕里发送内容ch句柄
        ch=logging.StreamHandler()
        #添加句柄操作
        logger.addHandler(fh)
        logger.addHandler(ch)
    
        #日志格式设定
        fm=logging.Formatter("%(asctime)s  %(message)s")
        #格式生效
        fh.setFormatter(fm)
        ch.setFormatter(fm)
    
        #日志级别
        logger.setLevel("DEBUG")
    
        #返回对象
        return logger
    
    #可以在任意一个py文件使用这个对象打印
    ret=logger()
    ret.debug("hello debug")
    ret.info("hello info")
    '''输出:文件和屏幕都会出现
    2019-02-13 11:36:44,483  hello debug
    2019-02-13 11:36:44,485  hello info
    '''

    logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。

    例子二:两个logger对象

    logger=logging.getLogger()
    
    
    logger1 = logging.getLogger('mylogger')
    logger1.setLevel(logging.DEBUG)
    
    logger2 = logging.getLogger('mylogger')
    logger2.setLevel(logging.WARNING)
    
    
    fh=logging.FileHandler("test_log-new")
    ch=logging.StreamHandler()
    
    logger.addHandler(ch)
    logger.addHandler(fh)
    
    logger1.addHandler(fh)
    logger1.addHandler(ch)
    
    logger2.addHandler(fh)
    logger2.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')
    '''输出:logger1和logger2每个出现两次
    logger warning message
    logger error message
    logger critical message
    logger1 warning message
    logger1 warning message
    logger1 error message
    logger1 error message
    logger1 critical message
    logger1 critical message
    logger2 warning message
    logger2 warning message
    logger2 error message
    logger2 error message
    logger2 critical message
    logger2 critical message
    '''

    这里有两个问题:

          <1>我们明明通过logger1.setLevel(logging.DEBUG)将logger1的日志级别设置为了DEBUG,为何显示的时候没有显示出DEBUG级别的日志信息,而是从WARNING级别的日志开始显示呢?

           原来logger1和logger2对应的是同一个Logger实例,只要logging.getLogger(name)中名称参数name相同则返回的Logger实例就是同一个,且仅有一个,也即name与Logger实例一一对应。在logger2实例中通过logger2.setLevel(logging.WARNING)设置mylogger的日志级别为logging.WARNING,所以最后logger1的输出遵从了后来设置的日志级别。我的理解就是只存在两个对象默认的root根logger和儿子logger: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) 注释掉,我们再来看效果:

    '''输出:logger1和logger2只出现一次
    logger warning message
    logger error message
    logger critical message
    logger1 warning message
    logger1 error message
    logger1 critical message
    logger2 warning message
    logger2 error message
    logger2 critical message
    '''

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

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

     例子三:filter的使用限制只有满足过滤规则的日志才会输出。

         比如我们定义了filter = logging.Filter('a.b.c'),并将这个Filter添加到了一个Handler上,则使用该Handler的Logger中只有名字带a.b.c前缀的Logger才能输出其日志。

    import logging
    def logger():
        #创建logger对象
        logger=logging.getLogger()
    
        #创建向文件里发送内容fh句柄
        fh=logging.FileHandler("test_log")
        #创建向屏幕里发送内容ch句柄
        ch=logging.StreamHandler()
        #添加句柄操作
        logger.addHandler(fh)
        logger.addHandler(ch)
    
        #日志格式设定
        fm=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        #格式生效
        fh.setFormatter(fm)
        ch.setFormatter(fm)
    
        # 定义一个filter
        filter = logging.Filter('mylogger')
        fh.addFilter(filter)
        ch.addFilter(filter)
    
        #日志级别
        logger.setLevel("DEBUG")
    
        #返回对象
        return logger
    
    #可以在任意一个py文件使用这个对象打印
    ret=logger()
    ret.debug("hello debug")
    ret.info("hello info")
    '''输出:
    如果filter设置为"root"则
    2019-02-13 19:47:49,003 - root - DEBUG - hello debug
    2019-02-13 19:47:49,004 - root - INFO - hello info
    如果filter设置为"mylogger"则没有输出
    '''

     (九)configparser模块:写配置文件

     1,创建一个配置文件

    import configparser
    
    #调用ConfigParser()实例化一个对象,就有了一个空字典
    config = configparser.ConfigParser()     #config={}
    
    #写法1,顶级键"DEFAULT"
    config["DEFAULT"] = {'ServerAliveInterval': '45',
                         'Compression': 'yes',
                         'CompressionLevel': '9'}
    
    #写法2,顶级键'bitbucket.org'
    config['bitbucket.org'] = {}
    config['bitbucket.org']['User'] = 'hg'
    
    #写法3,顶级键'topsecret.server.com'
    config['topsecret.server.com'] = {}
    topsecret = config['topsecret.server.com']
    topsecret['Host Port'] = '50022'  # mutates the parser
    topsecret['ForwardX11'] = 'no'  # same here
    
    #把对象写入文件
    with open('example.ini', 'w') as f:
        config.write(f)
    '''输出:example.ini
    [DEFAULT]
    serveraliveinterval = 45
    compression = yes
    compressionlevel = 9
    
    [bitbucket.org]
    user = hg
    
    [topsecret.server.com]
    host port = 50022
    forwardx11 = no
    '''

    2,查example.ini

    import configparser
    
    #调用ConfigParser()实例化一个对象,就有了一个空字典
    config = configparser.ConfigParser()     #config={}
    
    config.read('example.ini')
    
    #sections()方法输出除了[DEFAULT]以外的顶级键
    print(config.sections())
    #输出:['bitbucket.org', 'topsecret.server.com']
    
    #用来判断'bytebong.com'是否是顶级键
    print('bytebong.com' in config)
    # 输出:False
    
    #输出键的值
    print(config['bitbucket.org']['User'])
    #输出:hg
    print(config['DEFAULT']['Compression'])
    #输出:yes
    print(config['topsecret.server.com']['ForwardX11']) #如果键名错误则程序报错
    #输出:no
    
    #遍历顶级键下的键,把DEFAULT的也会输出
    #所以DEFAULT里面一定放公共信息,这样其它键都能读取
    for key in config['topsecret.server.com']:
        print(key)
    '''输出:
    host port
    forwardx11
    serveraliveinterval
    compression
    compressionlevel
    '''
    
    #options功能是取键
    print(config.options('bitbucket.org'))
    #输出:['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11']
    
    #items取键和值
    print(config.items('bitbucket.org'))
    #输出:[('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes'), ('user', 'hg')]
    
    #get可以连续放入键及其子键
    print(config.get('bitbucket.org','compression'))
    #输出:yes

    3,增删改

    import configparser
    
    #调用ConfigParser()实例化一个对象,就有了一个空字典
    config = configparser.ConfigParser()     #config={}
    
    config.read('example.ini')
    #增加顶级键yuan
    config.add_section('yuan')
    #增加顶级键下面的键值对
    config.set('yuan','k1','11111')
    
    #删除顶级键,连同下面的内容全部删除
    config.remove_section('yuan')
    #删除顶级键下面的键值对
    config.remove_option('bitbucket.org','user')
    
    #写入才能生效
    with open('example.ini', 'w+') as f:
        config.write(f)
    
    #另一种写法,不需要close
    #config.write(open('i.cfg', "w"))

    (十)hashlib模块:hash算法,摘要算法

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

    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("hello"),然后update("alvin")的结果和直接update("helloalvin")一样

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

    import hashlib
    
    obj = hashlib.md5("private".encode('utf-8'))#括号里面的称为“盐”
    obj.update("hello".encode("utf-8"))
    
    print(obj.hexdigest()) #没有加盐:5d41402abc4b2a76b9719d911017c592
                           #加盐后  :fc820a1cfa3dc4e81efb96c61fe9b981

    SHA256算法和MD5算法的用法是一样的,坚固程度好一点

    import hashlib
     
    # ######## 256 ########
     
    hash = hashlib.sha256('898oaFs09f'.encode('utf8'))
    hash.update('alvin'.encode('utf8'))
    print (hash.hexdigest())#e79e68f070cdedcfe63eaf1a2e92c83b4cfb1b5c6bc452d214c1b7e77cdfd1c7


    参考:http://www.cnblogs.com/yuanchenqi/articles/5732581.html

  • 相关阅读:
    poj-1273(最大流)
    SPOJ
    Gym
    (转)博弈 SG函数
    《STL详解》解题报告
    《STL详解》读书笔记
    LightOJ
    hdu1286 找新朋友 欧拉函数模板
    (转)数位dp
    (转)约瑟夫环问题
  • 原文地址:https://www.cnblogs.com/fudonghai/p/10347683.html
Copyright © 2020-2023  润新知