JOSN字符串转换为自定义类实例对象有时候我们有这种需求就是把一个JSON字符串转换为一个具体的Python类的实例,比如你接收到这样一个JSON字符串如下:{Name:
JOSN字符串将转换为自定义类实例对象
有这样的需求,就是将JSON字符串转换为特定的Python类的实例。 例如,假设接收到如下所示的JSON字符串:
“名字”:“汤姆”,“第二季”:“马尔”,“布罗德类型”:“a”,“Hobbies': [“篮球”,“足球”
需要将其转换为具体的人员类实例,然后以对象方式进行操作。 Java有Gson和FastJosn等许多实现。 下面的代码类似。 这里不是所有的代码,值表示最主要的部分。
import com.Alibaba.fast JSon.JSon对象;
import com.example.demo.entity .产品;
stringa=' {\' GMT创建\ ' :1559009853000,\ '数据格式\ ' :1,\ '设备计数\ ' :1,\ '节点
//JSON字符串逆序列化为Product对象
产品产品=JSon对象.透视对象(a,产品.类);
上述需求一般在JSON字符串和其他系统进行RPC通信时从前一级发送。 作为接收方,需要逆序列化为对象进行处理。 此外,Fastjson还提供了可以转换为对象列表的JSONArray.parseArray方法。 但是,Python没有像Java那样方便的东西。
我从网络留言板上也看到了几个,虽然有效果,但是使用起来很多很麻烦,所以在这里也谈谈我的想法。
用josn.loads的方式实现
# #! /usr/舒适的刺猬/env python
# #-* -编码: utf-8-* -
导入系统
导入JSON
类人:
def _ init _ (自我,数据=无) :
自助式名称='1'
瑟夫. _萨克斯=' '
瑟夫. _布罗德_类型=' o '
self._hobbies=[]
自身日期=' 1900/1/1 '
if数据:
self._ _光盘=数据
通过# # #属性获取并设定实例变量的值。 否则,只能使用set或get方法
@property
更新(自助) :
返回自我日期
@date_of_brith.setter
date_of_brith (自我,日期_ of _ brith ) :
self._ date _ of _ birth=日期_ of _ brith
defmain(: )
try:
str1='{'name': 'Tom ',' sex': 'male ',' blood_type': 'A ',' hobbies': [ '篮球]
Person1=JSON.loads(str1,对象_人=人) ) ) ) ) )。
打印(isinstance (人员1,人员) )
# #在此,您会发现没有名为date_of_brith的内容
打印(人员1._ _光盘_ )
获取date_of_brith属性值时出错。 JSON字符串不包含此键,但类中的实例变量有此键。 通常应该可以获取默认值,但因此
因为替换了#__dict__,所以不见了。 __dict__本来就是实例变量的词典格式,所以替换后也找不到原来的。
# # print (个人日期印刷)。
# #接下来,用常规方法实例化对象
人员2=人员()
打印(人员2._ _光盘_ )
print (人员2 .日期_日期_分布) )。
except Exception as err:
是打印(err )
if __name__=='__main__':
try:
主() )
finally:
sys.exit () )
object_hook是指缺省的json.loads ) )返回dict的意思。 可以使用object_hook返回其他类型的值。 此处实现的原理是将传递的JSON字符串传递给object_hook指定的方法或类() ) ) ) ) ) )。此时,在类的__init方法中,为self . 除非JSON字符串的键和实例变量的名称和数量匹配,否则无法从类中定义的实例变量名称中获取通过JSON字符串传递的值。 下图:
p>
所以通过上面可以看出来,这个过程不是为实例变量赋值的过程而是一个替换的过程,Python是动态语言这一点和JAVA不同。如果你在程序中用单下划线标识变量为私有(只是规范而不是真正的私有)那么你传递的JSON字符串的键也需要有下划线,这样你通过实例的方法才能获取。既然额外增加下划线不太现实,那么有没有其他办法呢?看方式2
方式2:通过反射机制来实现
先看一下类的定义
#!/usr/舒服的小刺猬/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__
# 当一个方法加上这个装饰器之后,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
下面看看转换的方法
#!/usr/舒服的小刺猬/env python
# -*- coding: utf-8 -*-
import sys
import json
import importlib
def get_instance(str_stream, class_full_path=None):
"""
: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个参数,第一个是类,第二个是fromlist,如果不写fromlist,则按照下面的写法会只导入AAA包,如果fromlist有值则会导入AAA下面的Classes模块 cc = __import__("AAA.Classes", fromlist=True) 不写fromlist 相当于 import AAA ,如果写了就相当于是 from AAA import Classes 编程时如果使用动态加载建议使用 importlib.import_module() ,而不是 __import__()。
下面看一下效果:
可以看到,这样操作之后就是给实例变量赋值而不是像之前那样的替换,而且保留了类中实例变量的私有规范。不过需要说明的是JSON字符串中的键名称要和类里面定义的属性名称一样,也就是键名称要和类中@property装饰的方法同名。我们也可以看到这种使用方式也有默认JSONObject.parseObject的意思。
不过这只是一个简单的实现,只能通过单一JSON字符串生成对象不能生成对象列表。当然有兴趣的朋友可以自己根据这个思路进行扩展。
另外既然无论是loads还是我自己的方法搜需要保证JSON字符串的键和变量名称一致大家就不要纠结于名称一致的问题,但是我的方法做到了保持实例变量命名、操作实例属性时候的规范,同时对类也没有过多的入侵性而不像loads方法中还需要在类的init方法里面增加不必要的内容。在我这个方法中如果能实现忽略大小写通用性就更好了。欢迎大家来提供思路。最后小编个人有六年开发经验,我自己有做python材料的整合,一个完整的python编程学习路线,学习资料和工具。想要这些资料的可以关注小编,并在后台私信:发送“01”领取,希望能帮助到你。
极速赛车买前5名的方法 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个参数,第一个是类,第二个是fromlist,如果不写fromlist,则按照下面的写法会只导入AAA包,如果fromlist有值则会导入AAA下面的Classes模块 cc = __import__("AAA.Classes", fromlist=True) 不写fromlist 相当于 import AAA ,如果写了就相当于是 from AAA import Classes 编程时如果使用动态加载建议使用 importlib.import_module() ,而不是 __import__()。
下面看一下效果:
可以看到,这样操作之后就是给实例变量赋值而不是像之前那样的替换,而且保留了类中实例变量的私有规范。不过需要说明的是JSON字符串中的键名称要和类里面定义的属性名称一样,也就是键名称要和类中@property装饰的方法同名。我们也可以看到这种使用方式也有默认JSONObject.parseObject的意思。
不过这只是一个简单的实现,只能通过单一JSON字符串生成对象不能生成对象列表。当然有兴趣的朋友可以自己根据这个思路进行扩展。
另外既然无论是loads还是我自己的方法搜需要保证JSON字符串的键和变量名称一致大家就不要纠结于名称一致的问题,但是我的方法做到了保持实例变量命名、操作实例属性时候的规范,同时对类也没有过多的入侵性而不像loads方法中还需要在类的init方法里面增加不必要的内容。在我这个方法中如果能实现忽略大小写通用性就更好了。欢迎大家来提供思路。最后小编个人有六年开发经验,我自己有做python材料的整合,一个完整的python编程学习路线,学习资料和工具。想要这些资料的可以关注小编,并在后台私信:发送“01”领取,希望能帮助到你。