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

 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节点的内容进行统计:

<response>
<row>
<row ...>
<creation_date>2012-11-18T00:00:00</creation_date>
<status>Completed</status>
<completion_date>2012-11-18T00:00:00</completion_date>
<service_request_number>12-01906549</service_request_number>
<type_of_service_request>Pot Hole in Street</type_of_service_request>
<current_activity>Final Outcome</current_activity>
<most_recent_action>CDOT Street Cut ... Outcome</most_recent_action>
<street_address>4714 S TALMAN AVE</street_address>
<zip>60632</zip>
<x_coordinate>1159494.68618856</x_coordinate>
<y_coordinate>1873313.83503384</y_coordinate>
<ward>14</ward>
<police_district>9</police_district>
<community_area>58</community_area>
<latitude>41.808090232127896</latitude>
<longitude>-87.69053684711305</longitude>
<location latitude="41.808090232127896"
longitude="-87.69053684711305" />
</row>
<row ...>
<creation_date>2012-11-18T00:00:00</creation_date>
<status>Completed</status>
<completion_date>2012-11-18T00:00:00</completion_date>
<service_request_number>12-01906695</service_request_number>
<type_of_service_request>Pot Hole in Street</type_of_service_request>
<current_activity>Final Outcome</current_activity>
<most_recent_action>CDOT Street Cut ... Outcome</most_recent_action>
<street_address>3510 W NORTH AVE</street_address>
<zip>60647</zip>
<x_coordinate>1152732.14127696</x_coordinate>
<y_coordinate>1910409.38979075</y_coordinate>
<ward>26</ward>
<police_district>14</police_district>
<community_area>23</community_area>
<latitude>41.91002084292946</latitude>
<longitude>-87.71435952353961</longitude>
<location latitude="41.91002084292946"
longitude="-87.71435952353961" />
</row>
</row>
</response>

全部加载到内存中解析:

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', '')
print(e)
print(tostring(e))
<Element 'stock' at 0x000001761DB01B88>
b'<stock _id="1234"><name>GOOG</name><shares>100</shares><price>490.1</price></stock>'

 

6.6 解析和修改XML

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

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

预先准备好的的文件pred.xml:

<?xml version="1.0"?>
<stop>
<id>14791</id>
<nm>Clark &amp; Balmoral</nm>
<sri>
<rt>22</rt>
<d>North Bound</d>
<dd>North Bound</dd>
</sri>
<cr>22</cr>
<pre>
<pt>5 MIN</pt>
<fd>Howard</fd>
<v>1378</v>
<rn>22</rn>
</pre>
<pre>
<pt>15 MIN</pt>
<fd>Howard</fd>
<v>1867</v>
<rn>22</rn>
</pre>
</stop>
>>> from xml.etree.ElementTree import parse, Element
>>> doc = parse('pred.xml')
>>> root = doc.getroot()
>>> root
<Element 'stop' at 0x100770cb0>
>>> 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)
>>>

