对象无法json序列化

时间:2018-12-24 14:53:49

标签: python json serialization

在python中编码时,出现错误:“类型myObject的对象不可JSON序列化”

我尝试使用在其他问题中看到的一些解决方案,但是在这些问题中我的代码与代码之间没有发现很多相似之处,因此我发现很难在我的代码中适应这些解决方案。

我的脚本的一部分如下。错误发生在第一个块的最后一行:

import json
import os
from my_object import myObject

for a in A_set:
    if os.path.isfile(filename):
        with open(filename, 'r') as f:
            json_data = json.load(f)
        object_name = myObject.from_json(json_data)
    else:
        object_name = myObject(a)
        object_name.property_A = property_A
        object_name.property_C = []

    object_name.property_C_add_elements(var)
    with open(filename, 'w') as f:
        json.dump(object_name.to_json(), f)

在另一个python文件中定义了“ myObject”类,其中还有方法“ to_json()”,我正在产生错误的代码行中对其进行调用。

class myObject:
    def __init__(self, name):
        self.name = name
        self.property_A = property_A
        self.property_B = property_B
        self.property_C = []

    def property_C_add_elements(self, var):  
        self.property_C.append(var)

    def to_json(self):
        return {
            'Name': self.name,
            'property A': self.property_A,
            'property B': self.property_B,
            'property C': self.property_C
        }

    @classmethod
    def from_json(cls, jason_data):
        object_name = myObject(jason_data['property A'])
        property_B = myObject(jason_data['property B'])
        c_list = []
        for var in jason_data['property C']:
            c_list.append(myObject(var))

        object_name.property_B = property_B
        object_name.property_C = c_list

        return object_name

如果能找到解决该问题的方法,我将感到非常高兴。预先感谢。

2 个答案:

答案 0 :(得分:0)

这是您代码的修改(且有效)版本。

custom_object.py

class CustomObject:

    @classmethod
    def from_json(cls, json_data):
        name = json_data["Name"]
        prop_a = json_data["PropertyA"]
        prop_b = json_data["PropertyB"]
        obj = cls(name, prop_a=prop_a, prop_b=prop_b)
        for var in json_data["PropertyC"]:
            obj.add_c_element(var)
        return obj

    def __init__(self, name, prop_a="", prop_b=""):
        self.name = name
        self.prop_a = prop_a
        self.prop_b = prop_a
        self.prop_c = list()

    def add_c_element(self, var):
        self.prop_c.append(var)

    def to_json(self):
        return {
            "Name": self.name,
            "PropertyA": self.prop_a,
            "PropertyB": self.prop_b,
            "PropertyC": self.prop_c,
        }

code.py

#!/usr/bin/env python3

import sys
import json
import os
from custom_object import CustomObject


def main():
    filename = "./data.json"
    if os.path.isfile(filename):
        print("Attempting to load object from json file...")
        with open(filename, "r") as f:
            json_data = json.load(f)
            try:
                obj = CustomObject.from_json(json_data)
            except Exception as e:
                print(e)
                return
            print("Object: {:}\n  Class: {:s}\n  Attributes:" .format(obj, obj.__class__.__name__))
            for k, v in getattr(obj, "__dict__", dict()).items():
                print("    {:s}: {:}".format(k, v))

    else:
        print("Creating dummy object and saving to json...")
        obj = CustomObject("Object name", prop_a="object property a", prop_b="object property b")
        obj.add_c_element(1)
        obj.add_c_element("c element 2")
        with open(filename, "w") as f:
            json.dump(obj.to_json(), f)
    print("Done.")


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

注释

  • 更正了错误(或添加了丢失的数据)
  • 为清楚起见,做了一些重命名(类,对象,属性)
  • 假设 prop_a prop_b 是字符串(不是很重要)
  • (主要)问题出在 from_json 函数中(我不确定您尝试在其中执行什么:为什么应该有那么多 myObject 实例化?只有一个)。无论如何,现在它会做什么:
    1. json_data (这是一个 dict )获取 name prop_a prop_b 属性em>)
    2. #1的3个值中构造对象。
    3. 读取 prop_c 的对象,并将它们(如果有的话)一个一个地添加(通过调用 add_c_element
  • 程序搜索文件(具有 json 内容):
    • 如果找到,它将尝试从中加载并显示对象
    • 如果找不到,它将创建一个虚拟对象并将其转储到文件中
  • 这是一种的方式(不是很好)。这意味着需要最少的代码更改,也用于学习目的。正确的(可扩展的,通用的)方法是扩展 JSONEncoder JSONDecoder [Python 3]: json - JSON encoder and decoder),但是我觉得这有点太先进了点

输出

(py35x64_test) e:\Work\Dev\StackOverflow\q053914912>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py
Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32

Creating dummy object and saving to json...
Done.

(py35x64_test) e:\Work\Dev\StackOverflow\q053914912>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py
Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32

Attempting to load object from json file...
Object: <custom_object.CustomObject object at 0x00000230B6182C88>
  Class: CustomObject
  Attributes:
    prop_a: object property a
    prop_b: object property a
    name: Object name
    prop_c: [1, 'c element 2']
Done.

答案 1 :(得分:-1)

根据您提供的代码,我只能推测您的property_A, property_B, property_C变量/属性到底是什么类型

@classmethod
def from_json(cls, jason_data):
    object_name = myObject(jason_data['property A'])
    property_B = myObject(jason_data['property B'])
    c_list = []
    for var in jason_data['property C']:
        c_list.append(myObject(var))

    object_name.property_B = property_B
    object_name.property_C = c_list

    return object_name

让我推测您的属性是Classinstances,它们对如何将其序列化为JSON没有“定义”。这是由您所说的:

  

“类型为myObject的对象不可JSON序列化”

我猜问题出在from_json()类方法上,您可能应该做一下。就像:

已编辑

假设您的Class的__init__()方法如下所示

def __init__(self, name, property_A, property_B, property_C):
    self.name = name
    self.property_A = property_A
    self.property_B = property_B
    self.property_C = property_C 
    # property_C should be a list, you may want to add validation method 
    # which checks for correct types if it is preocess cirtical

我建议以下内容:

@classmethod
def from_json(cls, jason_data):
    return cls(
               jason_data['name'],
               jason_data['property A'],
               jason_data['property B'],
               jason_data['property C']
               ) 

此外,如果可以的话,我建议您更改to_json()方法中提供的JSON格式,只需将空白从“属性A”替换为“ property_A”(其他属性相同)。另外,您可以将“名称”更改为小写的“名称”。

为什么?因为使用这种格式,并且我更改了__init__()方法,所以可以使用拆包操作将from_json()转换为以下内容:

@classmethod
def from_json(cls, jason_data):
    return cls(**json_data)