python json,copy

什么是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)。 
这些都是常见的数据结构。事实上大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为可能。

jso官方说明参见:http://json.org/

Python操作json的标准api库参考:http://docs.python.org/library/json.html

对简单数据类型的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类型的转化过程,具体的转化对照如下:

image

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的类型转化对照如下:

image

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 = object2dict)
print  dump
#{"age": 22, "__module__": "Person", "__class__": "Person", "name": "Peter"}
 
load =  json.loads(dump,object_hook =  dict2object)
print  load
#Person Object name : Peter , age : 22

上面代码已经写的很清楚了,实质就是自定义object类型和dict类型进行转化。object2dict函数将对象模块名、类名以及__dict__存储在dict对象里,并返回。dict2object函数则是反解出模块名、类名、参数,创建新的对象并返回。在json.dumps 方法中增加default参数,该参数表示在转化过程中调用指定的函数,同样在decode过程中json.loads方法增加object_hook,指定转化函数。

方法二:继承JSONEncoder和JSONDecoder类,覆写相关方法

JSONEncoder类负责编码,主要是通过其default函数进行转化,我们可以override该方法。同理对于JSONDecoder。

?
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
'''
Created on 2011-12-14
@author: Peter
'''
import  Person
import  json
 
p =  Person.Person( 'Peter' , 22 )
 
class  MyEncoder(json.JSONEncoder):
     def  default( self ,obj):
         #convert object to a dict
         d =  {}
         d[ '__class__' ] =  obj.__class__.__name__
         d[ '__module__' ] =  obj.__module__
         d.update(obj.__dict__)
         return  d
 
class  MyDecoder(json.JSONDecoder):
     def  __init__( self ):
         json.JSONDecoder.__init__( self ,object_hook = self .dict2object)
     def  dict2object( self ,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 =  MyEncoder().encode(p)
o =   MyDecoder().decode(d)
 
print  d
print  type (o), o

 

对于JSONDecoder类方法,稍微有点不同,但是改写起来也不是很麻烦。看代码应该就比较清楚了。

##################################################

Python处理json的模块
官方手册:http://docs.python.org/library/json.html

>>>import json
>>> json.JSONEncoder().encode({})
'{}'
>>> json.JSONEncoder().encode({"name":"daxi"})
'{"name": "daxi"}'
>>> json.JSONEncoder().encode({"name":"daxi","age":20})
'{"age": 20, "name": "daxi"}'
>>> s = json.JSONEncoder().encode({"name":"daxi","age":20})
>>> s
'{"age": 20, "name": "daxi"}'
>>> json.JSONDecoder().decode(s)
{u'age': 20, u'name': u'daxi'}
>>> print json.JSONDecoder().decode(s)
{u'age': 20, u'name': u'daxi'}
>>> print json.JSONDecoder().decode(s)['age']
20
>>> print json.JSONDecoder().decode(s)['name']
daxi
>>> s = json.JSONEncoder().encode({"name":"daxi","age":20, "city":"北京"})
>>> s
'{"city": "\\u5317\\u4eac", "age": 20, "name": "daxi"}'
>>> print json.JSONDecoder().decode(s)['city']
北京

还有一个 http://pypi.python.org/pypi/simplejson/, 暂未测试!

##################################################

json 格式的例子:
{
"firstName": "John",
"lastName": "Smith",
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": 10021
},
"phoneNumbers": [
{ "type": "home", "number": "212 555-1234" },
{ "type": "fax", "number": "646 555-4567" }
],
"newSubscription": false,
"companyName": null
}
本质上就是一串格式化的字符串。

