《Python Cookbook(第3版)中文版》——6.2 读写JSON数据

简介:

本节书摘来自异步社区《Python Cookbook(第3版)中文版》一书中的第6章,第6.2节,作者[美]David Beazley , Brian K.Jones,陈舸 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。

6.2 读写JSON数据

6.2.1 问题

我们想读写以JSON(JavaScript Object Notation)格式编码的数据。

6.2.2 解决方案

json模块中提供了一种简单的方法来编码和解码JSON格式的数据。这两个主要的函数就是json.dumps()以及json.loads()。这两个函数在命名上借鉴了其他序列化处理库的接口,比如pickle。下面的示例展示了如何将Python数据结构转换为JSON:

import json
data = {
    'name' : 'ACME',
    'shares' : 100,
    'price' : 542.23
}
json_str = json.dumps(data)

而接下来的示例告诉我们如何把JSON编码的字符串再转换回Python数据结构:

data = json.loads(json_str)

如果要同文件而不是字符串打交道的话,可以选择使用json.dump()以及json.load()来编码和解码JSON数据。示例如下:

# Writing JSON data
with open('data.json', 'w') as f:
     json.dump(data, f)
# Reading data back
with open('data.json', 'r') as f:
     data = json.load(f)

6.2.3 讨论

JSON编码支持的基本类型有None、bool、int、float和str,当然还有包含了这些基本类型的列表、元组以及字典。对于字典,JSON会假设键(key)是字符串(字典中的任何非字符串键都会在编码时转换为字符串)。要符合JSON规范,应该只对Python列表和字典进行编码。此外,在Web应用中,把最顶层对象定义为字典是一种标准做法。

JSON编码的格式几乎与Python语法一致,只有几个小地方稍有不同。比如,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中解码得到的数据,那么仅仅将其打印出来就想确定数据的结构通常是比较困难的——尤其是如果数据中包含了深层次的嵌套结构或者有许多字段时。为了帮助解决这个问题,考虑使用pprint模块中的pprint()函数。这么做会把键按照字母顺序排列,并且将字典以更加合理的方式进行输出。下面的示例展示了应该如何对Twitter上的搜索结果以漂亮的格式进行输出:

>>> from urllib.request import urlopen
>>> import json
>>> u = urlopen('http://search.twitter.com/search.json?q=python&rpp=5')
>>> resp = json.loads(u.read().decode('utf-8'))
>>> from pprint import pprint
>>> pprint(resp)
{'completed_in': 0.074,
 'max_id': 264043230692245504,
 'max_id_str': '264043230692245504',
 'next_page': '?page=2&max_id=264043230692245504&q=python&rpp=5',
 'page': 1,
 'query': 'python',
 'refresh_url': '?since_id=264043230692245504&q=python',
 'results': [{'created_at': 'Thu, 01 Nov 2012 16:36:26 +0000',
              'from_user': ...
             },
             {'created_at': 'Thu, 01 Nov 2012 16:36:14 +0000',
              'from_user': ...
            },
            {'created_at': 'Thu, 01 Nov 2012 16:36:13 +0000',
             'from_user': ...
            },
            {'created_at': 'Thu, 01 Nov 2012 16:36:07 +0000',
             'from_user': ...
            }
            {'created_at': 'Thu, 01 Nov 2012 16:36:04 +0000',
             'from_user': ...
            }],
 'results_per_page': 5,
 'since_id': 0,
 'since_id_str': '0'}
>>>

一般来说,JSON解码时会从所提供的数据中创建出字典或者列表。如果想创建其他类型的对象,可以为json.loads()方法提供object_pairs_hook或者object_hook参数。例如,下面的示例展示了我们应该如何将JSON数据解码为OrderedDict(有序字典),这样可以保持数据的顺序不变:

>>> s = '{"name": "ACME", "shares": 50, "price": 490.1}'
>>> from collections import OrderedDict
>>> data = json.loads(s, object_pairs_hook=OrderedDict)
>>> data
OrderedDict([('name', 'ACME'), ('shares', 50), ('price', 490.1)])
>>>

而下面的代码将JSON字典转变为Python对象:

>>> class JSONObject:
...     def __init__(self, d):
...             self.__dict__ = d
...
>>>
>>> data = json.loads(s, object_hook=JSONObject)
>>> data.name
'ACME'
>>> data.shares
50
>>> data.price
490.1
>>>

在上一个示例中,通过解码JSON数据而创建的字典作为单独的参数传递给了__init__()。之后就可以自由地根据需要来使用它了,比如直接将它当做对象的字典实例来用。

