所以你们既是神的选民,圣洁蒙爱的人,就要存怜悯、恩慈、谦虚、温柔、忍耐的心。倘若这人与那人有嫌隙,总要彼此包容,彼此饶恕;主怎么饶恕了你们,你们也要怎样饶恕人。在这一切之外,要存着爱心,爱心就是联络全德的。又要叫基督的平安在你们心里作主,你们也为此蒙召,归为一体,且要存感谢的心。(COLOSSIANS 3:12-15)

标准库(8)

json

就传递数据而言,xml是一种选择,还有另外一种,就是json,它是一种轻量级的数据交换格式,如果读者要做web编程,是会用到它的。根据维基百科的相关内容,对json了解一二:

JSON(JavaScript Object Notation)是一種由道格拉斯·克羅克福特構想設計、輕量級的資料交換語言,以文字為基礎,且易於讓人閱讀。儘管JSON是Javascript的一個子集,但JSON是獨立於語言的文本格式,並且採用了類似於C語言家族的一些習慣。

关于json更为详细的内容,可以参考其官方网站:http://www.json.org

从官方网站上摘取部分,了解一下json的结构:

JSON建构于两种结构:

  • “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
  • 值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。

python标准库中有json模块,主要是执行序列化和反序列化功能:

  • 序列化:encoding,把一个python对象编码转化成json字符串
  • 反序列化:decoding,把json格式字符串解码转换为python数据对象

基本操作

json模块相对xml单纯了很多:

>>> import json
>>> json.__all__
['dump', 'dumps', 'load', 'loads', 'JSONDecoder', 'JSONEncoder']

encoding: dumps()

>>> data = [{"name":"qiwsir", "lang":("python", "english"), "age":40}]
>>> print data
[{'lang': ('python', 'english'), 'age': 40, 'name': 'qiwsir'}]
>>> data_json = json.dumps(data)
>>> print data_json
[{"lang": ["python", "english"], "age": 40, "name": "qiwsir"}]

encoding的操作是比较简单的,请注意观察data和data_json的不同——lang的值从元组编程了列表,还有不同:

>>> type(data_json)
<type 'str'>
>>> type(data)
<type 'list'>

将python对象转化为json类型,是按照下表所示对照关系转化的:

python==> json
dict object
list, tuple array
str, unicode string
int, long, float number
True true
False false
None null

decoding: loads()

decoding的过程也像上面一样简单:

>>> new_data = json.loads(data_json)
>>> new_data
[{u'lang': [u'python', u'english'], u'age': 40, u'name': u'qiwsir'}]

需要注意的是,解码之后,并没有将元组还原。

解码的数据类型对应关系:

json==> python
object dict
array list
string unicode
number(int) int, long
number(real) float
true True
false False
null None

对人友好

上面的data都不是很长,还能凑合阅读,如果很长了,阅读就有难度了。所以,json的dumps()提供了可选参数,利用它们能在输出上对人更友好(这对机器是无所谓的)。

>>> data_j = json.dumps(data, sort_keys=True, indent=2)
>>> print data_j
[
  {
    "age": 40, 
    "lang": [
      "python", 
      "english"
    ], 
    "name": "qiwsir"
  }
]

sort_keys=True意思是按照键的字典顺序排序,indent=2是让每个键值对显示的时候,以缩进两个字符对齐。这样的视觉效果好多了。

大json字符串

如果数据不是很大,上面的操作足够了。但是,上面操作是将数据都读入内存,如果太大就不行了。怎么办?json提供了load()dump()函数解决这个问题,注意,跟上面已经用过的函数相比,是不同的,请仔细观察。

>>> import tempfile    #临时文件模块
>>> data
[{'lang': ('python', 'english'), 'age': 40, 'name': 'qiwsir'}]
>>> f = tempfile.NamedTemporaryFile(mode='w+')
>>> json.dump(data, f)
>>> f.flush()
>>> print open(f.name, "r").read()
[{"lang": ["python", "english"], "age": 40, "name": "qiwsir"}]

自定义数据类型

一般情况下,用的数据类型都是python默认的。但是,我们学习过类后,就知道,自己可以定义对象类型的。比如:

以下代码参考:Json概述以及python对json的相关操作

#!/usr/bin/env python
# coding=utf-8

import json

class Person(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __repr__(self):
        return 'Person Object name : %s , age : %d' % (self.name,self.age)


def object2dict(obj):    #convert Person to dict
    d = {}
    d['__class__'] = obj.__class__.__name__
    d['__module__'] = obj.__module__
    d.update(obj.__dict__)
    return d

def dict2object(d):     #convert dict ot Person
    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())    #get args
        inst = class_(**args)    #create new instance
    else:
        inst = d
    return inst


if __name__  == '__main__':
    p = Person('Peter',40)
    print p
    d = object2dict(p)
    print d
    o = dict2object(d)
    print type(o), o

    dump = json.dumps(p, default=object2dict)
    print dump
    load = json.loads(dump, object_hook=dict2object)
    print load

总目录   |   上节:标准库(7)   |   下节:第三方库

如有疑问,请到Python论坛提问