简体   繁体   English

如何将嵌套的object转换为python中的嵌套字典

[英]How to convert nested object to nested dictionary in python

I have an object Entry with following fields as id, scene_info and rating.我有一个 object Entry ,其中包含以下字段:id、scene_info 和 rating。 As can be seen, the object has attributes that are types to other classes Scene and Item .可以看出, object 具有属于其他类SceneItem的类型的属性。 I want to convert this object to dictionary.我想将此 object 转换为字典。

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), 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}

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}

I tried vars and they only convert outer object to dict but not inner object. How can I convert the nested ones?我试过vars ,它们只将外部 object 转换为 dict 而不是内部 object。如何转换嵌套的?

I usually do it this way:我通常这样做:

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() will give you a json string for the class and its nested objects if they are simple enough, you can also use marshmallow to do this with more control.如果它们足够简单, to_json()将为您提供类及其嵌套对象的 json 字符串,您也可以使用棉花糖来进行更多控制。 You could just do return json.dumps(self, default=lambda o: vars(o), indent=indent) in the parent class and not have the encode() method but using the encode method allows you to customize the output.您可以只在父类中return json.dumps(self, default=lambda o: vars(o), indent=indent)而没有encode()方法,但使用encode方法可以让您自定义输出。

Here is some random, silly code to show how it might be used and the output:这是一些随机的、愚蠢的代码,用于展示如何使用它以及输出:

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, name, 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=None):
        return json.dumps(self, default=lambda o: o.encode(), 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))

Output:输出:

{
    "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"
    }
}

For the class types (Entry\\Scene\\Item), you can create a function the returns the arguments as a dictionary.对于类类型 (Entry\\Scene\\Item),您可以创建一个函数,将参数作为字典返回。

Try this code:试试这个代码:

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)

Output输出

{'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}

The prefered way to go would be using modifing class definition as stated by Tenacious B , but if you want a fast solution you can use the recursive function stated below.首选的方法是使用Tenacious B所述的修改类定义,但如果您想要一个快速的解决方案,您可以使用下面所述的递归函数。

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

Example:例子:

# 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'}}
}     
  

                                                                              

You can use the Pydantic model's Entry.json() , this will convert everything including nested models to a string which can then be converted back to a dictionary by using something like json.loads()您可以使用 Pydantic 模型的Entry.json() ,这会将包括嵌套模型在内的所有内容转换为字符串,然后可以使用json.loads()类的东西将其转换回字典

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM