Python | JSON |
---|---|
dict | Object |
list, tuple | array |
str | string |
int, float, | numbers |
True | true |
False | false |
None | null |
你注意到了吗? 还有很多python数据类型(set, datetime)不在上表中哦。
json模块的dumps方法可以将python常用数据格式转化为json格式。该方法还提供了很多可选参数如ident, separators, ensure_ascii, sort_keys和default参数。这些参数都非常有用,我们会稍后逐一介绍。
dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
我们先来看看一个最简单的例子。你注意到了吗? 生成的json格式数据外面都加了单引号,这说明dict类型数据已经转化成了json字符串。
>>> import json >>> json.dumps({"name":"John", "score": 112}) '{"name": "John", "score": 112}'
如果一个dict很长,生成的json字符串会非常长,这时我们可以设置indent参数使生成的json格式数据更优美,更容易人们阅读。代码如下所示:
>>> import json >>> json.dumps({"name":"John", "score": 112}, indent=4) '{\n "name": "John",\n "score": 112\n}' >>> print(json.dumps({"name":"John", "score": 112}, indent=4)) { "name": "John", "score": 112 }
然而使用indent参数的代价是json字符串里增加了额外的空白,机器阅读根本不需要它们,
即使不用indent参数,你会发现dumps生成的json字符串中的','号和':'号分隔符后都会附加一个默认空白字符,我们可以通过separators参数重新指定分隔符,从而去除无用的空白字符,如下所示。这样可以减少无用数据的的传输,节省带宽增加数据传输速度。
>>> import json >>> json.dumps({"name":"John", "score": 112}) '{"name": "John", "score": 112}' # 使用separators选项 >>> json.dumps({"name":"John", "score": 112}, separators=(',',':')) '{"name":"John","score":112}'
如果字符串有非ASCII字符(比如中文),它们在json序列化时都会被转义成'\uXXXX'组成的ascii字符串。如果想得到更加易读的字符串,可以设置ensure_ascii=False。
>>> import json >>> json.dumps({"Name":"小明", "Age": 16}) '{"Name": "\\u5c0f\\u660e", "Age": 16}' # 设置ensure_ascii=False >>> json.dumps({"Name":"小明", "Age": 16}, ensure_ascii=False) '{"Name": "小明", "Age": 16}'
一般的dict默认是无序的,你还可以设置sort_keys = True对生成的json格式数据进行排序,这里就不演示了。default参数我们后面会重点介绍。
与dumps方法不同,json模块的dump方法用于将生成的json数据写入磁盘文件。其用法和dumps类似,唯一不同的是需要指定需要写入的文件,具体用法如下所示:
import json with open("json.txt", 'w') as f: json.dump({"Name":"小明", "Age": 16}, f, ensure_ascii=True)
json的loads方法用于将json格式数据转化为python格式,实现数据的反序列化,如下所示。千万别忘了在json符串外的单引号哦。
>>> import json >>> json.loads('{"Name": "小明", "Age": 16}') {'Name': '小明', 'Age': 16}
json的load方法与loads用法相似,不过它需要指定存有json数据的文件。
>>> import json >>> with open("json.txt", 'r') as f: json.load(f)
很多python数据类型(比如日期,集合和自定义的类)并不能直接被dumps方法序列化,这时会出现 xxx is not JSON serializable的错误,如下面代码所示。当出现类似错误时,我们有两种解决方案。
>>> import json >>> from datetime import datetime # DateTime类型 >>> json.dumps({"date":datetime.now()}) Traceback (most recent call last): TypeError: Object of type 'datetime' is not JSON serializable # 自定义的User类 >>> class User(object): def __init__(self, name): self.name = name >>> json.dumps(User("John")) Traceback (most recent call last): TypeError: Object of type 'User' is not JSON serializable
该方法的工作原理是先编写数据类型转化函数,通过设置dumps方法里的default参数调用格式转化函数,将dumps方法不支持的数类型先转化为字符串格式,再实现json序列化。
# 将datetime格式数据json化 >> > import json >> > from datetime import datetime >> > def date_to_str(obj): if isinstance(obj, datetime): return obj.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(obj, date): return obj.strftime('%Y-%m-%d') return TypeError >> > json.dumps({"date": datetime.now()}, default=date_to_str) '{"date": "2018-09-22 21:25:42"}' # 将set类型数据json化 >> > import json >> > set_data = {'my_set': {1, 2, 3}} >> > def set_to_list(obj): if isinstance(obj, set): return list(obj) raise TypeError >> > result = json.dumps(set_data, default=set_to_list)
对于我们自定义的类, 使用dumps方法时我们一般要先编写obj_to_dict方法,将object转化为字典dict再JSON序列化。同理,使用loads方法对json数据反序列化时,我们还需要编写dict_to_obj方法,通过default参数调用。下面这2段代码是比较通用的对象(object)与字典(dict)互转的经典代码,请用微信收藏后再看。
# 将自定义的类转化为字典,dumps方法使用 def obj_to_dict(obj): d = {} d['__class__'] = obj.__class__.__name__ d['__module__'] = obj.__module__ d.update(obj.__dict__) return d # 将字典转化为自定义的类,loads方法使用 def dict_to_obj(d): if '__class__' in d: class_name = d.pop('__class__') module_name = d.pop('__module__') module = __import__(module_name) class_ = getattr(module, class_name) args = dict((key.encode('ascii'), value) for key, value in d.items()) instance = class_(**args) else: instance = d return instance
另一个解决方案是继承JSONEncoder类和JSONDecode类定义自己的编码Encoder类,然后使用cls=MyEncoder,来调用编码器。比如下例中我们定义了自己的DateTimeEncoder,将日期类型数据序列化。
from datetime import datetime, date import json class DateTimeEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime): return obj.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(obj, date): return obj.strftime('%Y-%m-%d') return json.JSONEncoder.default(self, obj) json_data = {'num': 1, 'date': datetime.now()} print(json.dumps(json_data, cls=DateTimeEncoder))
对于自定义的对象,我们也可以通过继承JSONEncoder类实现它的序列化,如下所示:
import json class User(object): def __init__(self, name): self.name = name class MyJSONEncoder(json.JSONEncoder): def default(self, obj): d = {} d['__class__'] = obj.__class__.__name__ d['__module__'] = obj.__module__ d.update(obj.__dict__) return d user = User("John") json.dumps(user, cls=MyJSONEncoder))
对于简单的数据序列化,方案一更容易理解,代码也更少。但当需要传输的数据很大时,使用继承JSONEncoder类来实现序列化时有个很大的好处,就是可以通过iterencode()方法把一个很大的数据对象分多次进行序列化,这对于网络持续传输或写入大的文件非常有用。如下所示。
>>> for chunk in MyJSONEncoder().iterencode(big_object): ... print(chunk)
Django编程就是是python编程,以上所介绍的序列化方法对django也是适用的。不同的是Django还有自己专属的数据类型比如QuerySet和ValueQuerySet类型数据,还提供了更便捷的serializers类。使用serializers类可以轻易将QuerySet格式的数据转化为json格式。
# Django Queryset数据 to Json from django.core import serializers data = serializers.serialize("json", SomeModel.objects.all()) data1 = serializers.serialize("json", SomeModel.objects.all(), fields=('name','id')) data2 = serializers.serialize("json", SomeModel.objects.filter(field = some_value))
有时候我们只需要查询结果集的部分字段,可以使用values('字段名','字段名2')来要求返回的是哪些列的数据.但是返回来的是ValuesQuerySet对象而不是QuerySet对象。ValuesQuerySet对象不能用 serializers.serialize() 方法序列化成json, 需要先转换成list再用 json.dumps()方法序列化成json格式。示例代码如下所示:
import json from django.core.serializers.json import DjangoJSONEncoder queryset = myModel.objects.filter(foo_icontains=bar).values('f1', 'f2', 'f3') data4 = json.dumps(list(queryset), cls=DjangoJSONEncoder)
如果你要利用django开发restful的web API, 为不同客户端提供序列化过的json格式数据,django-rest-framework才是你真正需要的序列化工具。与django自带的serializers类相比,rest framework支持用户验证,查询过滤和符合restful规范的url设计,我们后面会专门介绍。欢迎关注我的微信。
我们介绍了何为JSON序列化以及python json模块的dumps, loads, dump和load方法。我们还介绍了如何将dumps方法不支持的数据格式(如日期,集合, 自定义的类和Django的QuerySet类型)如何通过要自定义格式转化函数和继承JsonEncoder类将它们转化为json格式。希望本文对你有所帮助。喜欢的给个赞吧!
以上就是Python如何把不同类型数据的json序列化的详细内容,更多关于python 数据json序列化的资料请关注脚本之家其它相关文章!