本篇內(nèi)容主要講解“JSON數(shù)據(jù)格式轉(zhuǎn)換為Python的類對象方法有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“JSON數(shù)據(jù)格式轉(zhuǎn)換為Python的類對象方法有哪些”吧!
創(chuàng)新互聯(lián)建站專業(yè)IDC數(shù)據(jù)服務(wù)器托管提供商,專業(yè)提供成都服務(wù)器托管,服務(wù)器租用,西云機房,西云機房,成都多線服務(wù)器托管等服務(wù)器托管服務(wù)。有時候我們有這種需求就是把一個JSON字符串轉(zhuǎn)換為一個具體的Python類的實例,比如你接收到這樣一個JSON字符串如下:
{"Name": "Tom", "Sex": "Male", "BloodType": "A", "Hobbies": ["籃球", "足球"]}
我需要把這個轉(zhuǎn)換為具體的一個Person類的實例,通過對象的方式來進行操作。在Java中有很多實現(xiàn)比如Gson或者FastJosn。如下代碼所示(這里不是全部代碼,值標(biāo)識最主要的部分):
import com.alibaba.fastjson.JSONObject;
import com.example.demo.entity.Product;
String a = "{\"gmtCreate\":1559009853000,\"dataFormat\":1,\"deviceCount\":1,\"nodeType\":0,\"productKey\":\"a1U85pSQrAz\",\"productName\":\"溫度計\"}";
//JSON字符串反序列化為一個Product對象
Product product = JSONObject.parseObject(a, Product.class);
上述這種需求一般發(fā)生在前段傳遞過來JSON字符串或者其他系統(tǒng)進行RPC通信的時候也發(fā)送過來JSON字符串,作為接收端需要反序列化成對象來進行處理,而且Fastjson里還有一個JSONArray.parseArray方法可以轉(zhuǎn)換為對象列表??墒窃赑ython沒有像Java中這么方便的東西。
從網(wǎng)上論壇中也看到過一些,不過很多都是效果有但是使用起來麻煩,所以我這里也來說一下我的思路。
方式1:通過josn.loads來實現(xiàn)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import json
class Person:
def __init__(self, data=None):
self._name = "1"
self._sex = ""
self._blood_type = "O"
self._hobbies = []
self._date_of_birth = "1900/1/1"
if data:
self.__dict__ = data
# 通過屬性的方式來獲取和設(shè)置實例變量的值,如果不這樣那么就只能通過set或者get方法來做
@property
def date_of_brith(self):
return self._date_of_birth
@date_of_brith.setter
def date_of_brith(self, date_of_brith):
self._date_of_birth = date_of_brith
def main():
try:
str1 = '{"name": "Tom", "sex": "male", "blood_type": "A", "hobbies": ["籃球", "足球"]}'
person1 = json.loads(str1, object_hook=Person)
print(isinstance(person1, Person))
# 這里你會發(fā)現(xiàn)沒有date_of_brith這個內(nèi)容
print(person1.__dict__)
# 獲取date_of_brith屬性值報錯,因為JSON字符串不包含這個鍵,但是類中的實例變量有這個,正常來講你應(yīng)該可以獲取默認(rèn)值,但是由于
# 替換了__dict__,所以就沒有了,因為__dict__原本就是實例變量的字典形式,你替換了自然也就找不到原來的了。
# print(person.date_of_brith)
# 下面我們通過正常的方式實例化一個對象
person2 = Person()
print(person2.__dict__)
print(person2.date_of_brith)
except Exception as err:
print(err)
if __name__ == "__main__":
try:
main()
finally:
sys.exit()
object_hook的含義是,默認(rèn)json.loads()返回的是dict,你可以使用object_hook來讓其返回其他類型的值,它這里實現(xiàn)的原理就是把你傳遞進來的JSON字符串傳遞給了object_hook指定的方法或者類(如果是類的話則會執(zhí)行__init__方法,其實就是實例化),這時候在類的__init方法中我們通過賦值給self.dict__,其實這就等于對Person類的實例變量做了替換,除非你的JSON字符串的鍵和實例變量的名稱以及數(shù)量一致否則你無法通過你在類里定義的實例變量名稱獲取通過JSON字符串傳遞進去的值。
所以通過上面可以看出來,這個過程不是為實例變量賦值的過程而是一個替換的過程,Python是動態(tài)語言這一點和JAVA不同。如果你在程序中用單下劃線標(biāo)識變量為私有(只是規(guī)范而不是真正的私有)那么你傳遞的JSON字符串的鍵也需要有下劃線,這樣你通過實例的方法才能獲取。既然額外增加下劃線不太現(xiàn)實,那么有沒有其他辦法呢?看方式2
方式2:通過反射機制來實現(xiàn)
先看一下類的定義
#!/usr/bin/env python
# -*- coding: utf-8 -*-
class Person:
def __init__(self):
self._name = "1"
self._sex = ""
self._blood_type = "O"
self._hobbies = []
self._date_of_birth = "1900/1/1"
def __str__(self):
"""
輸出實例的類名字,而不是一個地址
:return: 該實例的類名字
"""
return self.__class__.__name__
# 當(dāng)一個方法加上這個裝飾器之后,hasattr()中的屬性要寫成這個方法的名稱,而不是實例變量的名稱。
# 如果不加這個裝飾器,那么hasattr()中的屬性名稱要和實例變量的名稱保持一致
@property
def Name(self):
return self._name
@Name.setter
def Name(self, name):
self._name = name
@property
def Sex(self):
return self._sex
@Sex.setter
def Sex(self, sex):
self._sex = sex
@property
def BloodType(self):
return self._blood_type
@BloodType.setter
def BloodType(self, blood_type):
self._blood_type = blood_type
@property
def Hobbies(self):
return self._hobbies
@Hobbies.setter
def Hobbies(self, hobbies):
self._hobbies = hobbies
@property
def date_of_brith(self):
return self._date_of_birth
@date_of_brith.setter
def date_of_brith(self, date_of_brith):
self._date_of_birth = date_of_brith
下面看看轉(zhuǎn)換的方法
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import json
import importlib
def get_instance(str_stream, class_full_path=None):
"""鄭州人流手術(shù)費用 http://www.zzzzyy120.com/
:param str_stream: json的字符串形式 '{"Name": "Tom", "Sex": "Male", "BloodType": "A"}'
:param class_full_path: package.module.class
:return:
"""
try:
json_obj = json.loads(str_stream)
except Exception as err:
print("輸入的字符串不符合JSON格式,請檢查。")
return None
if class_full_path is None:
return json_obj
else:
try:
# 獲取模塊路徑
module_path = ".".join(class_full_path.split(".")[0:-1])
# 獲取類名稱
class_name = class_full_path.split(".")[-1]
# 通過模塊名加載模塊
CC = importlib.import_module(module_path)
# 判斷是否有class_name所代表的屬性
if hasattr(CC, class_name):
# 獲取模塊中屬性
temp_obj = getattr(CC, class_name)
# 實例化對象
obj = temp_obj()
for key in json_obj.keys():
obj.__setattr__(key, json_obj[key])
return obj
else:
pass
except Exception as err:
print(err)
return None
def main():
try:
str1 = '{"Name": "Tom", "Sex": "Male", "BloodType": "A", "Hobbies": ["籃球", "足球"]}'
person1 = get_instance(str1, class_full_path="AAA.Classes.Person")
# 查看類型
print(type(person1))
# 查看屬性
print(person1.__dict__)
# 查看指定屬性
print(person1.Name)
except Exception as err:
print(err)
if __name__ == "__main__":
try:
main()
finally:
sys.exit()
import() 有2個參數(shù),第一個是類,第二個是fromlist,如果不寫fromlist,則按照下面的寫法會只導(dǎo)入AAA包,如果fromlist有值則會導(dǎo)入AAA下面的Classes模塊cc = import(“AAA.Classes”, fromlist=True)不寫fromlist 相當(dāng)于 import AAA ,如果寫了就相當(dāng)于是from AAA import Classes編程時如果使用動態(tài)加載建議使用importlib.import_module(),而不是__import__()。
得出效果
可以看到,這樣操作之后就是給實例變量賦值而不是像之前那樣的替換,而且保留了類中實例變量的私有規(guī)范。不過需要說明的是JSON字符串中的鍵名稱要和類里面定義的屬性名稱一樣,也就是鍵名稱要和類中@property裝飾的方法同名。我們也可以看到這種使用方式也有默認(rèn)JSONObject.parseObject的意思。
到此,相信大家對“JSON數(shù)據(jù)格式轉(zhuǎn)換為Python的類對象方法有哪些”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!