有几个选项对于编码JSON来说是很有用的。如果想让输出格式变得漂亮一些,可以在json.dumps()函数中使用indent参数。这会使得数据能够像pprint()函数那样以漂亮的格式打印出来。示例如下:

>>> print(json.dumps(data))
{"price": 542.23, "name": "ACME", "shares": 100}
>>> print(json.dumps(data, indent=4))
{
    "price": 542.23,
    "name": "ACME",
    "shares": 100
}
>>>

如果想在输出中对键进行排序处理,可以使用sort_keys参数:

>>> print(json.dumps(data, sort_keys=True))
{"name": "ACME", "price": 542.23, "shares": 100}
>>>

类实例一般是无法序列化为JSON的。比如说:

>>> class Point:
...     def __init__(self, x, y):
...             self.x = x
...             self.y = y
...
>>> p = Point(2, 3)
>>> json.dumps(p)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.3/json/__init__.py", line 226, in dumps
    return _default_encoder.encode(obj)
  File "/usr/local/lib/python3.3/json/encoder.py", line 187, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/lib/python3.3/json/encoder.py", line 245, in iterencode
    return _iterencode(o, 0)
  File "/usr/local/lib/python3.3/json/encoder.py", line 169, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <__main__.Point object at 0x1006f2650> is not JSON serializable
>>>

如果想序列化类实例,可以提供一个函数将类实例作为输入并返回一个可以被序列化处理的字典。示例如下:

def serialize_instance(obj):
    d = { '__classname__' : type(obj).__name__ }
    d.update(vars(obj))
    return d

如果想取回一个实例,可以编写这样的代码来处理:

# Dictionary mapping names to known classes
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

最后给出如何使用这些函数的示例:

>>> p = Point(2,3)
>>> s = json.dumps(p, default=serialize_instance)
>>> s
'{"__classname__": "Point", "y": 3, "x": 2}'
>>> a = json.loads(s, object_hook=unserialize_object)
>>> a
<__main__.Point object at 0x1017577d0>
>>> a.x
2
>>> a.y
3
>>>
相关文章
|
2天前
|
机器学习/深度学习 Python 数据处理
Python中利用长短期记忆模型LSTM进行时间序列预测分析 - 预测电力负荷数据
Python中利用长短期记忆模型LSTM进行时间序列预测分析 - 预测电力负荷数据
17 0
Python中利用长短期记忆模型LSTM进行时间序列预测分析 - 预测电力负荷数据
|
2天前
|
存储 机器学习/深度学习 数据可视化
Python面板时间序列数据预测:格兰杰因果关系检验Granger causality test药品销售实例与可视化
Python面板时间序列数据预测:格兰杰因果关系检验Granger causality test药品销售实例与可视化
39 6
|
2天前
|
机器学习/深度学习 数据采集 供应链
从数据到决策:scikit-learn在业务分析中的应用
【4月更文挑战第17天】本文探讨了scikit-learn在业务分析中的应用,包括数据预处理、分类、回归和聚类模型的构建,以及模型评估与优化。通过使用scikit-learn,企业能有效处理数据、预测趋势、客户细分并制定决策,从而提升经营效率和市场策略。随着机器学习的发展,scikit-learn在业务分析领域的潜力将持续释放,创造更多价值。
|
2天前
|
算法 数据可视化 Python
Python中LARS和Lasso回归之最小角算法Lars分析波士顿住房数据实例
Python中LARS和Lasso回归之最小角算法Lars分析波士顿住房数据实例
11 0
|
2天前
|
BI 开发者 数据格式
Python代码填充数据到word模板中
【4月更文挑战第16天】
|
3天前
|
数据可视化 算法 API
Python数据可视化-seaborn Iris鸢尾花数据
Python数据可视化-seaborn Iris鸢尾花数据
11 0
|
3天前
|
程序员 索引 Python
06-python数据容器-set(集合)入门基础操作
06-python数据容器-set(集合)入门基础操作
|
1月前
|
JSON JavaScript 前端开发
如何在Python中解析JSON响应?
【2月更文挑战第26天】【2月更文挑战第92篇】如何在Python中解析JSON响应?
|
1月前
|
存储 JSON JavaScript
Python中读写(解析)JSON文件的深入探究
Python中读写(解析)JSON文件的深入探究
27 0
|
1月前
|
存储 JSON JavaScript
Python如何解析json对象?
Python如何解析json对象?
23 1

热门文章

最新文章