python對json的相關操作 json.dumps() json.loads()
什麼是json:
JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式。易於人閱讀和編寫。同時也易於機器解析和生成。它基於JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一個子集。JSON採用完全獨立於語言的文字格式,但是也使用了類似於C語言家族的習慣(包括C, C++, C#, Java, JavaScript, Perl, Python等)。這些特性使JSON成為理想的資料交換語言。
JSON建構於兩種結構:
“名稱/值”對的集合(A collection of name/value pairs)。不同的語言中,它被理解為物件(object),紀錄(record),結構(struct),字典(dictionary),雜湊表 (hash table),有鍵列表(keyed list),或者關聯陣列 (associative array)。
值的有序列表(An ordered list of values)。在大部分語言中,它被理解為陣列(array)。
這些都是常見的資料結構。事實上大部分現代計算機語言都以某種形式支援它們。這使得一種資料格式在同樣基於這些結構的程式語言之間交換成為可能。
對簡單資料型別的encoding 和 decoding:
使用簡單的json.dumps方法對簡單資料型別進行編碼,例如:
1 2 3 4 5 6 |
import json
obj = [[ 1 , 2 , 3 ], 123 , 123.123 , 'abc' ,{ 'key1' :( 1 , 2 , 3 ), 'key2' :( 4 , 5 , 6 )}]
encodedjson = json.dumps(obj)
print repr (obj)
print encodedjson
|
輸出:
[[1, 2, 3], 123, 123.123, 'abc', {'key2': (4, 5, 6), 'key1': (1, 2, 3)}]
[[1, 2, 3], 123, 123.123, "abc", {"key2": [4, 5, 6], "key1": [1, 2, 3]}]
通過輸出的結果可以看出,簡單型別通過encode之後跟其原始的repr()輸出結果非常相似,但是有些資料型別進行了改變,例如上例中的元組則轉換為了列表。在json的編碼過程中,會存在從python原始型別向json型別的轉化過程,具體的轉化對照如下:
json.dumps()方法返回了一個str物件encodedjson,我們接下來在對encodedjson進行decode,得到原始資料,需要使用的json.loads()函式:
1 2 3 4 |
decodejson = json.loads(encodedjson)
print type (decodejson)
print decodejson[ 4 ][ 'key1' ]
print decodejson
|
輸出:
<type 'list'>
[1, 2, 3]
[[1, 2, 3], 123, 123.123, u'abc', {u'key2': [4, 5, 6], u'key1': [1, 2, 3]}]
loads方法返回了原始的物件,但是仍然發生了一些資料型別的轉化。比如,上例中‘abc’轉化為了unicode型別。從json到python的型別轉化對照如下:
json.dumps方法提供了很多好用的引數可供選擇,比較常用的有sort_keys(對dict物件進行排序,我們知道預設dict是無序存放的),separators,indent等引數。
排序功能使得儲存的資料更加有利於觀察,也使得對json輸出的物件進行比較,例如:
1 2 3 4 5 6 7 8 9 10 |
data1 = { 'b' : 789 , 'c' : 456 , 'a' : 123 }
data2 = { 'a' : 123 , 'b' : 789 , 'c' : 456 }
d1 = json.dumps(data1,sort_keys = True )
d2 = json.dumps(data2)
d3 = json.dumps(data2,sort_keys = True )
print d1
print d2
print d3
print d1 = = d2
print d1 = = d3
|
輸出:
{"a": 123, "b": 789, "c": 456}
{"a": 123, "c": 456, "b": 789}
{"a": 123, "b": 789, "c": 456}
False
True
上例中,本來data1和data2資料應該是一樣的,但是由於dict儲存的無序特性,造成兩者無法比較。因此兩者可以通過排序後的結果進行儲存 就避免了資料比較不一致的情況發生,但是排序後再進行儲存,系統必定要多做一些事情,也一定會因此造成一定的效能消耗,所以適當排序是很重要的。
indent引數是縮排的意思,它可以使得資料儲存的格式變得更加優雅。
1 2 3 |
data1 = { 'b' : 789 , 'c' : 456 , 'a' : 123 }
d1 = json.dumps(data1,sort_keys = True ,indent = 4 )
print d1
|
輸出:
{
"a": 123,
"b": 789,
"c": 456
}
輸出的資料被格式化之後,變得可讀性更強,但是卻是通過增加一些冗餘的空白格來進行填充的。json主要是作為一種資料通訊的格式存在的,而網路通 信是很在乎資料的大小的,無用的空格會佔據很多通訊頻寬,所以適當時候也要對資料進行壓縮。separator引數可以起到這樣的作用,該引數傳遞是一個 元組,包含分割物件的字串。
1 2 3 4 5 |
print 'DATA:' , repr (data)
print 'repr(data)
:' , len ( repr (data))
print 'dumps(data)
:' , len (json.dumps(data))
print 'dumps(data,
indent=2) :' , len (json.dumps(data,
indent = 4 ))
print 'dumps(data,
separators):' , len (json.dumps(data,
separators = ( ',' , ':' )))
|
輸出:
DATA: {'a': 123, 'c': 456, 'b': 789}
repr(data) : 30
dumps(data) : 30
dumps(data, indent=2) : 46
dumps(data, separators): 25
通過移除多餘的空白符,達到了壓縮資料的目的,而且效果還是比較明顯的。
另一個比較有用的dumps引數是skipkeys,預設為False。 dumps方法儲存dict物件時,key必須是str型別,如果出現了其他型別的話,那麼會產生TypeError異常,如果開啟該引數,設為True的話,則會比較優雅的過度。
1 2 |
data = { 'b' : 789 , 'c' : 456 ,( 1 , 2 ): 123 }
print json.dumps(data,skipkeys = True )
|
輸出:
{"c": 456, "b": 789}
處理自己的資料型別
json模組不僅可以處理普通的python內建型別,也可以處理我們自定義的資料型別,而往往處理自定義的物件是很常用的。
首先,我們定義一個類Person。
1 2 3 4 5 6 7 8 9 |
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)
if __name__ = = '__main__' :
p = Person( 'Peter' , 22 )
print p
|
如果直接通過json.dumps方法對Person的例項進行處理的話,會報錯,因為json無法支援這樣的自動轉化。通過上面所提到的json 和python的型別轉化對照表,可以發現,object型別是和dict相關聯的,所以我們需要把我們自定義的型別轉化為dict,然後再進行處理。這 裡,有兩種方法可以使用。
方法一:自己寫轉化函式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
'''
Created on 2011-12-14
@author: Peter
'''
import Person
import json
p = Person.Person( 'Peter' , 22 )
def object2dict(obj):
#convert
object to a dict
d = {}
d[ '__class__' ] = obj.__class__.__name__
d[ '__module__' ] = obj.__module__
d.update(obj.__dict__)
return d
def dict2object(d):
#convert
dict to object
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
d = object2dict(p)
print d
#{'age': 22, '__module__': 'Person', '__class__': 'Person', 'name': 'Peter'}
o = dict2object(d)
print type (o),o
#<class 'Person.Person'> Person Object name : Peter , age : 22
dump = json.dumps(p,default
|