python 2.5 没有内置的 json 处理模块,可以下载 python-json (json-py) 模块(下载地址: http://pypi.python.org/pypi/python-json)。解压zip包 然后把 json.py 和 minjson.py 考到 /usr/lib/python2.5/下面就行了。
python 2.6 内置了一个 json 的处理模块(官方使用文档: http://docs.python.org/library/json.html)。


关于几个流行 json 处理模块的效率比较:
http://blog.csdn.net/toontong/archive/2009/12/10/4979572.aspx

语法:
这里以 python 2.5 为例:


>>> import json
读取:

>>> data = json.read('{"firstname": "Zhongwei", "lastname": "Sun"}') # 前面已经提到了,json 就是一个格式化字符串,所以大括号两侧要加上引号。
>>> data['firstname']
'Zhongwei'
>>> data['lastname']
'Sun'

写:(感觉这个用处不是很大)

>>> test = json.write(data)
>>> test
'{"lastname":"Sun","firstname":"Zhongwei"}'
>>>

python 2.6 为例:

## object-->jsonstr

Compact encoding:

>>> import json
>>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':'))
'[1,2,3,{"4":5,"6":7}]'

## jsonstr-->object

Decoding JSON:

>>> import json
>>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')
###
>>> data=json.loads('{"firstname": "Zhongwei", "lastname": "Sun"}')
>>> print data
{u'lastname': u'Sun', u'firstname': u'Zhongwei'}
>>> {u'lastname': u'Sun', u'firstname': u'Zhongwei'}
{u'lastname': u'Sun', u'firstname': u'Zhongwei'}
>>> print data['firstname']
Zhongwei

>>> import json
>>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
'["foo", {"bar": ["baz", null, 1.0, 2]}]'
>>> print json.dumps("\"foo\bar")
"\"foo\bar"
>>> print json.dumps(u'\u1234')
"\u1234"
>>> print json.dumps('\\')
"\\"
>>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)
{"a": 0, "b": 0, "c": 0}
>>> from StringIO import StringIO
>>> io = StringIO()
>>> json.dump(['streaming API'], io)
>>> io.getvalue()
'["streaming API"]'

JSON 的基本介绍:
引用自:http://www.ruanyifeng.com/blog/2009/05/data_types_and_json.html

21世纪初,Douglas Crockford寻找一种简便的数据交换格式,能够在服务器之间交换数据。这其实需要二步,第一步是将各种数据转化为一个字符串,也就是数据的串行化(serialization),第二步才是交换这个字符串。

当时通用的数据交换语言是XML,但是Douglas Crockford觉得XML的生成和解析都太麻烦,所以他提出了一种简化格式,也就是Json。

Json的规格非常简单,只用一个页面、几百个字就能说清楚,而且Douglas Crockford声称这个规格永远不必升级,因为该规定的都规定了。

1) 并列的数据之间用逗号(“,”)分隔。

2) 映射用冒号(“:”)表示。

3) 并列数据的集合(数组)用方括号("[]")表示。

4) 映射的集合(对象)用大括号(“{}”)表示。

上面四条规则,就是Json格式的所有内容。

比如,下面这句话:

“北京市的面积为16800平方公里,常住人口1600万人。上海市的面积为6400平方公里,常住人口1800万。”

写成json格式就是这样:

[
{"城市":"北京","面积":16800,"人口":1600},
{"城市":"上海","面积":6400,"人口":1800}
]

如果事先知道数据的结构,上面的写法还可以进一步简化:

[
["北京",16800,1600],
["上海",6400,1800]
]

由此可以看到,json非常易学易用。所以,在短短几年中,它就取代xml,成为了互联网上最受欢迎的数据交换格式。

我猜想,Douglas Crockford一定事先就知道,数据结构可以简化成三种形式,否则怎么可能将json定义得如此精炼呢!

#####

最近发现json解释时,不同人,用同个json库写的代码不一样(所调方法函数不一致,不同用法会出现代码不兼容)。
特地去查了下资料,做了个比较。结果如下:
------------------------------------------------------------------------------------------------------------------------
python中的json解释库有好几个,其中不同版本有使用上的差异。
常用有 json-py 与smiplejson 两个包
其中json-py 包含一个minjson,用法一样,只是import时 是 import minjson
两个用法上有差别, 但import语句一样,
import json   # 都是如此import的。
import minjson
# json-py库用法
json.read( js_obj )
json.write(py_obj)
#json的minjson用法 
minjson.read( js_obj )
minjson.write(py_obj)
# smiplejson 的用法
json.loads(js_obj)   
json.dumps(py_obj)
python2.5没有内置的json,要手动安装。我们现在使用的是 json-py3.4
python2.6内置json解释库,是 smiplejson

