如何在python中将嵌套对象转换为嵌套字典

问题描述

我有一个对象Traceback (most recent call last): File ".import.py",line 17,in <module> modules.append(importlib.import_module(auto,Package=enum)) ,其ID,scene_info和rating等字段如下。可以看出,对象具有属于其他类EntryScene的类型的属性。我想将此对象转换为字典。

Item

Entry(id=None,scene_info=Scene(Recipes=[Item(ID='rec.chicky-nuggies',SpawnerIdx=0),Item(ID='rec.impossible-burger',SpawnerIdx=1)],Decor=[Item(ID='dec.plate-large-orange',SpawnerIdx=2),Item(ID='dec.plate-small-green',SpawnerIdx=3)]),rating=None) (Pdb) vars(self) {'id': None,'scene_info': Scene(Recipes=[Item(ID='rec.chicky-nuggies',SpawnerIndex=0),'rating': None}

EXPECTED RESULT

我尝试了{'id': None,'scene_info':{'Recipes': [{'ID': 'rec.chicky-nuggies','SpawnerIdx': 0},{'ID': 'rec.impossible-burger','SpawnerIdx': 1}],'Decor': [{'ID': 'dec.plate-large-orange','SpawnerIndex': 2},{'ID': 'dec.plate-small-green','SpawnerIdx': 3}]},'rating': None} ,他们只将外部对象转换为dict,而不将内部对象转换为dict。如何转换嵌套的?

解决方法

我通常这样做:

class Bar:
    # child class
    # some init code...

    def encode(self):
        return vars(self)

class Foo:
    # parent class
    # some init code...

    def encode(self):
        return vars(self)

    def to_json(self,indent=None):
        return json.dumps(self,default=lambda o: o.encode(),indent=indent)

to_json()将为您提供该类及其嵌套对象的json字符串(如果它们足够简单),您也可以使用棉花糖通过更多控制来做到这一点。您可以只在父类中执行return json.dumps(self,default=lambda o: vars(o),indent=indent),而没有encode()方法,但是使用encode方法可以自定义输出。

下面是一些随机的,愚蠢的代码,以显示其用法和输出:

import json


class Ingredient:
    def __init__(self,name,cost=0):
        self.name = name
        self.cost = cost

    def encode(self):
        return vars(self)


class Recipe:
    def __init__(self,prep_time=0,cook_time=0,ingredients=None,instructions=None):
        self.name = name
        self.prep_time = prep_time
        self.cook_time = cook_time
        self.ingredients = ingredients or []
        self.instructions = instructions or {}

    def encode(self):
        return vars(self)

    def to_json(self,indent=indent)


lettuce = Ingredient('Lettuce',1.3)
tomato = Ingredient('Tomato',5.2)

salad = Recipe('Salad',prep_time=5,cook_time=0)

salad.ingredients = [
    lettuce,tomato
]

salad.instructions = {
    'Step 1': 'Get the ingredients out','Step 2': 'Mix tem together','Step 3': 'Eat' 
}

print(salad.to_json(4))

输出:

{
    "name": "Salad","prep_time": 5,"cook_time": 0,"ingredients": [
        {
            "name": "Lettuce","cost": 1.3
        },{
            "name": "Tomato","cost": 5.2
        }
    ],"instructions": {
        "Step 1": "Get the ingredients out","Step 2": "Mix tem together","Step 3": "Eat"
    }
}
,

对于类类型(Entry \ Scene \ Item),您可以创建一个函数,该函数以字典形式返回参数。

尝试以下代码:

def getargs(**kwargs):
   return kwargs  # already a dictionary

Entry = Scene = Item = getargs  # all functions do same thing

x = Entry(id=None,scene_info=Scene(Recipes=[Item(ID='rec.chicky-nuggies',SpawnerIdx=0),Item(ID='rec.impossible-burger',SpawnerIdx=1)],Decor=[Item(ID='dec.plate-large-orange',SpawnerIdx=2),Item(ID='dec.plate-small-green',SpawnerIdx=3)]),rating=None)

print(x)

输出

{'id': None,'scene_info': {'Recipes': [{'ID': 'rec.chicky-nuggies','SpawnerIdx': 0},{'ID': 'rec.impossible-burger','SpawnerIdx': 1}],'Decor': [{'ID': 'dec.plate-large-orange','SpawnerIdx': 2},{'ID': 'dec.plate-small-green','SpawnerIdx': 3}]},'rating': None}
,

首选的方法是使用Tenacious B所述的修饰类定义,但是如果您想要一种快速的解决方案,则可以使用下面所述的 recursive 函数。

def class2dict(instance,built_dict={}):
    if not hasattr(instance,"__dict__"):
        return instance
    new_subdic = vars(instance)
    for key,value in new_subdic.items():
        new_subdic[key] = class2dict(value)
    return new_subdic

示例:

# Class definitions
class Scene:
    def __init__(self,time_dur,tag):
        self.time_dur = time_dur
        self.tag = tag


class Movie:
    def __init__(self,scene1,scene2):
        self.scene1 = scene1
        self.scene2 = scene2


class Entry:
    def __init__(self,movie):
        self.movie = movie
In [2]: entry = Entry(Movie(Scene('1 minute','action'),Scene('2 hours','comedy')))                                                                                                                                                                                       
In [3]: class2dict(entry)                                                                                                             
Out[3]:                                                                                                                          
{'movie': {
    'scene1': {'time_dur': '1 minute','tag': 'action'},'scene2': {'time_dur': '2 hours','tag': 'comedy'}}
}