7.Python中不同文件的读取
- Csv的读取
对于CSV的读取,python直接提供了csv库,就好比我们有一个如下的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 |
对于这样一个文件,只需要在外面使用csv包上一层即可
with open(‘stocks.csv’) as f:
f_csv = csv.reader(f) headers = next(f_csv) for row in f_csv: |
之后对于row,就是一个列表,我们通过row[0] 来访问Symbol,row[4]访问Change
如果想要直接访问,可以考虑使用命名元组
from collections import namedtuple
with open(‘stock.csv’) as f: f_csv = csv.reader(f) headings = next(f_csv) Row = namedtuple(‘Row’, headings) for r in f_csv: row = Row(*r) |
这时候就可以使用row.Symbol或者row.Change来访问了
Csv模块中还支持将文件读取位字典格式
with open(‘stocks.csv’) as f:
f_csv = csv.DictReader(f) for row in f_csv: # process row |
会形成一个列表,其中每一个item都是一个字典,对应的就是row
当然csv模块也提供了写入功能,不过要先创建一个writer对象
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) |
上面我们先写入了一行,header,然后利用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) |
需要注意的是csv产生的数据都是字符串类型的,不会产生其他类型的转换,比如
这就需要我们自己去转换,比如如下的代码
col_types = [str, float, str, str, float, int]
with open(‘stocks.csv’) as f: f_csv = csv.reader(f) headers = next(f_csv) for row in f_csv: # Apply conversions to the row items row = tuple(convert(value) for convert, value in zip(col_types, row)) |
如果希望,有更进阶的使用方式,则可以看Pandas包
其中提供了pandas.read_csv() 可以将csv文件中的数据加载到一个DataFrame中
- Json文件的读写
Json模块提供了一种很简单的方式来使用Json,只需要json模块下的dumps和loads就可以了
我们简单看一个示例
import json
data = { ‘name’ : ‘ACME’, ‘shares’ : 100, ‘price’ : 542.23 } json_str = json.dumps(data) |
同样loads就可以将其家在为数据结构
对于json和python的数据类型,是有一些差异的,python的json模块也会进行映射
比如True – true,False – false None映射null
>>> json.dumps(False)
‘false’ >>> d = {‘a’: True, … ‘b’: ‘Hello’, … ‘c’: None} >>> json.dumps(d) ‘{“b”: “Hello”, “c”: null, “a”: true}’ >>> |
JSON模块一般会根据数据创建lists或者dict,但是如果我们想要创建其他类型的对象,则应该在object_paris_hook或object_hook中设置
如果希望自定义的对象支持反序列化,则可以实现一个init函数,其中接收一个dict对象
>>> class JSONObject:
… def __init__(self, d): … self.__dict__ = d … >>> >>> data = json.loads(s, object_hook=JSONObject) |
如果希望支持序列化,则应该提供一个函数,输入一个实例,返回一个字典
classes = {
‘Point’ : Point } def unserialize_object(d): clsname = d.pop(‘__classname__’, None) if clsname: cls = classes[clsname] obj = cls.__new__(cls) # Make instance without calling __init__ for key, value in d.items(): setattr(obj, key, value) return obj else: return d |
当然,如果希望打印json,则可以考虑使用pprint这个函数进行打印输出
会考虑更加美观的打印方式
- 解析XML
如果希望解析XMl
使用xml.etree.ElementTree就可以提取,比如如下代码
# 数据例如
<?xml version=”1.0″?> <rss version=”2.0″ xmlns:dc=”http://purl.org/dc/elements/1.1/”> <channel> <title>Planet Python</title> <link>http://planet.python.org/</link> <language>en</language> <description>Planet Python – http://planet.python.org/</description> <item> <title>Steve Holden: Python for Data Analysis</title> <guid>http://holdenweb.blogspot.com/…-data-analysis.html</guid> <link>http://holdenweb.blogspot.com/…-data-analysis.html</link> <description>…</description> <pubDate>Mon, 19 Nov 2012 02:13:51 +0000</pubDate> </item> <item> <title>Vasudev Ram: The Python Data model (for v2 and v3)</title> <guid>http://jugad2.blogspot.com/…-data-model.html</guid> <link>http://jugad2.blogspot.com/…-data-model.html</link> <description>…</description> <pubDate>Sun, 18 Nov 2012 22:06:47 +0000</pubDate> </item> <item> <title>Python Diary: Been playing around with Object Databases</title> <guid>http://www.pythondiary.com/…-object-databases.html</guid> <link>http://www.pythondiary.com/…-object-databases.html</link> <description>…</description> <pubDate>Sun, 18 Nov 2012 20:40:29 +0000</pubDate> </item> … </channel> </rss> from urllib.request import urlopen from xml.etree.ElementTree import parse # Download the RSS feed and parse it u = urlopen(‘http://planet.python.org/rss20.xml’) doc = parse(u) # Extract and output tags of interest for item in doc.iterfind(‘channel/item’): title = item.findtext(‘title’) date = item.findtext(‘pubDate’) link = item.findtext(‘link’) print(title) print(date) print(link) print() |
上面我们首先使用parse解析为一个XML文件
然后从其中的获取到’channel/item’下的数据
并且依次获取到了’title’,’pubDate’,’link’的数据
类似的查找函数有find iterfind findtext查找
而item元素中,tag属性包含了标签的名字,text包含了内部文本,get() 获取了属性值
而类似xml的还有lxml,使用方式一样
除了parse可以获取到数据之外,还有着iterparse可以获取到数据,以一种迭代的,内存占用更少的方式
比如下面代码
def parse_and_remove(filename, path):
path_parts = path.split(‘/’) doc = iterparse(filename, (‘start’, ‘end’)) # Skip the root element 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 elem_stack[-2].remove(elem) try: tag_stack.pop() elem_stack.pop() except IndexError: pass |
我们在代码中不断的遍历,并且在其中指定了事件列表,包含starth额end
Start对应某一个元素刚遇见,end则表示已经创建完成元素
我们就当遇到end的时候,返回着这个元素,然后将其从数组中移除
elem_stack[-2].remove(elem)
这时候因为没有引用了,就会被自动移除,从而减少内存占用
那么我们是否可以插入XML呢,或者说创建XML文档?
当然可以,利用Element对象即可
from xml.etree.ElementTree import Element
def dict_to_xml(tag, d): ”’ Turn a simple dict of key/value pairs into XML ”’ elem = Element(tag) for key, val in d.items(): child = Element(key) child.text = str(val) elem.append(child) return elem |
我们直接创建了一个Element,然后在下面添加了数据
那么我们有了Element之后,如何进行XML的插入修改呢?
只需要考虑使用其中的insert函数即可
比如
>>> e = Element(‘spam’)
>>> e.text = ‘This is a test’
>>> root.getchildren().index(root.find(‘nm’))
1
>>> root = doc.getroot()
>>> root.insert(root.getchildren().index(root.find(‘nm’))+ 1, e)
移除则是
>>> root.remove(root.find(‘sri’))
>>> root.remove(root.find(‘cr’))
最后写入直接是利用parse后的对象进行write
>>> doc.write(‘newpred.xml’, xml_declaration=True)
- 数据库的交互
如果想要和数据库进行交互的话,python中都提供了不同的库进行使用
比如我们希望连接sqllite,则可以使用python标准库中的sqlite3,如果是使用不同的数据库,则还需要安装不同的第三方库
首先是连接到数据库,通常要执行connect() 函数,提供一些数据库名,主机,用户名等信息,不过sqlite比较简单
>>> import sqlite3
>>> db = sqlite3.connect(‘database.db’)
然后我们希望执行语句的话,直接使用execute即可
>>> c = db.cursor()
>>> c.execute(‘create table portfolio (symbol text, shares integer, price real)’)
<sqlite3.Cursor object at 0x10067a730>
>>> db.commit()
如果希望插入多条数据的话,则可以考虑如下语句
>>> c.executemany(‘insert into portfolio values (?,?,?)’, stocks)
<sqlite3.Cursor object at 0x10067a730>
>>> db.commit()
其中的stocks是一个序列,序列中包含的每一个元素都是一个元组,正好三个
如果是希望获取到查询结果,sqlite中直接,可以
>>> for row in db.execute(‘select * from portfolio’):
print(row)
并且也支持使用 ? 作为占位符
不过需要注意的是python中的数据类型和数据库中的数据类型的映射
不同的数据库的映射规则是不一样的
如果希望能够更高层次的抽象不同数据库的差异,可以考虑使用ORM框架,比如SQLAlchemy这样的库,可以以一个类的方式映射一个数据库表
- 编解码十六进制数
如果希望将十六进制的字符串解码为一个字节字符串或者将一个字节字符串编码为一个十六进制字符串
如果是简单的编解码的话,使用binascii即可
>>> s = b’hello’
>>> import binascii
>>> h = binascii.b2a_hex(s)
>>> h
b’68656c6c6f’
>>> binascii.a2b_hex(h)
b’hello’
或者是使用base64模块也可以做到,其中包含了b16encode,b16decode可以进行解码和编码
需要注意的是b16decode和a2b_hex都可以接受字节以及unicode字符串,但是对于unicode 字符串,必须要求只包含ASCII编码的十六进制数
同理,Base64其中的b64encode和b64decode更加符合之前使用base64的习惯
>>> s = b’hello’
>>> import base64
>>> a = base64.b64encode(s)
>>> a
b’aGVsbG8=’
>>> base64.b64decode(a)
b’hello’
别忘了将字节转换为字符串需要进行decode
- 简单介绍下pandas
我们这里简单介绍下Pandas库,支持分析大量数据
>>> import pandas
>>> # Read a CSV file, skipping last line # 读取 >>> rats = pandas.read_csv(‘rats.csv’, skip_footer=1) >>> rats <class ‘pandas.core.frame.DataFrame’> Int64Index: 74055 entries, 0 to 74054 Data columns: Creation Date 74055 non-null values Status 74055 non-null values Completion Date 72154 non-null values Service Request Number 74055 non-null values Type of Service Request 74055 non-null values Number of Premises Baited 65804 non-null values Number of Premises with Garbage 65600 non-null values Number of Premises with Rats 65752 non-null values Current Activity 66041 non-null values Most Recent Action 66023 non-null values Street Address 74055 non-null values ZIP Code 73584 non-null values X Coordinate 74043 non-null values Y Coordinate 74043 non-null values Ward 74044 non-null values Police District 74044 non-null values Community Area 74044 non-null values Latitude 74043 non-null values Longitude 74043 non-null values Location 74043 non-null values dtypes: float64(11), object(9) >>> # Investigate range of values for a certain field >>> rats[‘Current Activity’].unique() array([nan, Dispatch Crew, Request Sanitation Inspector], dtype=object) >>> # Filter the data # 直接过滤 >>> crew_dispatched = rats[rats[‘Current Activity’] == ‘Dispatch Crew’] # 获取数量 >>> len(crew_dispatched) 65676 >>> # 聚合统计zip code >>> # Find 10 most rat-infested ZIP codes in Chicago >>> crew_dispatched[‘ZIP Code’].value_counts()[:10] 60647 3837 60618 3530 60614 3284 60629 3251 60636 2801 60657 2465 60641 2238 60609 2206 60651 2152 60632 2071 >>> >>> # Group by completion date # 根据日期进行聚合 >>> dates = crew_dispatched.groupby(‘Completion Date’) <pandas.core.groupby.DataFrameGroupBy object at 0x10d0a2a10> >>> len(dates) 472 >>> >>> # Determine counts on each day >>> date_counts = dates.size() >>> date_counts[0:10] Completion Date 01/03/2011 4 01/03/2012 125 01/04/2011 54 01/04/2012 38 01/05/2011 78 01/05/2012 100 01/06/2011 100 01/06/2012 58 01/07/2011 1 01/09/2012 12 >>> # 排序后获取前十个 >>> # Sort the counts >>> date_counts.sort() >>> date_counts[-10:] Completion Date 10/12/2012 313 10/21/2011 314 09/20/2011 316 10/26/2011 319 02/22/2011 325 10/26/2012 333 03/17/2011 336 10/13/2011 378 10/14/2011 391 10/07/2011 457 >>> |