JSON 序列化
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,人类易读、机器易解析。Python 的 json 模块提供了 JSON 编码(Python 对象 → JSON 字符串)和解码(JSON 字符串 → Python 对象)的功能。
基本用法
编码:dumps()
import json
data = {
"name": "Alice",
"age": 25,
"is_student": False,
"courses": ["Math", "Physics"],
"address": None,
}
json_str = json.dumps(data)
print json_str
# {"courses": ["Math", "Physics"], "is_student": false, "name": "Alice", "age": 25, "address": null}
dumps() 把 Python 对象转换为 JSON 字符串。注意 JSON 的格式特点:
- 键必须是双引号字符串
False变成falseNone变成null- 字典键的顺序可能不同(Python 2 中字典无序)
解码:loads()
json_str = '{"name": "Bob", "age": 30}'
data = json.loads(json_str)
print data # {u'age': 30, u'name': u'Bob'}
print type(data) # <type 'dict'>
loads() 把 JSON 字符串转换为 Python 对象。Python 2 中,JSON 字符串解码为 unicode,数字解码为 int 或 float。
格式化输出
data = {"name": "Alice", "age": 25}
# 美化输出(缩进)
print json.dumps(data, indent=2)
# {
# "age": 25,
# "name": "Alice"
# }
# 自定义分隔符
print json.dumps(data, indent=2, separators=(",", ": "))
# {
# "age": 25,
# "name": "Alice"
# }
# 排序键
print json.dumps(data, indent=2, sort_keys=True)
# {
# "age": 25,
# "name": "Alice"
# }
处理中文
默认情况下,非 ASCII 字符被转义为 \uXXXX:
data = {"name": "张三"}
print json.dumps(data)
# {"name": "\u5f20\u4e09"}
# 保留中文
print json.dumps(data, ensure_ascii=False)
# {"name": "张三"}
ensure_ascii=False 让 dumps() 直接输出 Unicode 字符,而不是转义序列。写入文件时需要指定编码:
import codecs
with codecs.open("data.json", "w", "utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
文件读写
# 写入文件
with open("data.json", "w") as f:
json.dump(data, f, indent=2)
# 读取文件
with open("data.json", "r") as f:
data = json.load(f)
dump() 和 load() 直接操作文件对象,dumps() 和 loads() 操作字符串。
类型映射
| Python | JSON |
|---|---|
dict | object |
list, tuple | array |
str, unicode | string |
int, long, float | number |
True | true |
False | false |
None | null |
注意:
- JSON 不支持元组,
tuple被编码为数组,解码后变成list - JSON 不支持
set - JSON 的键必须是字符串,Python
dict的整数键会被转为字符串
data = {1: "one", 2: "two"}
json_str = json.dumps(data)
print json_str # {"1": "one", "2": "two"},键变成字符串
自定义编码
对于 JSON 不支持的对象(如 datetime、自定义类),需要自定义编码器:
import json
from datetime import datetime
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def custom_encoder(obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, Person):
return {"name": obj.name, "age": obj.age}
raise TypeError("Object of type %s is not JSON serializable" % type(obj))
now = datetime.now()
p = Person("Alice", 25)
print json.dumps({"time": now, "person": p}, default=custom_encoder)
# {"time": "2024-01-15T10:30:00", "person": {"age": 25, "name": "Alice"}}
实际应用
配置文件:
# config.json
{
"host": "localhost",
"port": 8080,
"debug": false,
"allowed_hosts": ["example.com", "api.example.com"]
}
# 读取配置
with open("config.json", "r") as f:
config = json.load(f)
print config["host"] # localhost
API 数据交换:
import urllib2
response = urllib2.urlopen("https://api.example.com/data")
data = json.load(response)
print data["users"][0]["name"]
与 pickle 的对比
| 特性 | JSON | pickle |
|---|---|---|
| 格式 | 文本,人类可读 | 二进制 |
| 跨语言 | 是 | 否(Python 专用) |
| 安全性 | 安全 | 不安全(不要加载不信任的数据) |
| 支持类型 | 基本类型 | 几乎所有 Python 对象 |
| 速度 | 较慢 | 较快 |
原则:数据交换用 JSON,Python 内部对象持久化用 pickle(但要确保数据来源可信)。