python应用:python3-cookbook笔记,数据编码和处理

    作者:lwtyh更新于: 2020-05-11 15:19:55

    大神带你学编程,欢迎选课

      Python是一种解释型脚本语言,可以应用于以下领域:

      web和Internet开发

      科学计算和统计

      人工智能

      教育

      桌面界面开发

      软件开发

      后端开发

      网络爬虫

    python3-cookbook中每个小节以问题、解决方案和讨论三个部分探讨了Python3在某类问题中的最优解决方式,或者说是探讨Python3本身的数据结构、函数、类等特性在某类问题上如何更好地使用。这本书对于加深Python3的理解和提升Python编程能力的都有显著帮助,特别是对怎么提高Python程序的性能会有很好的帮助,如果有时间的话强烈建议看一下。
    本文为学习笔记,文中的内容只是根据自己的工作需要和平时使用写了书中的部分内容,并且文中的示例代码大多直接贴的原文代码,当然,代码多数都在Python3.6的环境上都验证过了的。不同领域的编程关注点也会有所不同,有兴趣的可以去看全文。

     

    6.1 读写CSV数据

    对于CSV文件,如果不是需要特殊处理,为了尽可能少地出意外,那么总是应该选择CSV模块来读写CSV文件。下面只列几个简单读写CSV文件的示例:

    CSV文件stocks.csv,内容如下:

    复制代码
    Symbol,Price,Date,Time,Change,Volume
    "AA",39.48,"6/11/2007","9:36am",-0.18,181800
    "AIG",71.38,"6/11/2007","9:36am",-0.15,195500
    "AXP",62.58,"6/11/2007","9:36am",-0.46,935000
    "BA",98.31,"6/11/2007","9:36am",+0.12,104800
    "C",53.08,"6/11/2007","9:36am",-0.25,360900
    "CAT",78.29,"6/11/2007","9:36am",-0.23,225400
    复制代码
    复制代码
    import csv

    # 以列表形式读取数据
    with open('stocks.csv') as f:
    f_csv = csv.reader(f)
    headers = next(f_csv)
    # headers和row都是一个列表
    print(headers)
    for row in f_csv:
    print(row)
    复制代码
    复制代码
    import csv

    # 以字典形式读取数据
    with open('stocks.csv') as f:
    f_csv = csv.DictReader(f)
    # row是一个OrderedDict字典类型
    for row in f_csv:
    # 第一条输出为:OrderedDict([('Symbol', 'AA'), ('Price', '39.48'), ('Date', '6/11/2007'), ('Time', '9:36am'), ('Change', '-0.18'), ('Volume', '181800')])
    print(row)
    复制代码
    复制代码
    headers = ['Symbol','Price','Date','Time','Change','Volume']
    rows = [('AA', 39.48, '6/11/2007', '9:36am', -0.18, 181800),
    ('AIG', 71.38, '6/11/2007', '9:36am', -0.15, 195500),
    ('AXP', 62.58, '6/11/2007', '9:36am', -0.46, 935000),
    ]

    # 以列表形式写入数据
    with open('stocks.csv','w') as f:
    f_csv = csv.writer(f)
    # 写入单行数据
    f_csv.writerow(headers)
    # 写入多行数据
    f_csv.writerows(rows)
    复制代码
    复制代码
    headers = ['Symbol', 'Price', 'Date', 'Time', 'Change', 'Volume']
    rows = [{'Symbol':'AA', 'Price':39.48, 'Date':'6/11/2007',
    'Time':'9:36am', 'Change':-0.18, 'Volume':181800},
    {'Symbol':'AIG', 'Price': 71.38, 'Date':'6/11/2007',
    'Time':'9:36am', 'Change':-0.15, 'Volume': 195500},
    {'Symbol':'AXP', 'Price': 62.58, 'Date':'6/11/2007',
    'Time':'9:36am', 'Change':-0.46, 'Volume': 935000},
    ]

    # 以字典形式写入数据
    with open('stocks.csv','w') as f:
    f_csv = csv.DictWriter(f, headers)
    f_csv.writeheader()
    f_csv.writerows(rows)
    复制代码

     

    6.3 解析简单的XML数据

    就如此小节的标题所写,这里只讲了简单的XML解析,如果是较小且不复杂的XML文件,可以使用内置的xml.etree.ElementTree,如果是复杂的XML文档,可以使用三方库lxml,功能更加强大且速度更快。对于以下示例代码,可以直接替换为from lxml.etree import parse。

    复制代码
    from urllib.request import urlopen
    from xml.etree.ElementTree import parse

    # 下载XML文件并解析
    u = urlopen('http://planet.python.org/rss20.xml')
    doc = parse(u)

    # 查找节点channel下的title节点
    e = doc.find('channel/title')
    # 打印节点名称:title
    print(e.tag)
    # 打印节点文本:Planet Python
    print(e.text)
    # 打印节点的某个属性值,因为这个节点没有其他属性,所以获取xxx的结果就是None
    print(e.get('xxx'))

    # 遍历channel下的item节点
    for item in doc.iterfind('channel/item'):
    # 在item节点中查找对应子节点的文本
    title = item.findtext('title')
    date = item.findtext('pubDate')
    link = item.findtext('link')

    print(title)
    print(date)
    print(link)
    print()
    复制代码
    复制代码
    title
    Planet Python
    None
    Codementor: Automating Everything With Python: Reading Time: 3 Mins
    Sat, 22 Feb 2020 09:01:58 +0000
    https://www.codementor.io/maxongzb/automating-everything-with-python-reading-time-3-mins-13v57qt7y6

    Quansight Labs Blog: My Unexpected Dive into Open-Source Python
    Fri, 21 Feb 2020 18:38:07 +0000
    https://labs.quansight.org/blog/2020/02/my-unexpected-dive-into-open-source-python/

    ...
    复制代码

     

    6.4 增量式解析大型XML文件

    如果需要解析的XML文件太大,那么可以考虑使用from xml.etree.ElementTree import iterparse进行增量式解析,需要说明的是,以下示例的两个版本中,将整个XML文档加载到内存中的做法性能要优于增量式解析,但是在内存的占用消耗上却是要远远大于增量式解析了。

    需要解析的XML文件potholes.xml部分内容如下,现在需要对row节点中zip节点的内容进行统计:

    复制代码



    2012-11-18T00:00:00
    Completed
    2012-11-18T00:00:00
    12-01906549
    Pot Hole in Street
    Final Outcome
    CDOT Street Cut ... Outcome
    4714 S TALMAN AVE
    60632
    1159494.68618856
    1873313.83503384
    14
    9
    58
    41.808090232127896
    -87.69053684711305
    longitude="-87.69053684711305" />


    2012-11-18T00:00:00
    Completed
    2012-11-18T00:00:00
    12-01906695
    Pot Hole in Street
    Final Outcome
    CDOT Street Cut ... Outcome
    3510 W NORTH AVE
    60647
    1152732.14127696
    1910409.38979075
    26
    14
    23
    41.91002084292946
    -87.71435952353961
    longitude="-87.71435952353961" />



    复制代码
    全部加载到内存中解析:

    复制代码
    from xml.etree.ElementTree import parse
    from collections import Counter

    potholes_by_zip = Counter()

    doc = parse('potholes.xml')
    for pothole in doc.iterfind('row/row'):
    potholes_by_zip[pothole.findtext('zip')] += 1
    for zipcode, num in potholes_by_zip.most_common():
    print(zipcode, num)
    复制代码
    增量式解析:

    复制代码
    from xml.etree.ElementTree import iterparse
    from collections import Counter


    def parse_and_remove(filename, path):
    path_parts = path.split('/')
    # start事件:某个节点被创建时产生
    # end事件:某个节点被创建完成时产生
    doc = iterparse(filename, ('start', 'end'))
    # 跳过根节点
    next(doc)

    tag_stack = []
    elem_stack = []
    for event, elem in doc:
    if event == 'start':
    tag_stack.append(elem.tag)
    elem_stack.append(elem)
    elif event == 'end':
    if tag_stack == path_parts:
    yield elem
    # 此处是减少内存消耗的核心语句:把yield产生的元素从它的父节点中删除掉
    elem_stack[-2].remove(elem)
    try:
    tag_stack.pop()
    elem_stack.pop()
    except IndexError:
    pass


    potholes_by_zip = Counter()

    data = parse_and_remove('potholes.xml', 'row/row')
    for pothole in data:
    potholes_by_zip[pothole.findtext('zip')] += 1
    for zipcode, num in potholes_by_zip.most_common():
    print(zipcode, num)
    复制代码

     

    6.5 将字典转换为XML

    from xml.etree.ElementTree import Element可以用来创建一个XML,但需要注意的是它只能构造字符串类型的值。

    复制代码
    from xml.etree.ElementTree import Element, tostring


    def dict_to_xml(tag, d):
    """根据一个字典创建一个XML"""
    elem = Element(tag)
    for key, val in d.items():
    child = Element(key)
    # text的值需要是str类型
    child.text = str(val)
    elem.append(child)
    return elem


    s = {'name': 'GOOG', 'shares': 100, 'price': 490.1}
    e = dict_to_xml('stock', s)
    # 给某个节点设置属性值
    e.set('_id', '1234')
    print(e)
    print(tostring(e))
    复制代码

    b'GOOG100490.1'

     

    6.6 解析和修改XML

    示例中修改XML时需要注意的是,所有的修改都是针对父节点来操作的,并且可以将它视为一个列表来处理。

    删除节点:使用父节点的remove()方法。
    添加节点:使用父节点的insert()和append()方法。
    索引和切片:可以对节点使用如element[i]或element[i:j]进行索引和切片操作。
    创建新节点:使用Element类即可。
    预先准备好的的文件pred.xml:

    复制代码


    14791
    Clark & Balmoral

    22
    North Bound

    North Bound


    22

    5 MIN
    Howard
    1378
    22


    15 MIN
    Howard
    1867
    22


    复制代码
    复制代码
    >>> from xml.etree.ElementTree import parse, Element
    >>> doc = parse('pred.xml')
    >>> root = doc.getroot()
    >>> root

    >>> root.remove(root.find('sri'))
    >>> root.remove(root.find('cr'))
    >>> root.getchildren().index(root.find('nm'))
    1
    >>> e = Element('spam')
    >>> e.text = 'This is a test'
    >>> root.insert(2, e)
    >>> doc.write('newpred.xml', xml_declaration=True)
    >>>

    Python是一种跨平台的计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。

课课家教育

未登录