[英]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 具有属于其他类
Scene
和Item
的类型的属性。 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.