【问题标题】:object not json serializable对象不是 json 可序列化的
【发布时间】:2018-12-24 14:53:48
【问题描述】:

在 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

如果我能找到解决这个问题的方法,我会很高兴。提前致谢。

【问题讨论】:

  • 根据[SO]: How to create a Minimal, Complete, and Verifiable example (mcve),该问题缺少一些必需的数据。例如,所有文件都不应编译:for a in A_set:self.property_A = property_A。请更正问题并添加堆栈跟踪。并编辑问题,不要添加 cmets。
  • 嗯,这是一个很长的脚本,它正在从 excel 文件中读取数据并希望将其转换为 json 格式。生成一个最小且完整的代码有点困难,但我会试一试。然而,第二个代码块是我的第二个文件的完整代码。感谢您的回复。

标签: python json serialization


【解决方案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 格式,只需将空格从“property A”替换为“property_A”(其他属性相同)。此外,您可以将“名称”更改为小写的“名称”。

为什么?因为使用这种格式,以及我更改的__init__() 方法,您可以使用解包操作将您的from_json() 转换为以下内容:

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

【讨论】:

  • 嗯,是的。错误的类型让我没有在自己的代码中仔细搜索解决方案。甚至错误是在一条很明显没有任何错误的行中产生的。但是不熟悉 ool 的概念,我会犯这样的错误。现在代码可以正常工作了。非常感谢您的回复以及您花费的时间。
  • 很遗憾,答案中的代码比问题中的代码更不正确。
  • 如果完全准确:是的,我在回答的第一个版本中非常肤浅和仓促。我希望我澄清了编辑中的所有内容。
【解决方案2】:

这是您的代码的修改(和工作)版本。

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_aprop_b都是字符串(不是很重要)
  • (主要)问题出在 from_json 函数中(我不确定您在那里尝试做什么:为什么会有这么多 myObject 实例化,什么时候应该有只有一个)。无论如何,它现在做了什么:
    1. json_data获取nameprop_aprop_b属性(这是一个dict em>)
    2. #1 的 3 个值中构造对象。
    3. prop_c读取对象,并将它们一一添加(如果有的话)到对象中(通过调用add_c_element
  • 程序搜索文件(带有 json 内容):
    • 如果找到,它会尝试从中加载对象并显示它
    • 如果找不到,它会创建一个虚拟对象并将其转储到文件中
  • 这是一种(不是很好)的做事方式。它意味着需要最少的代码更改,并且也用于学习目的。正确的(可扩展的、通用的)方式是扩展JSONEncoderJSONDecoder[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.

【讨论】:

  • 非常感谢。关键终于如您在类方法中所说的那样,我的错误是属性应该从 json_data 而不是从新对象创建中获取它们的值。其实这就是我想要的。但是由于错误发生在离那一点几行的地方,我错过了它。关于脚本的代码,我会看一下,我可能会将它作为一部分或整体使用。再次感谢!
猜你喜欢
  • 2012-07-02
  • 2013-05-23
  • 2015-02-24
  • 2014-10-23
  • 1970-01-01
  • 1970-01-01
  • 2018-09-12
  • 2018-08-16
  • 2016-03-03
相关资源
最近更新 更多