📜  python-json 6: 读取json数据并转化为Python对象

📅  最后修改于: 2020-09-27 03:27:32             🧑  作者: Mango

在本系列的学习中,我们学习过如何将Python自定义的类转为Json数据进行存储/传输

在这次学习中,我们学习一下其相反的操作,如何解析Json的数据并转换为python对象。例如,您从AP/从文件中读取到JSON数据,希望将其转换为自定义的Employee类型。

当使用json.load/json.loads方法从文件或字符串加载JSON数据时,它将返回python Dict,如果能将JSON数据直接加载到我们的自定义类型中,我们可以轻松地进行操作和使用。

1. 使用namedtuple和object_hook转换JSON数据为Python对象

我们可以使用load/loads方法的object_hook 参数,其实可以理解因为一个函数,任何对象解码的结果都会调用它;因此,当我们执行时json.load的时候,object_hook返回值将被使用,而不是Python的dict。

如何将JSON转换为自定义Python类型?

load/loads方法只能将JSON转换为dict对象,因此我们需要创建一个自定义函数并将这个新创建的函数传递json.loads方法的object_hook参数。

namedtuple是一个类,位于Python的collections之中,像字典类型的对象一样,它包含键,并映射到某些值。在这种情况下,我们可以使用键和索引访问元素,如果对namedtuple不熟悉的小伙伴,可参考https://www.runoob.com/note/25726

我们以例子说明,将Student JSON数据转换为自定义的Student Class类型。

import json
from collections import namedtuple
from json import JSONEncoder

def customStudentDecoder(studentDict):
    return namedtuple('X', studentDict.keys())(*studentDict.values())

#Assume you received this JSON response
studentJsonData = '{"rollNumber": 1, "name": "Emma"}'

# Parse JSON into an object with attributes corresponding to dict keys.
student = json.loads(studentJsonData, object_hook=customStudentDecoder)

print("After Converting JSON Data into Custom Python Object")
print(student.rollNumber, student.name)

我们看看打印的输出:真是我们想要的结果

After Converting JSON Data into Custom Python Object
1 Emma

现在,让我们学习稍微复杂示例。而且我们需要将自定义Python对象转换为JSON,同时我们想从JSON构造一个自定义Python对象

在此示例中,我们使用两个类Student和Marks。Marks类是Student类的成员。

  • 首先,我们将Student类编码为JSON数据。
  • 然后,我们使用相同的JSON数据将其解码为Student类
import json
from collections import namedtuple
from json import JSONEncoder

class Student:
    def __init__(self, rollNumber, name, marks):
        self.rollNumber, self.name, self.marks = rollNumber, name, marks

class Marks:
    def __init__(self, english, geometry):
        self.english, self.geometry = english, geometry

class StudentEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__

def customStudentDecoder(studentDict):
    return namedtuple('X', studentDict.keys())(*studentDict.values())

marks = Marks(82, 74)
student = Student(1, "Emma", marks)

# dumps() produces JSON in native str format. if you want to writ it in file use dump()
studentJson = json.dumps(student, indent=4, cls=StudentEncoder)
print("Student JSON")
print(studentJson)

# Parse JSON into an object with attributes corresponding to dict keys.
studObj = json.loads(studentJson, object_hook=customStudentDecoder)

print("After Converting JSON Data into Custom Python Object")
print(studObj.rollNumber, studObj.name, studObj.marks.english, studObj.marks.geometry)

输出结果:

Student JSON
{
    "rollNumber": 1,
    "name": "Emma",
    "marks": {
        "english": 82,
        "geometry": 74
    }
}
After Converting JSON Data into Custom Python Object
1 Emma 82 74

上面两种方法,实现了将Json数据转化为Python中的namedtuple对象。

使用types.SimpleNamespace和object_hook转换JSON数据自定义对象

