zoukankan      html  css  js  c++  java
  • python day 9: xlm模块,configparser模块,shutil模块,subprocess模块,logging模块,迭代器与生成器,反射

    python day 9

    2019/10/12

    学习资料来自老男孩教育

    1. xml模块

    xml模块是在json没有出来之前,用于不同语言之间通信,交换,处理xml格式数据的一种方式。

    1.1 初识xml

    import requests
    
    from xml.etree import ElementTree as ET
    
    # 使用第三方模块requests发送HTTP请求,或者XML格式内容
    response = requests.get('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=375132083')
    result = response.text  # 字符串类型
    
    # 使用xml包中的ElementTree解析XML格式内容
    # XML接收一个字符串作为参数,将其格式化特殊的对象
    node = ET.XML(result)
    
    #获取内容
    if node.text =='Y':
        print('在线')
    
    
    import requests
    
    response2 = requests.get('http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=K234&UserID=starpinlan')
    result2 = response2.text  #字符串str
    
    from xml.etree import ElementTree as ET
    
    root = ET.XML(result2)  #<class 'xml.etree.ElementTree.Element'>
    # print(type(node2))
    
    for node in root.iter('TrainDetailInfo'):  #iter方法是找到root这个对象中的后代标签名是TrainDetailInfo的所有元素
        print(node.tag,node.attrib)  #输出它的标签名,以及它的属性
        print(node.find('TrainStation').text) #find方法是找到指定名称的第一个子标签
    
    
    

    1.2 遍历xml文档的指定节点

    • 创建一个xml文档,写入如下内容:
    
    s1 = '''
    <data>
        <country name="Liechtenstein">
            <rank updated="yes">2</rank>
            <year id="year">2024</year>
            <gdppc>141100</gdppc>
            <neighbor direction="E" name="Austria" />
            <neighbor direction="W" name="Switzerland" />
        </country>
        <country name="Singapore">
            <rank updated="yes">5</rank>
            <year id="year">2027</year>
            <gdppc>59900</gdppc>
            <neighbor direction="N" name="Malaysia" />
        </country>
        <country name="Panama">
            <rank updated="yes">69</rank>
            <year id="year">2027</year>
            <gdppc>13600</gdppc>
            <neighbor direction="W" name="Costa Rica" />
            <neighbor direction="E" name="Colombia" />
        </country>
    </data>
    '''
    
    with open('xmltest.xml','w+',encoding='utf-8') as f:
        f.write(s1)
        f.flush()
    
    • 读取xml文档,不修改原文件
    
    from xml.etree import ElementTree as ET
    #使用XML格式化字符串
    root = ET.XML(open('xmltest.xml',encoding='utf-8').read())  #此种方式只能读取,不可修改文件
    print(root.tag)
    for node in root.iter('country'):
        print(node.tag,node.attrib,node.find('year').text)
        child_node = node.find('year')  #找到标签名为year的所有节点
        new_year = int(child_node.text)+1 #将year标签的值加1
        child_node.text = str(new_year)
        child_node.set('name','year')  #设置属性name,其值为year
        # del child_node.attrib['name']  #删除name属性键值对
    
    #保存文件需要另创建一个新文件
    tree = ET.ElementTree(root)  #创建一个内容为root的ElementTree对象
    tree.write('newxml.xml',encoding='utf-8')  #一定要通过write写入文件。
    
    • 使用parse方法解析文件,可以修改原文件。
    
    #使用ElementTree的parse方法解析文件
    
    from xml.etree import ElementTree as ET
    
    tree = ET.parse('xmltest.xml')  #parse方法可以打开文件,并解析其内容
    # print(tree,type(tree))  # <class 'xml.etree.ElementTree.ElementTree'>
    root = tree.getroot()   # getroot方法获得最顶层的根节点
    # print(root.tag)  # data
    
    for node in root.iter('year'):
        print(node.tag,node.text)
        new_year = int(node.text) + 1
        node.text = str(new_year)
        node.set('id','year')  # 设置id属性,其值为year,
        print(node.attrib)    #  attrib是字典形式
    
    tree.write('xmltest.xml')  #parse可以直接修改原文件
    
    • 查看一个节点都有哪些方法
    from xml.etree  import ElementTree as ET
    
    tree = ET.parse('xmltest.xml')
    root = tree.getroot()
    print(dir(root))  #查看节点都有哪些方法
    
    '''
    ['__class__', '__copy__', '__deepcopy__', '__delattr__', '__delitem__', '__dir__', '__doc__', 
     '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', 
     '__hash__', '__init__', '__init_subclass__', '__le__', '__len__', '__lt__', '__ne__', '__new__', 
     '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__setstate__', '__sizeof__', 
     '__str__', '__subclasshook__', 'append', 'attrib', 'clear', 'extend', 'find', 'findall', 'findtext', 
     'get', 'getchildren', 'getiterator', 'insert', 'items', 'iter', 'iterfind', 'itertext', 'keys', 'makeelement', 
     'remove', 'set', 'tag', 'tail', 'text']
     #常用tag,attrib,find,text,set,iter,get,append,clear,extend,findall,getchildren,insert,makeelement
     '''
    

    1.3 通过python手工创建xml文档

    from xml.etree import ElementTree as ET
    
    root = ET.Element('namelist')  #通过Element类创建一个名为namelist的xml元素(对象)
    print(root,type(root))  # <Element 'namelist' at 0x00000184AD6C21D8> <class 'xml.etree.ElementTree.Element'>
    name1 = ET.SubElement(root,'name',attrib={'enrolled':'yes'})  # 给root创建子节点,子节点的标签名是name,属性
    name1.text = 'lanxing'  #给内容赋值
    age1 = ET.SubElement(name1,'age',attrib={'checked':'no'})  # 给name1创建子节点
    age1.text = '18'
    sex1 = ET.SubElement(name1,'sex',attrib={'sex':'male'})
    sex1.text = 'male'
    
    name2 = ET.SubElement(root,'name',attrib={'enrolled':'yes'})  # 给root创建子节点,子节点的标签名是name,属性
    name2.text = '蓝星'  #给内容赋值
    age2 = ET.SubElement(name2,'age',attrib={'checked':'no'})  # 给name1创建子节点
    age2.text = '28'  # 必须是字符串才可以序列化
    sex2 = ET.SubElement(name2,'sex',attrib={'sex':'male'})
    sex2.text = 'female'
    
    tree = ET.ElementTree(root)  # 通过ElementTree类生成文档对象
    tree.write('xmltest2.xml',encoding='utf-8',xml_declaration=True)  #将文档对象写入文件,declaration表示声明文件,相当于注释。
    

    1.4 创建节点的两种方式

    from xml.etree import ElementTree as ET
    
    tree = ET.parse('xmltest.xml')
    
    root = tree.getroot()
    # 创建新节点的第一种方式:makeelement
    son = root.makeelement('son',{'sex':'male'})
    print(son,type(son))  # <Element 'son' at 0x000002E1E1B10138> <class 'xml.etree.ElementTree.Element'>
    # 创建新节点的第二种方式:通过Element类进行创建,实际第一种方式也是调用Element类
    son2 = ET.Element('son2',{'sex':'male'})
    son2.text = '男'
    # 将新节点添加到root上
    root.append(son)
    root.append(son2)
    
    tree.write('xmltest.xml',encoding='utf-8',short_empty_elements=False) # short参数是控制是否可简写的。
    

    1.5 总结

    
    XML:
        1,解析:
                str:ElementTree.XML(str)
                文件:ElementTree.parse(file)
        2,Element对象操作:
                tag,text,find,iter,get,set,findall,append,insert,remove。
        3,重新写入文件:
                ElementTree(Element(tag,attrib)).write(filepath,encoding=None)
                必须是ElementTree对象才有写入方法。
        4,创建XML:
                root= Element(tag,attrib)
                ele = root.makeelement(tag,attrib)
                root.append(ele)
                ElementTree.SubElement(root,tag,attrib)
        5,缩进
                from xml.dom import minidom
    
                def prettify(root):
                    '''将节点转换成字符串,并添加缩进'''
                    rough_string = ET.tostring(root,'utf-8')
                    reparsed = minidom.parseString(rough_string)
    
                    return reparsed.topprettyxml(indent='	')
        6,命名空间
        7,非常重要
                一切皆对象,type(obj)查看对象的类。dir(obj)查看对象具有的方法。
    

    2. configparser模块

    configparser模块用来处理配置文件,配置文件是以.ini结尾的文件,长得像下面这样。

    [AutoUpdate] #[xxx]叫做节点
    configfileurl = https://update.pan.baidu.com/autoupdate # 键值对,左边的叫key,右边的叫value
    autoupdatecheckdelay = 30
    configfilekey1 = EDAD921681272C3E37F34020450A6963
    configfilekey2 = 132150629469920000
    lstm_autoupdate = 1570589347
    isautoupdate = 0

    [PackageInstallInfo]
    default = 2
    c6aa1078e4d92ff0573452220ca2d8ae = 4

    import configparser
    
    con = configparser.ConfigParser()  # 创建一个ConfigParser对象
    con.read('config.ini',encoding='utf-8') # 打开文件并读取文件内容,放进内存
    
    # 1,获取所有节点
    # con对象的sections方法,内存中寻找所有的[xxx],一个[xxx]就是一个配置文件的节点
    ret = con.sections() # 获取所有的节点名称,并返回一个列表
    print(ret)  # ['AutoUpdate', 'PackageInstallInfo']
    
    # 2,获取指定节点下所有的键值对,将key与值作为元组,元组作为列表的元素返回。
    ret2 = con.items('AutoUpdate')
    print(ret2)  # [('configfileurl', 'https://update.pan.baidu.com/autoupdate'), ('isautoupdate', '0'), ('autoupdatecheckdelay', '30'), ('configfilekey1', 'EDAD921681272C3E37F34020450A6963'), ('configfilekey2', '132150629469920000'), ('lstm_autoupdate', '1570589347')]
    
    # 3,获取指定节点所有的键
    ret3 = con.options('PackageInstallInfo')
    print(ret3)  # ['default', 'c6aa1078e4d92ff0573452220ca2d8ae']
    
    # 4, 获取指定节点下指定key的值,get(sections,key)
    value1 = con.get('PackageInstallInfo','default')  #默认返回字符串
    print(value1,type(value1))
    # 可以使用getint方法,自动将字符串转换为整数返回
    value2 = con.getint('PackageInstallInfo','default')
    print(value2,type(value2))
    # 可以使用getfloat方法,自动将字符串转换为浮点数返回
    value3 = con.getfloat('PackageInstallInfo','default')
    print(value3,type(value3))
    # 如果值是布尔值,可以使用getboolean方法,自动将字符串转换为布尔值返回
    # value4 = con.getboolean('PackageInstallInfo','default')  # 会报错,因为其值不是布尔值
    
    # 5,检查,添加,删除节点
    
    has_sec = con.has_section('AutoUpdate')  #判断是否有节点,如果有返回True
    print(has_sec)
    
    con.add_section('name')
    
    con.remove_section('name')
    
    # 添加,删除操作必须重新写入文件,否则不能持久化保存。
    
    
    # 6,检查,删除,设置指定节点内的键值对
    
    #检查
    has_opt =con.has_option('AutoUpdate','IsAutoUpdate')
    
    #删除
    con.remove_option('AutoUpdate','IsAutoUpdate')
    
    #设置
    con.set('AutoUpdate','IsAutoUpdate','0')
    
    con.write(open('config.ini','w'))  #write写入得接收一个文件对象
    
    

    3. shutil模块

    shutil模块是高级的文件,文件夹,压缩包处理模块。

    import shutil
    # 将文件内容复制到另一个文件中
    # shutil.copyfileobj(fsrc,fdst[,length]) 将一个文件流对象复制给另一个文件流对象,长度是可选的。
    f1 =open('1.txt','r',encoding='utf-8')
    f2 =open('2.txt','w',encoding='utf-8')
    shutil.copyfileobj(f1,f2)
    f1.close()
    f2.close()
    
    # shutil.copyfile(src,dst),复制文件
    shutil.copyfile('1.txt','3.txt')
    
    # shutil.copymode(src,dst) 仅复制文件的权限,用户,组和内容都不变
    shutil.copymode('1.txt','2.txt')  #dst要存在
    # shutil.copystat(src,dst) 仅拷贝状态的信息,包括:mode bits, atime, mtime, flags
    shutil.copystat('1.txt', '2.txt')
    # shutil.copy(src,dst) #复制文件和权限
    shutil.copy('1.txt','2.txt')
    # shutil.copy2(src,dst) # 复制文件和状态信息
    shutil.copy2('1.txt','2.txt')
    # shutil.ignore_patterns(*patterns)忽略某些格式的文件
    # shutil.copytree(src, dst, symlinks=False, ignore=None) 递归地去复制文件夹
    shutil.copytree('.','../day10',symlinks=True,ignore=shutil.ignore_patterns('*.py'))
    
    # shutil.rmtree(path[, ignore_errors[, onerror]])
    shutil.rmtree('../day10')# 递归的去删除文件
    # shutil.move(src, dst) 递归的去移动文件,它类似mv命令,其实就是重命名。
    shutil.make_archive(base_name, format[,root_dir[,owner[,group[,logger]]]])
    # 创建压缩包并返回文件路径,
    # 其中base_name是指压缩包的文件包,也可以压缩包的路径。
    # format:压缩包种类,zip,tar,bztar,gztar.
    # root_dir: 要压缩的文件夹路径(默认当前目录)
    # owner:用户,默认当前用户
    # group:组,默认当前组
    # logger:用于记录日志,通常是logging.Logger对象
    shutil.make_archive('../test1','tar','.')
    

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

    import zipfile
    
    # 压缩
    z = zipfile.ZipFile('laxi.zip', 'w') #创建一个zip的压缩包对象
    z.write('a.log') # 往压缩包里面加入文件
    z.write('data.data')
    z.close()
    
    # 解压
    z = zipfile.ZipFile('laxi.zip', 'r')
    z.extractall() # 解压所有文件
    print(z.namelist())  # 获得压缩包内的所有文件名
    z.extract('1.txt') # 单独解压指定文件
    z.close()
    
    
    import tarfile
    
    # 压缩
    tar = tarfile.open('your.tar','w')  # 创建tar格式的压缩包
    tar.add('/Users/wupeiqi/PycharmProjects/bbs2.log', arcname='bbs2.log')  #往里面加入压缩文件,可以另外设置名字为bbs2.log
    tar.add('/Users/wupeiqi/PycharmProjects/cmdb.log', arcname='cmdb.log')
    tar.close()
    
    # 解压
    tar = tarfile.open('your.tar','r')
    tar.extractall()  # 可设置解压地址
    print(tar.getmembers())  #返回压缩包内的所有文件名
    tar.extractfile('1.txt')  #单独解压指定文件
    tar.close()
    

    4. subprocess模块

    专门用于python执行系统命令

    import subprocess
    
    ret = subprocess.call('ipconfig')  # call执行系统命令,返回状态码
    print(ret)  # 成功的返回码是0
    
    ret2 = subprocess.check_call('ipconfig')  # 执行命令,返回状态码
    print(ret2)
    ret3 = subprocess.check_output('ipconfig')  # 执行命令,返回字节类型的命令结果
    print(ret3)
    
    '''
    Popen()用于执行复杂的系统命令
    
    参数:
        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()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等 
    '''
    
    subprocess.Popen('mkdir test',shell=True,cwd='.')  # shell是True的情况下,就是将前面的字符串当作命令来输入
    subprocess.Popen(['ipconfig','dir'])  # 执行多个命令
    
    obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
    obj.stdin.write("print(1)
    ")
    obj.stdin.write("print(2)")
    obj.stdin.close()
    
    cmd_out = obj.stdout.read()
    obj.stdout.close()
    cmd_error = obj.stderr.read()
    obj.stderr.close()
    
    print(cmd_out)
    print(cmd_error)
    

    5. logging模块

    线程安全,方便,多人来写时不会写脏数据

    • 只写单文件日志
    import logging
    
    logging.basicConfig(filename='log.log',
                        format='%(asctime)s - %(name)s - %(levelname)s - %(module)s:  %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S %p',
                        level=logging.INFO,)  #level表示大于10的才会记录
    '''
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    '''
    logging.critical('c')
    logging.fatal('f')
    logging.error("sssssss")
    logging.warning('w')
    logging.info('i')
    logging.debug('d')
    logging.log(logging.INFO,'333')  #本质上都是调用的log方法。
    
    '''
    
    • 写多文件日志
    '''
    #logging模块写多文件日志取决于两个方法:
        一个专门用于写日志
        一个用于比较
        def w():
            pass
        def w2():
            pass
        def b():
            if agr>30:
                w()
                w2()
        b()
    定义文件:
        创建文件
        file_1_1 = logging.FileHandler('11_1.log','a')
        创建格式
        fmt = logging.Formatter(fmt="%s(asctime)s - %(name)s - %(levelname)s - %(module)s:  %(message)s")  
        文件应用格式
        file_1_1.setFormatter(fmt) 
        
        file_1_2 = logging.FileHandler('11_2.log','a')
        创建格式
        fmt = logging.Formatter(fmt="%s(asctime)s - %(name)s - %(levelname)s - %(module)s:  %(message)s")  
        文件应用格式
        file_1_1.setFormatter(fmt) 
        
    用于比较的函数:
        logger1 = logging.Logger('s1',level=logging.ERROR)  # 就是b()
        logger1.addHandler(file_1_1)  # 将文件加入进来
        logger1.addHandler(file_1_2)
    
    写日志:
        logger1.critical('1111')
    '''
    

    6. 生成器(generator)与迭代器(iterator)

    能够使用for循环都叫可迭代对象(iterable),可以被next()函数调用并不断返回下一个值的对象叫迭代器(iterator)。

    生成器与迭代器都是可迭代对象,生成器都是迭代器对象,可迭代对象不一定是迭代器。可以通过iter()函数将可迭代对象转换为迭代器。

    • 生成器
      python中,一边循环一边计算的机制叫做生成器,generator。
      创建生成器,有两种方法。第一种通过列表生成式。
      a = (x for x in range(10) if x>=2)像这种通过列表生成式的就是一个生成器,可以通过for循环或者next()内置函数来获得生成器的值,生成器如果迭代完毕,则会报错。
      li = [x for x in rang(10) ] 这个叫做列表推导式。与下面的函数是一个功能。
    li = []
    for i in range(10):
        li.append(i)
    

    通过关键字yield来声明是生成器。

    def f():
        for x in range(10):
            yield x
    # 这时 f()就是一个生成器
    
    print(next(f()))  # 可以next(generator)函数来创建生成器的下一个值
    print(f().__next__())  # 也可以通过__next__()方法
    for i in f():
        print i
     
    

    7. 反射

    '''
    # 反射
        通过字符串的形式,导入模块
        通过字符串的形式,去模块中寻找指定的函数,并执行
    
        反射:根据字符串的形式去某个对象中去操作它的成员
        getattr:
            import random
            寻找函数
            target_func = getattr(random,'randint',None)
            target_func()
            寻找变量
            target_var = getattr(random,'sample',None)
        hasattr:
            hasattr(random,'randint')
        setattr:
            setattr(random,'randxy',lambda x,y:x+y)
        delattr:
            delattr(random,'randxy')
    扩展:
        导入模块:
            import random as rd
            rd = __import__('random.randint',fromlist=True)
    
    
    '''
    import random as rd
    # 本质是调用__import__来导入模块
    rm = __import__('random')
    
    # r1 = rm.randint(1,20)
    # print(r1)
    
    f1 = getattr(rm,'randint') # random.randint本质上是调用了getattr方法,这种就叫做反射
    print(f1(1,20))
    
    
  • 相关阅读:
    Windows下使用CMake编译SuiteSparse成VS工程
    【设计模式
    【设计模式
    vue过滤和复杂过滤
    el-tooltip 自定义样式
    el-table加表单验证
    使用Go env命令设置Go的环境
    面试官:GET 和 POST 两种基本请求方法有什么区别?
    解决 Vue 重复点击相同路由报错的问题
    利用promise和装饰器封装一个缓存api请求的装饰器工具
  • 原文地址:https://www.cnblogs.com/lanxing0422/p/pythonday9.html
Copyright © 2011-2022 走看看