《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
>>>
相关文章
|
11天前
|
SQL JSON 数据格式
SPL 处理多层 JSON 数据比 DuckDB 方便多了
esProc SPL 处理多层 JSON 数据比 DuckDB 更便捷,尤其在保留 JSON 层次与复杂计算时优势明显。DuckDB 虽能通过 `read_json_auto()` 将 JSON 解析为表格结构,但面对深层次或复杂运算时,SQL 需频繁使用 UNNEST、子查询等结构,逻辑易变得繁琐。而 SPL 以集合运算方式直接处理子表,代码更简洁直观,无需复杂关联或 Lambda 语法,同时保持 JSON 原始结构。esProc SPL 开源免费,适合复杂 JSON 场景,欢迎至乾学院探索!
|
8天前
|
JSON 算法 API
1688商品详情API实战:Python调用全流程与数据解析技巧
本文介绍了1688电商平台的商品详情API接口,助力电商从业者高效获取商品信息。接口可返回商品基础属性、价格体系、库存状态、图片描述及商家详情等多维度数据,支持全球化语言设置。通过Python示例代码展示了如何调用该接口,帮助用户快速上手,适用于选品分析、市场研究等场景。
|
29天前
|
数据采集 NoSQL 关系型数据库
Python爬虫去重策略:增量爬取与历史数据比对
Python爬虫去重策略:增量爬取与历史数据比对
|
7天前
|
供应链 API 开发者
1688 商品数据接口终极指南:Python 开发者如何高效获取标题 / 价格 / 销量数据(附调试工具推荐)
1688商品列表API是阿里巴巴开放平台提供的服务,允许开发者通过API获取1688平台的商品信息(标题、价格、销量等)。适用于电商选品、比价工具、供应链管理等场景。使用时需构造请求URL,携带参数(如q、start_price、end_price等),发送HTTP请求并解析返回的JSON/XML数据。示例代码展示了如何用Python调用该API获取商品列表。
70 18
|
1月前
|
XML JSON API
如何在 Postman 中上传文件和 JSON 数据
如果你想在 Postman 中同时上传文件和 JSON 数据,本文将带你一步一步地了解整个过程,包括最佳实践和技巧,让你的工作更轻松。
|
1月前
|
JSON JavaScript 前端开发
如何在 Postman 中发送 JSON 数据
我们将深入探讨使用 Postman 发送 JSON 数据这一主题,Postman 是一款强大的 API 测试和开发工具。无论您是经验丰富的开发人员还是新手,掌握这项技能对于高效的 API 测试和开发都至关重要。
|
1天前
|
Web App开发 数据采集 JavaScript
动态网页爬取:Python如何获取JS加载的数据?
动态网页爬取:Python如何获取JS加载的数据?
|
1月前
|
数据采集 存储 缓存
Python爬虫与代理IP:高效抓取数据的实战指南
在数据驱动的时代,网络爬虫是获取信息的重要工具。本文详解如何用Python结合代理IP抓取数据:从基础概念(爬虫原理与代理作用)到环境搭建(核心库与代理选择),再到实战步骤(单线程、多线程及Scrapy框架应用)。同时探讨反爬策略、数据处理与存储,并强调伦理与法律边界。最后分享性能优化技巧,助您高效抓取公开数据,实现技术与伦理的平衡。
89 4
|
2月前
|
XML JSON API
淘宝商品详情API的调用流程(python请求示例以及json数据示例返回参考)
JSON数据示例:需要提供一个结构化的示例,展示商品详情可能包含的字段,如商品标题、价格、库存、描述、图片链接、卖家信息等。考虑到稳定性,示例应基于淘宝开放平台的标准响应格式。
|
2月前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——封装统一返回的数据结构
本文介绍了在Spring Boot中封装统一返回的数据结构的方法。通过定义一个泛型类`JsonResult&lt;T&gt;`,包含数据、状态码和提示信息三个属性,满足不同场景下的JSON返回需求。例如,无数据返回时可设置默认状态码&quot;0&quot;和消息&quot;操作成功!&quot;,有数据返回时也可自定义状态码和消息。同时,文章展示了如何在Controller中使用该结构,通过具体示例(如用户信息、列表和Map)说明其灵活性与便捷性。最后总结了Spring Boot中JSON数据返回的配置与实际项目中的应用技巧。
155 0