python3-cookbook笔记:第六章 数据编码和处理的更多相关文章

  1. Android群英传笔记——第六章:Android绘图机制与处理技巧

    Android群英传笔记--第六章:Android绘图机制与处理技巧 一直在情调,时间都是可以自己调节的,不然世界上哪有这么多牛X的人 今天就开始读第六章了,算日子也刚好一个月了,一个月就读一半,这效 ...

  2. 深入理解 C 指针阅读笔记 -- 第六章

    Chapter6.h #ifndef __CHAPTER_6_ #define __CHAPTER_6_ /*<深入理解C指针>学习笔记 -- 第六章*/ typedef struct _ ...

  3. JVM学习笔记-第六章-类文件结构

    JVM学习笔记-第六章-类文件结构 6.3 Class类文件的结构 本章中,笔者只是通俗地将任意一个有效的类或接口锁应当满足的格式称为"Class文件格式",实际上它完全不需要以磁 ...

  4. [CSAPP笔记][第六章存储器层次结构]

    第六章 存储器层次结构 在简单模型中,存储器系统是一个线性的字节数组,CPU能够在一个常数访问每个存储器位置. 虽然是一个行之有效的模型,但没有反应现代系统实际工作方式. 实际上,存储器系统(memo ...

  5. 《Microsoft Sql server 2008 Internals》读书笔记--第六章Indexes:Internals and Management(1)

    <Microsoft Sql server 2008 Internals>索引文件夹: <Microsoft Sql server 2008 Internals>读书笔记--文 ...

  6. C Primer Plus 学习笔记 -- 前六章

    记录自己学习C Primer Plus的学习笔记 第一章 C语言高效在于C语言通常是汇编语言才具有的微调控能力设计的一系列内部指令 C不是面向对象编程 编译器把源代码转化成中间代码,链接器把中间代码和 ...

  7. C primer plus 读书笔记第六章和第七章

    这两章的标题是C控制语句:循环以及C控制语句:分支和跳转.之所以一起讲,是因为这两章内容都是讲控制语句. 第六章的第一段示例代码 /* summing.c --对用户输入的整数求和 */ #inclu ...

  8. 韩松毕业论文笔记-第六章-EFFICIENT METHODS AND HARDWARE FOR DEEP LEARNING

    难得跟了一次热点,从看到论文到现在已经过了快三周了,又安排了其他方向,觉得再不写又像之前读过的N多篇一样被遗忘在角落,还是先写吧,虽然有些地方还没琢磨透,但是paper总是这样吧,毕竟没有亲手实现一下 ...

  9. Linux学习笔记(第六章)

    第六章-档案权限与目录配置#chgrp:改变档案的所属群组#chown:改变档案的拥有者#chmod:改变档案的权限及属性 chown用法 chmod用法: r:4 w:2 x:1对于文档: 对于目录 ...

  10. o'Reill的SVG精髓(第二版)学习笔记——第六章

    第六章:坐标系统变换 想要旋转.缩放或者移动图片到新的位置.可以给对应的SVG元素添加transform属性. 6.1 translate变换 可以为<use>元素使用x和y属性,以在特性 ...

随机推荐

  1. 这个菜鸟花几个小时写的 DEMO 被码云推荐上首页 ?

    写在最前     没有接触过 AntV 的诸位看客可通过这篇不成文的文章稍作了解.最近 病毒猖獗,遂抽空做了一个相关小 DEMO.数据可视化方面的使用的是 AntV F2,前端框架使用 Vue 快速成 ...

  2. Spring AOP源码分析--代理方式的选择

    能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! 年前写了一个面试突击系列的文章,目前只有redis相关的.在这个系列里,我整理了一些面试题与大家 ...

  3. python中os模块的一些小总结

    (一)os模块的应用小总结 os.name: 获取当前系统平台,Windows下返回'nt',Linux下返回'posix'.   os.linesep: 获取当前平台使用的行终止符.Windows下 ...

  4. 批量解析域名为IP地址的python脚本

    脚本如下: #!/usr/bin/env python #coding:utf- import os,sys from socket import gethostbyname DOMAIN= &quo ...

  5. 如何在OpenStack中对云主机类型进行重新配置

    目标:很多用户在OpenStack启动一个虚拟机,选择了一个云主机配置类型,例如2CPU 4GB内存,使用了一段时间,感觉这个配置并不能满足需求,所以希望能够提高配置,那么OpeNStack的管理界面 ...

  6. void * 和 void 在函数返回值中的区别

    一个很容易糊涂的问题. 在函数的返回值中, void 是没有任何返回值, 而 void * 是返回任意类型的值的指针. 还是看代码吧: #include <stdlib.h> #inclu ...

  7. lwip 2.0.2 snmp mib ipv6

    1.3.6.1.2.1 - SNMP MIB-2 Submitted by Harald.T.Alvestrand at uninett.no from host aun.uninett.no (12 ...

  8. lwip的netif状态管理

    netif的状态变化可以设置回调函数, 主要有三项变化, 1 netif up or down,address change,address state change(IPv6) 2 link up ...

  9. docker-compose 常用命令整理:

    docker-compose -f my.yaml version 查看docker-compose版本信息 docker-compose -f lnmp.yaml images 列出镜像 docke ...

  10. 杭电-------2047阿牛的eof牛肉串(C语言写)

    /* 主要看最后一个是否为O,若为O,则倒数第二个不能为O,则为a[n-2]*1*2; 若不为O,则最后一个有两个选择则为a[n-1]*2 */ #include<stdio.h> ] = ...