文章目錄
前言
適用於python2和python3
正文
1. loads方法與load方法的異同
在Python中json是一個非常常用的模塊,這個主要有4個方法:
json.dumps
json.dump
json.loads
json.load
這裏主要分析講解一下json的loads
和load
方法。
這兩個方法中都是把其他類型的對象轉爲Python對象,這裏先說明一下Python對象,
Python對象包括:
所有Python基本數據類型,列表,元組,字典,自己定義的類,等等等等,當然不包括Python的字符串類型,把字符串或者文件鎏中的字符串轉爲字符串會報錯的
1.1不相同點:
loads
操作的是字符串load
操作的是文件流
1.2 相同點
- 除了第一個參數(要轉換的對象)類型不同,其他所有的參數都相同
- 最終都是轉換成Python對象
1.3 例子
先來一個例子,除了要轉換的對象,其他什麼參數都不傳:
s = '{"name": "wade", "age": 54, "gender": "man"}'
# json.loads讀取字符串並轉爲Python對象
print("json.loads將字符串轉爲Python對象: type(json.loads(s)) = {}".format(type(json.loads(s))))
print("json.loads將字符串轉爲Python對象: json.loads(s) = {}".format(json.loads(s)))
# json.load讀取文件並將文件內容轉爲Python對象
# 數據文件要s.json的內容 --> {"name": "wade", "age": 54, "gender": "man"}
with open('s.json', 'r') as f:
s1 = json.load(f)
print("json.load將文件內容轉爲Python對象: type(json.load(f)) = {}".format(type(s1)))
print("json.load將文件內容轉爲Python對象: json.load(f) = {}".format(s1))
2. 轉換成Python對象
由於loads
和load
兩個方法只是處理的數據源不同,其他的參數都是相同的,返回的結果類型也相同,故這是loads
和load
方法兩個只說一個,
日常工作中最常見的就是把字符串通過json.loads
轉爲字典,其實json的loads
方法不僅可以把字符串轉爲字典,還可以轉爲任何Python對象。
比如說,轉成python
基本數據類型:
print('json.loads 將整數類型的字符串轉爲int類型: type(json.loads("123456"))) --> {}'.format(type(json.loads("123456"))))
print('json.loads 將浮點類型的字符串轉爲float類型: type(json.loads("123.456")) --> {}'.format(type(json.loads("123.456"))))
print('json.loads 將boolean類型的字符串轉爲bool類型: type(json.loads("true")) --> {}'.format((type(json.loads("true")))))
print('json.loads 將列表類型的字符串轉爲列表: type(json.loads(\'["a", "b", "c"]\')) --> {}'.format(type(json.loads('["a", "b", "c"]'))))
print('json.loads 將字典類型的字符串轉爲字典: type(json.loads(\'{"a": 1, "b": 1.2, "c": true, "d": "ddd"}\')) --> %s' % str(type(json.loads('{"a": 1, "b": 1.2, "c": true, "d": "ddd"}'))))
json模塊會根據你的字符串自動轉爲最符合的數據類型,
但是需要注意的是不能把轉爲字符串,否則會報json.decoder.JSONDecodeError
錯誤:
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
3. json.load(s)的參數
我們先看下json.loads方法的簽名:
def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None,
parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):
"""Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON # 把一個字符串反序列化爲Python對象,這個字符串可以是str類型的,也可以是unicode類型的
document) to a Python object.
If ``s`` is a ``str`` instance and is encoded with an ASCII based encoding # 如果參數s是以ASCII編碼的字符串,那麼需要手動通過參數encoding指定編碼方式,
other than utf-8 (e.g. latin-1) then an appropriate ``encoding`` name # 不是以ASCII編碼的字符串,是不被允許的,你必須把它轉爲unicode
must be specified. Encodings that are not ASCII based (such as UCS-2)
are not allowed and should be decoded to ``unicode`` first.
``object_hook`` is an optional function that will be called with the # object_hook參數是可選的,它會將(loads的)返回結果字典替換爲你所指定的類型
result of any object literal decode (a ``dict``). The return value of # 這個功能可以用來實現自定義解碼器,如JSON-RPC
``object_hook`` will be used instead of the ``dict``. This feature
can be used to implement custom decoders (e.g. JSON-RPC class hinting).
``object_pairs_hook`` is an optional function that will be called with the # object_pairs_hook參數是可選的,它會將結果以key-value列表的形式返回
result of any object literal decoded with an ordered list of pairs. The # 形式如:[(k1, v1), (k2, v2), (k3, v3)]
return value of ``object_pairs_hook`` will be used instead of the ``dict``. # 如果object_hook和object_pairs_hook同時指定的話優先返回object_pairs_hook
This feature can be used to implement custom decoders that rely on the
order that the key and value pairs are decoded (for example,
collections.OrderedDict will remember the order of insertion). If
``object_hook`` is also defined, the ``object_pairs_hook`` takes priority.
``parse_float``, if specified, will be called with the string # parse_float參數是可選的,它如果被指定的話,在解碼json字符串的時候,
of every JSON float to be decoded. By default this is equivalent to # 符合float類型的字符串將被轉爲你所指定的,比如說你可以指定爲decimal.Decimal
float(num_str). This can be used to use another datatype or parser
for JSON floats (e.g. decimal.Decimal).
``parse_int``, if specified, will be called with the string # parse_int參數是可選的,它如果被指定的話,在解碼json字符串的時候,
of every JSON int to be decoded. By default this is equivalent to # 符合int類型的字符串將被轉爲你所指定的,比如說你可以指定爲float
int(num_str). This can be used to use another datatype or parser
for JSON integers (e.g. float).
``parse_constant``, if specified, will be called with one of the # parse_constant參數是可選的,它如果被指定的話,在解碼json字符串的時候,
following strings: -Infinity, Infinity, NaN. # 如果出現以以下字符串: -Infinity, Infinity, NaN 那麼指定的parse_constant方法將會被調用到
This can be used to raise an exception if invalid JSON numbers
are encountered.
To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` # 你也可以用cls參數通過實現一個JSONDecoder的子類,來代替JSONDecoder,通過這個功能你可以自定義上面的那些parse_xxx參數,這裏就不舉例了
kwarg; otherwise ``JSONDecoder`` is used.
"""
以下參數說明是根據官方文檔翻譯的
3.1 s參數
把一個字符串反序列化爲Python對象,這個字符串可以是str類型的,也可以是unicode
類型的,如果參數s
是以ASCII
編碼的字符串,那麼需要手動通過參數encoding
指定編碼方式,不是以ASCII
編碼的字符串,是不被允許的,你必須把它轉爲unicode
對於loads
方法來說,s是一個字符串,而對於load
方法來說,是一個數據流文件
3.2 object_hook參數
object_hook
參數是可選的,它會將(loads的)返回結果字典替換爲你所指定的類型,這個功能可以用來實現自定義解碼器,如JSON-RPC
這裏先定義一個Person
對象:
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def toJSON(self):
return {
"name": self.name,
"age": self.age,
"gender": self.gender
}
@staticmethod
def parseJSON(dct):
if isinstance(dct, dict):
p = Person(dct["name"], int(dct['age']), dct['gender'])
return p
return dct
OK,試下object_hook
參數吧:
s = '{"name": "馬雲", "age": 54, "gender": "man"}'
# 測試json.loads方法的object_hook參數
p = json.loads(s, object_hook=Person.parseJSON)
print("json.loads 是否將字符串轉爲字典了: --> " + str(isinstance(p, dict)))
print("json.loads 是否將字符串轉爲Person對象了: --> " + str(isinstance(p, Person)))
3.3 object_pairs_hook參數
object_pairs_hook
參數是可選的,它會將結果以key-value有序列表的形式返回,形式如:[(k1, v1), (k2, v2), (k3, v3)]
,如果object_hook
和object_pairs_hook
同時指定的話優先返回object_pairs_hook
s = '{"name": "馬雲", "age": 54, "gender": "man"}'
# 測試json.loads方法的object_pairs_hook參數
print("-" * 30 + "> test object_pairs_hook <" + "-" * 30)
p = json.loads(s, object_hook=Person.parseJSON, object_pairs_hook=collections.OrderedDict)
# p = json.loads(s, object_hook=Person.parseJSON, object_pairs_hook=Person.parseJSON)
print("json.loads 測試同時指定object_hook和object_pairs_hook,最終調用哪個參數: --> " + str(type(p)))
print("json.loads 指定object_pairs_hook結果將會返回一個有序列表 --> {}".format(p))
3.4 parse_float參數
parse_float
參數是可選的,它如果被指定的話,在解碼json
字符串的時候,符合float
類型的字符串將被轉爲你所指定的,比如說你可以指定爲decimal.Decimal
# 測試json.loads方法的parse_float參數
print("-" * 30 + "> test parse_float <" + "-" * 30)
p = json.loads("123.456", parse_float=decimal.Decimal)
print("json.loads 通過parse_float參數將原本應該轉爲float類型的字符串轉爲decimal類型: type(json.loads(\"123.456\", parse_float=decimal.Decimal)) --> " + str(type(p)))
print("")
3.5 parse_int參數
parse_int
參數是可選的,它如果被指定的話,在解碼json
字符串的時候,符合int
類型的字符串將被轉爲你所指定的,比如說你可以指定爲float
# 測試json.loads方法的parse_int參數
print("-" * 30 + "> test parse_int <" + "-" * 30)
p = json.loads("123", parse_int=float)
print("json.loads 通過parse_int參數將原本應該轉爲int類型的字符串轉爲float類型: type(json.loads(\"123\", parse_int=float)) --> " + str(type(p)))
3.6 parse_constant參數
parse_constant
參數是可選的,它如果被指定的話,在解碼json
字符串的時候,如果出現以以下字符串:-Infinity
,Infinity
,NaN
那麼指定的parse_constant
方法將會被調用到
def transform(s):
"""
此方法作爲參數傳給json.load(s)方法的parse_轉譯NAN, -Infinity,Infinity
:param s:
:return:
"""
# NaN --> not a number
if "NaN" == s:
return "Not a Number"
# 將負無窮大轉爲一個非常小的數
elif "-Infinity" == s:
return -999999
# 將正無窮大轉爲一個非常大的數
elif "Infinity" == s:
return 999999
else:
return s
# 測試json.loads方法的parse_constant參數
print("-" * 30 + "> test parse_constant <" + "-" * 30)
print("json.loads Infinity: --> " + str(json.loads('Infinity')))
print("json.loads parse_constant convert Infinity: --> " + str(json.loads('Infinity', parse_constant=transform_constant)))
print("json.loads -Infinity: --> " + str(json.loads('-Infinity')))
print("json.loads parse_constant convert -Infinity: --> " + str(json.loads('-Infinity', parse_constant=transform_constant)))
print("json.loads NaN: --> " + str(json.loads('NaN')))
print("json.loads parse_constant convert NaN : --> " + str(json.loads('NaN', parse_constant=transform_constant)))
print("")
3.7 cls參數
通過官方文檔的註釋我們可以知道json.load(s)
方法具體的實現是通過JSONCoder
類實現的,而cls
參數是用於自定義一個JSONCoder
的子類,用於替換JSONCoder
類,,通過這個功能你可以自定義上面的那些parse_xxx參數,這裏就不舉例了