Git Product home page Git Product logo

jsonmodel's Introduction

Python Json to Model

1.Python 需要json2model吗?

最近用Python写crash监控预警系统,系统在最开始时,加载请求一个监控需要的配置接口。接口返回一个Json结构的数据,如下:

{
    "projectName": "X项目",
    "projectID": "xproject",
    "administrator": "[email protected]",
    "threshold":30,
    "type":"iOS",
    "needCreateTask":false, 
    "flowTaskName":"FLOWPEO",
    "channels": [
      {
        "channelName": "平台业务",
        "channelID": " PlatPlugin",
        "manager": "[email protected]",
        "threshold":5
      },
      {
        "channelName": "用户评论回复",
        "channelID": " disPlugin",
        "manager": "[email protected]",
        "threshold":5
      }
    ],
    "members": [
      {
        "misID": "[email protected]",
        "channelID": "FoodPlugin",
        "type": "rd"
      },
      {
        "misID": "[email protected]",
        "channelID": "NAN",
        "type": "qa"
      },
      {
        "misID": "[email protected]",
        "channelID": "NAN",
        "type": "leader"
      }
    ]
  }

在使用Java和swift开发时,从接口拿到数据后,紧接着就把它转换为实体类。通过实体类的属性去访问各个信息字段。这样做不仅对IDE友好,输入一个.自动提示有哪些属性。而且可以避免由于拼写造成的crash ,如project['members']写作project['mmembers']。但是Python里默认没有相应的转换功能,我们在写代码时一般如下面这样:

if respond.status_code == 200:
    self.projectConfig = respond.json()
# self.projectConfig 是一个字典(key_value)

于是就有一大堆的 if x in X的判断代码,比如:

if 'channels' in self.projectConfig and len(self.projectConfig['channels']) > 0:
    for channel in self.projectConfig['channels']:

不使用实体类的另外一个缺点就是不能抽象的描述数据,不能将相关的方法与数据结合。比如我们用for channel in self.projectConfig['channels']取出来的channel不是一个对象,这在写代码的时候会十分难受,有一大推的本应该封装在"Channel类“中的操作被放在高层,比如:

def findFirstLevelUsers(self):
        if 'members' in self.mainProject and len(self.mainProject['members']) > 0:
            return map(lambda member: member['misID'],
                       filter(lambda member: member['type'] == 'rd' or member['type'] == 'qa',
                              self.mainProject['members']))
        else:
            return []
"""
这个函数本应该封装在project中,现在要放在预警处理类中,造成预警处理类逻辑很多。程序整体的封装和内聚都很差
"""

所以把json对象对应的字典变成实体类,应该是一个常规需求,在Python中应该也有现成的解决办法。但是由于接触Python时间不长,没有在网上找到十分令人满意的转换方法。

2.现有的json2model方法或框架

搜索到最多的方案是:

class MyClass:  
    #初始化  
    def __init__(self):  
        self.a=2  
        self.b='bb' 
        
myClass2 = MyClass()
myClass2.__dict__ = json.loads(myClassJson)

这种方法有一个很严重的缺陷,就是实体类无法嵌套定义,比如MyClass中包含OtherClass类的属性就不行了。 可以使用下面方法解决这个问题:

load = json.loads(dump,object_hook = dict2object)

但是要每个类都要写一个object_hook函数,对开发人员带来的负担很大。这个问题如此明显,网上应该有相应的框架做了这个事情才对,但不知道是不是我搜索关键词的问题,在github上搜索json model,真的没一个好用的,于是索性自己写一个。(PS:我没有专门深入找过相应的框架,觉得很简单就自己写了,如果有现有的好用的库还请告诉我,多谢)

3.Python Json to Model实现

这种框架在Android和iOS上十分泛滥,各种优缺点的框架都有。总的来说满足代码侵入性低易用性强稳定性高这三点的框架都是好框架。

  • 代码代码侵入性低是指,不要让用户非得继承框架中的某个BaseModel,不要让用户添加或重写某种转换方法
  • 易用性是指让用户非常方便的描述一个对象成员所属的类是哪个,对象数组成员中数组元素所属的类是哪个。(这两点,是所有框架都必须要的,因为无论框架做的再好都要让用户告诉程序这两个信息)
  • 稳定性是指,一个来自文件或网络的json格式是不确定的,框架要保证无论json里面是啥,程序都能正常运行,不崩溃,合理的告诉用户哪里有问题

我写了一个叫JsonModel的小框架,用法大概就如下这样。大家看看是不是满足上面三个特性

import json
from jsonModel import jsonModel

@jsonModel()
class Pet(object):

    def __init__(self):
        self.name = ""

@jsonModel()
class Car(object):

    def __init__(self):
        self.registration_number = ""
        self.engine_capacity = 0.0
        self.color = ""


@jsonModel({"car": Car}, {"pets": Pet})
class Person(object):

    def __init__(self):
        self.name = ""
        self.surname = ""
        self.car = None
        self.pets = []


jsonString = """{
    "car": {
        "color": "red",
        "registration_number": "ASDF777",
        "engine_capacity": 5.0
    },
    "surname": "Bravo",
    "name": "Johny",
    "nickname": "hello",
    "pets": [
        {
            "name": "Garfield"
        },
        {
            "age": 9,
            "name": "Dogmeat"
        }
    ]
}"""

person = Person()

person.fromJson(json.loads(jsonString))  # json to model
print(person.__dict__)

print(json.dumps(person.toKeyValue()))  # model to json

用户通过修饰符对实体类进行修饰就行了,对用户代码的侵入性很低。如果用户想要更换解析框架只要把修饰去除就好了。通过可选的objectMap={}, listClassMap={}参数很简单就可以对映射做出描述。

最后大家看代码吧,总共不超过60行就搞定了,如果大家喜欢给个星星吧~

github链接(https://github.com/hdw09/jsonmodel)。

在使用的过程中有发现需要添加两个针对数组的方法,补充进来,更新的示例如下:

jsonListString = """[{
    "car": {
        "color": "red",
        "registration_number": "ASDF777",
        "engine_capacity": 5.0
    },
    "surname": "Bravo",
    "name": "Johny",
    "nickname": "hello",
    "pets": [
        {
            "name": "Garfield"
        },
        {
            "age": 9,
            "name": "Dogmeat"
        }
    ]
},{
    "car": {
        "color": "red",
        "registration_number": "ASDF777",
        "engine_capacity": 5.0
    },
    "surname": "Bravo",
    "name": "Johny",
    "nickname": "hello",
    "pets": [
        {
            "name": "Garfield"
        },
        {
            "age": 9,
            "name": "Dogmeat"
        }
    ]
},{
    "car": {
        "color": "red",
        "registration_number": "ASDF777",
        "engine_capacity": 5.0
    },
    "surname": "Bravo",
    "name": "Johny",
    "nickname": "hello",
    "pets": [
        {
            "name": "Garfield"
        },
        {
            "age": 9,
            "name": "Dogmeat"
        }
    ]
}]"""


"""
通过调用描述符动态生成Person的类方法objectArrayFromJsonArray()
可以吧json list 直接转换为object list 
"""
personList = Person.objectArrayFromJsonArray(json.loads(jsonListString))
print(personList)
print(json.dumps(personList[0].toKeyValue()))

"""
通过调用描述符动态生成Person的类方法objectArrayToJsonArray()
可以反过来吧object list 转换为 json keyvalue list
"""
print(json.dumps(Person.objectArrayToJsonArray(personList)))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.