Python读写JSON数据完整指南:编码、解码与对象序列化

咖啡半糖
咖啡半糖
发布时间:2026-10-14 | 5人浏览过
原创

本文详细介绍Python中json模块的使用,涵盖json.dumps和json.loads进行数据编码解码,以及json.dump和json.load处理JSON文件。文章还深入探讨了处理嵌套数据、保留字典顺序、格式化输出以及通过自定义hook函数实现复杂Python对象与JSON相互转换的高级技巧。

Python读写JSON数据完整指南:编码、解码与对象序列化

问题

你需要处理以JavaScript Object Notation (JSON) 格式编码的数据,实现数据的读写操作。

解决方案

基础JSON编码与解码

Python内置的json模块提供了简便的方法来编码和解码JSON数据。其核心接口主要包含两个函数:json.dumps()用于将Python对象转换为JSON字符串,而json.loads()则负责将JSON字符串还原为Python对象。相较于pickle等其他序列化库,json模块的接口更为简洁。以下示例展示了如何将一个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文件读写操作

若需直接处理文件而非字符串,可使用json.dump()进行写入,使用json.load()进行读取。具体用法如下:


# 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)

讨论

JSON数据类型映射与规范

JSON编码支持的基础数据类型包括None、bool、int、float和str,以及由这些类型构成的lists、tuples和dictionaries。对于字典(dictionaries),其键(keys)必须为字符串类型;若字典中包含非字符串类型的键,编码时会自动将其转换为字符串。为符合JSON规范,建议仅对Python的lists和dictionaries进行编码。在Web应用程序中,顶层对象通常被编码为字典,这是标准做法。

JSON编码后的格式与Python语法几乎一致,仅存在细微差异。例如,Python的True和False会被映射为JSON的true和false,而None则映射为null。以下示例展示了编码后的字符串效果:


>>> json.dumps(False)
'false'
>>> d = {'a': True,
...  'b': 'Hello',
...  'c': None}
>>> json.dumps(d)
'{"b": "Hello", "c": null, "a": true}'
>>>

数据格式化与顺序保留

在检查JSON解码后的数据时,若数据结构嵌套较深或字段众多,简单的print()输出往往难以清晰展示其结构。为此,建议使用pprint模块中的pprint()函数替代普通print()。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解码会根据数据内容生成dicts或lists。若需创建其他类型的对象,可向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
}
>>>

通常情况下,Python对象实例并非直接可序列化为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

若需逆向操作,即从JSON字符串恢复对象实例,可按以下方式操作:


# 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
>>>

json模块还提供了其他选项,用于控制数字、特殊值(如NaN)等低级数据的解析行为。更多细节可参考官方文档。

以上就是Python如何读取、写入JSON数据的详细内容,更多关于Python读写json数据的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表