smiplejson 2.09 下载 http://pypi.python.org/pypi/simplejson/
json-py 3.4         下载 http://sourceforge.net/projects/json-py/files/


经过我测试两者的效率,发现
python2.5.4, XP下,1K次读/写结果如下:
------------------------------------------------------------
minjosn :     1.0737601508
json     :      4.49144874205
simplejson: 0.24600865082
---------------------------------------------------------------
python2.5.4, centOS5.3 (lniux)下:

minjosn     : 1.8272049427
json          : 8.26148796082
simplejson: 3.87293195724
-------------------------------------------------------------
以上令我不解的是XP下速度会比lniux快???
结论:
基于以上,个人感觉使用 minjson.py比较保险,现在我们开发使用的是 json-py速度最慢那个。。。
因为minjson.py只有一个文件,建议直接复制到工程公共库目录下,直接使用,免去安装痛苦。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/toontong/archive/2009/12/10/4979572.aspx

香巴拉工作的一个小例子:

def get_sharedInfo(sql): # be shared..
    try:
        share=0
        rowset = dbtools.fetchall(sql)
        print sql
        if not dbtools.isfull(rowset) : return 0
        for row in rowset:
# [{"share_album":"2","share_page":"1"}] 
            share_s=0
            report_data=row.report_data
            report_data_s=str(report_data)

#            report_data_s=unicode(report_data_s.encode("utf-8"))
            json_data=json.loads(report_data_s)
#            print type(json_data[0])
            for key in json_data[0].keys():
                share_s+=int(json_data[0][key])

            share+=share_s
        print "share=%s " %(share)
        return share
    except Exception,e:
        print "Exception happened : ",e
        traceback.print_exc()


##################################################

import copy

class Obj(object):
    def __init__(self,num):
        self.num=num

    def __str__(self):
        return str(self.num)

    __repr__=__str__

def test(fun):
    a=[ Obj(10),Obj(11) ]
    b=fun(a)
    print 'a=%s,b=%s'%(a,b)
    a.reverse()
    a[0].num=100
    print 'a=%s,b=%s'%(a,b)


print '='
test(lambda _:_)

print 'copy.copy'
test(copy.copy)

print 'copy.deepcopy'
test(copy.deepcopy)



In [14]: b=copy.copy(a) 


In [15]: b 
Out[15]: [[1, 2], (3, 5), 123, [1, 2, 3, 4]] 


In [16]: b[2]=456 


In [17]: b 
Out[17]: [[1, 2], (3, 5), 456, [1, 2, 3, 4]] 


In [18]: a 
Out[18]: [[1, 2], (3, 5), 123, [1, 2, 3, 4]] 


In [19]: b[0][1]=0 


In [20]: a 
Out[20]: [[1, 0], (3, 5), 123, [1, 2, 3, 4]] 


In [21]: b 
Out[21]: [[1, 0], (3, 5), 456, [1, 2, 3, 4]] 
 


copy.copy只是复制的a本身,a里面的对象并没有被复制,还是引用的


In [22]: c=copy.deepcopy(a)


In [23]: a
Out[23]: [[1, 0], (3, 5), 123, [1, 2, 3, 4]]


In [24]: c
Out[24]: [[1, 0], (3, 5), 123, [1, 2, 3, 4]]


In [25]: c[0][1]=12


In [26]: c
Out[26]: [[1, 12], (3, 5), 123, [1, 2, 3, 4]]


In [27]: a
Out[27]: [[1, 0], (3, 5), 123, [1, 2, 3, 4]]


copy.deepcopy是连内部的对象一块复制的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值