《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
>>>
相关文章
|
7月前
|
数据采集 Web App开发 数据可视化
Python零基础爬取东方财富网股票行情数据指南
东方财富网数据稳定、反爬宽松,适合爬虫入门。本文详解使用Python抓取股票行情数据,涵盖请求发送、HTML解析、动态加载处理、代理IP切换及数据可视化,助你快速掌握金融数据爬取技能。
4593 1
|
7月前
|
Java 数据挖掘 数据处理
(Pandas)Python做数据处理必选框架之一!(一):介绍Pandas中的两个数据结构;刨析Series:如何访问数据;数据去重、取众数、总和、标准差、方差、平均值等;判断缺失值、获取索引...
Pandas 是一个开源的数据分析和数据处理库,它是基于 Python 编程语言的。 Pandas 提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据(类似于Excel表格)。 Pandas 是数据科学和分析领域中常用的工具之一,它使得用户能够轻松地从各种数据源中导入数据,并对数据进行高效的操作和分析。 Pandas 主要引入了两种新的数据结构:Series 和 DataFrame。
678 0
|
7月前
|
JSON API 数据格式
淘宝拍立淘按图搜索API系列,json数据返回
淘宝拍立淘按图搜索API系列通过图像识别技术实现商品搜索功能,调用后返回的JSON数据包含商品标题、图片链接、价格、销量、相似度评分等核心字段,支持分页和详细商品信息展示。以下是该API接口返回的JSON数据示例及详细解析:
|
7月前
|
JSON 算法 API
Python采集淘宝商品评论API接口及JSON数据返回全程指南
Python采集淘宝商品评论API接口及JSON数据返回全程指南
|
7月前
|
JSON API 数据安全/隐私保护
Python采集淘宝拍立淘按图搜索API接口及JSON数据返回全流程指南
通过以上流程,可实现淘宝拍立淘按图搜索的完整调用链路,并获取结构化的JSON商品数据,支撑电商比价、智能推荐等业务场景。
|
7月前
|
JSON 中间件 Java
【GoGin】(3)Gin的数据渲染和中间件的使用:数据渲染、返回JSON、浅.JSON()源码、中间件、Next()方法
我们在正常注册中间件时,会打断原有的运行流程,但是你可以在中间件函数内部添加Next()方法,这样可以让原有的运行流程继续执行,当原有的运行流程结束后再回来执行中间件内部的内容。​ c.Writer.WriteHeaderNow()还会写入文本流中。可以看到使用next后,正常执行流程中并没有获得到中间件设置的值。接口还提供了一个可以修改ContentType的方法。判断了传入的状态码是否符合正确的状态码,并返回。在内部封装时,只是标注了不同的render类型。再看一下其他返回的类型;
349 3
|
7月前
|
JSON Java Go
【GoGin】(2)数据解析和绑定:结构体分析,包括JSON解析、form解析、URL解析,区分绑定的Bind方法
bind或bindXXX函数(后文中我们统一都叫bind函数)的作用就是将,以方便后续业务逻辑的处理。
442 3
|
8月前
|
数据采集 关系型数据库 MySQL
python爬取数据存入数据库
Python爬虫结合Scrapy与SQLAlchemy,实现高效数据采集并存入MySQL/PostgreSQL/SQLite。通过ORM映射、连接池优化与批量提交,支持百万级数据高速写入,具备良好的可扩展性与稳定性。
|
7月前
|
XML JSON 数据处理
超越JSON:Python结构化数据处理模块全解析
本文深入解析Python中12个核心数据处理模块,涵盖csv、pandas、pickle、shelve、struct、configparser、xml、numpy、array、sqlite3和msgpack,覆盖表格处理、序列化、配置管理、科学计算等六大场景,结合真实案例与决策树,助你高效应对各类数据挑战。(238字)
969 0
|
7月前
|
JSON 算法 API
Python中的json模块:从基础到进阶的实用指南
本文深入解析Python内置json模块的使用,涵盖序列化与反序列化核心函数、参数配置、中文处理、自定义对象转换及异常处理,并介绍性能优化与第三方库扩展,助你高效实现JSON数据交互。(238字)
606 4