python day 9: xlm模块,configparser模块,shutil模块,subprocess模块,logging模块,迭代器与生成器,反射,configparser


目录

  • python day 9
    • 1. xml模块
      • 1.1 初识xml
      • 1.2 遍历xml文档的指定节点
      • 1.3 通过python手工创建xml文档
      • 1.4 创建节点的两种方式
      • 1.5 总结
    • 2. configparser模块
    • 3. shutil模块
    • 4. subprocess模块
    • 5. logging模块
    • 6. 生成器(generator)与迭代器(iterator)
    • 7. 反射

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='\t')
    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 -> 同意使用 \n
    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)\n")
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))

相关内容

    暂无相关文章

评论关闭