我们可以types.SimpleNamespace作为JSON对象的容器,与namedtuple相比,它具有以下优点:

  • 它的执行时间较少,因为它不会为每个对象创建一个类。
  • 精确而简单
    from __future__ import print_function
    import json
    from json import JSONEncoder
    try:
        from types import SimpleNamespace as Namespace
    except ImportError:
        # Python 2.x fallback
        from argparse import Namespace
    
    class Student:
        def __init__(self, rollNumber, name, marks):
            self.rollNumber, self.name, self.marks = rollNumber, name, marks
    
    class Marks:
        def __init__(self, english, geometry):
            self.english, self.geometry = english, geometry
    
    class StudentEncoder(JSONEncoder):
            def default(self, o): return o.__dict__
    
    marks = Marks(82, 74)
    student = Student(1, "Emma", marks)
    
    # dumps() produces JSON in native str format. if you want to writ it in file use dump()
    studentJsonData = json.dumps(student, indent=4, cls=StudentEncoder)
    print("Student JSON")
    print(studentJsonData)
    
    # Parse JSON into an custom Student object.
    studObj = json.loads(studentJsonData, object_hook=lambda d: Namespace(**d))
    print("After Converting JSON Data into Custom Python Object using SimpleNamespace")
    print(studObj.rollNumber, studObj.name, studObj.marks.english, studObj.marks.geometry)

    输出如下:输出结果和之前的方法一致,但不需要创建一个类

    Student JSON
    {
        "rollNumber": 1,
        "name": "Emma",
        "marks": {
            "english": 82,
            "geometry": 74
        }
    }
    After Converting JSON Data into Custom Python Object using SimpleNamespace
    1 Emma 82 7

使用JSONDecoder类的对象解码转换JSON数据为自定义对象

可以使用json.JSONDecoder对JSON对象解码,我们需要在类中创建一个新函数,该类将负责检查JSON字符串中的对象类型,在JSON数据中获取正确的类型之后,我们可以构造Object。

import json

class Student(object):
    def __init__(self, rollNumber, name, marks):
        self.rollNumber = rollNumber
        self.name = name
        self.marks = marks

def studentDecoder(obj):
    if '__type__' in obj and obj['__type__'] == 'Student':
        return Student(obj['rollNumber'], obj['name'], obj['marks'])
    return obj

studentObj = json.loads('{"__type__": "Student", "rollNumber":1, "name": "Ault kelly", "marks": 78}',
           object_hook=studentDecoder)

print("Type of decoded object from JSON Data")
print(type(studentObj))
print("Student Details")
print(studentObj.rollNumber, studentObj.name, studentObj.marks)

代码输出:

Type of decoded object from JSON Data

Student Details
1 Ault kelly 78

使用jsonpickle模块转换JSON数据为自定义对象

使用jsonpickle,我们将执行以下操作:

  • 首先,我们将使用jsonpickle将Student Object编码为JSON
  • 然后我们将学生JSON解码为学生对象
import json
import jsonpickle
from json import JSONEncoder

class Student(object):
    def __init__(self, rollNumber, name, marks):
        self.rollNumber = rollNumber
        self.name = name
        self.marks = marks

class Marks(object):
    def __init__(self, english, geometry):
        self.english = english
        self.geometry = geometry

marks = Marks(82, 74)
student = Student(1, "Emma", marks)

print("Encode Object into JSON formatted Data using jsonpickle")
studentJSON = jsonpickle.encode(student)
print(studentJSON)

print("Decode and Convert JSON into Object using jsonpickle")
studentObject = jsonpickle.decode(studentJSON)
print("Object type is: ", type(studentObject))

print("Student Details")
print(studentObject.rollNumber, studentObject.name, studentObject.marks.english, studentObject.marks.geometry)

输出如下所示:此方法就不需要专门的写 JSONEncoder and Decoder了

Encode Object into JSON formatted Data using jsonpickle
{"marks": {"english": 82, "geometry": 74, "py/object": "__main__.Marks"}, "name": "Emma", "py/object": "__main__.Student", "rollNumber": 1}
Decode JSON formatted Data using jsonpickle
1 Emma 82 74

自己定义转换方法

众所周知json.loads(),json.load()方法返回一个dict对象,那么我们可以通过将dict对象作为参数传递给我们自己的一个函数,在函数中我们解码为我们自定义对象。

import json
from json import JSONEncoder

class Student(object):
    def __init__(self, rollNumber, name, *args, **kwargs):
        self.rollNumber = rollNumber
        self.name = name

class StudentEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__

student = Student(1, "Emma")

# encode Object it
studentJson = json.dumps(student, cls=StudentEncoder, indent=4)

#Deconde JSON
resultDict = json.loads(studentJson)

print("Converting JSON into Python Object")
studentObj = Student(**resultDict)

print("Object type is: ", type(studentObj))

print("Student Details")
print(studentObj.rollNumber, studentObj.name)

输出如下:

Converting JSON into Python Object
Object type is:  
Student Details
1 Emma

 

——-》》》关于讲Json数据转化为自定义对象的方法介绍就这么多,感谢你的阅读。