在python中动态地将dict转换为类

在python中动态地将dict转换为类,python,json,mongodb,dictionary,casting,Python,Json,Mongodb,Dictionary,Casting,我知道以前也回答过类似的问题,但在花了数小时浏览网页之后,我仍然无法找到解决问题的正确方法(或“python方式”解决方案) 我使用以下“数据库”模块将任何对象插入MongoDB: from pymongo import MongoClient import json def insert(obj, collection_name): with MongoClient(27017, 'localhost') as client: if hasattr(obj, '__d

我知道以前也回答过类似的问题,但在花了数小时浏览网页之后,我仍然无法找到解决问题的正确方法(或“python方式”解决方案)

我使用以下“数据库”模块将任何对象插入MongoDB:

from pymongo import MongoClient
import json

def insert(obj, collection_name):
    with MongoClient(27017, 'localhost') as client:
        if hasattr(obj, '__dict__'):
            doc = obj.__dict__
        else:
            doc = json.dumps(obj)
        return client['test'][collection_name].insert_one(doc).inserted_id

def get_one(collection_name, query):
    with MongoClient(27017, 'localhost') as client:
        return client['test'][collection_name].find_one(query)
这部分工作得很好,因为我可以处理任何模块中的任何类,并以通用方式存储对象

我面临的问题是从MongoDB重新加载一个对象,并将其转换回正确的类

我有一个通用类“操作”(表示可以对银行/货币账户执行的操作:

import database 

class Operation(object):
    def __init__(self):
        self._id = 'OPE-{}'.format(str(uuid.uuid1()))

    @property
    def id(self):
        return self._id

    def save(self):
        database.update(self, 'operations')

def create_from_dict(d):
    operation = Operation()
    for key, value in d.items():
        operation.__dict__[key] = value
    return operation

def get(operation_id):
    return create_from_dict(database.get_one('operations', {'_id': operation_id}))
在这之前,一切都正常,我可以实例化任何操作对象,将其插入MongoDB并使用其id将其加载回

现在我有两个新的类“费”和“信用”来自“操作”

import uuid
from operation import Operation

class Credit(Operation):
    def __init__(self):
        Operation.__init__(self)
        self._id = 'CRE-{}'.format(uuid.uuid1())

    @property
    def id(self):
        return self._id

其思想是保留代码,以便在“Operation”类中保存/加载对象,并在需要时创建简单的派生类。 所以“Operation”类应该能够动态地将加载的对象从Operation转换为Credit/Fee/Transfer

我尝试在所有类上添加以下行以存储对象类型:

self.type = self.__class__
或者(因为类不能直接序列化为json)

但我不知道如何才能实现:

def create_from_dict(d):
    operation = Operation()
    for key, value in d.items():
        operation.__dict__[key] = value
    operation.__class__ = get_type_from_name(operation.type) #This is the function I'm trying to implement
    return operation
在对对象进行编码以从另一个模块将其强制转换回时,是否应该同时存储模块和类名

很抱歉问了这么长的问题,但我想完全描述代码背后的逻辑 我对任何建议都非常开放

编辑: 可以使用locals()或globals()吗?将类名传递给get_type_from_name()方法,它将返回相应的类?
高级Pythonists的另外一个问题:这是正确的方法吗?

使用您建议的
self.type=self.\uuuu name\uuuuu
思想,您可以为
get\u type\u from\u name
函数尝试此实现:

def get_type_from_name(name):
    name_to_type = {'Credit': Credit, 'Fee':Fee}
    return name_to_type[name]

不过,我不太确定我是否完全理解您的问题,因此,如果这不是您想要的,请告诉我。

我想我已经设法解决了:

将此添加到我要(反)序列化的类:

self.type = self.__class__.__name__
self.module = self.__module__
然后,一旦从PyMongo加载json文档:

    if not hasattr(doc, 'module') or not hasattr(doc, 'type'):
        return obj
    for key, value in doc.items():
        obj.__dict__[key] = value
    mod = __import__(obj.module, fromlist=[obj.type])
    obj.__class__ = getattr(mod, obj.type)
最后两行导入包含类的模块,并动态修改对象

谢谢你的回答。
但我仍然很好奇,想知道你们是否认为这是一个好的设计,或者可能会导致更多的问题。

这是一个想法,但我不想维护一个静态映射名称/类。而且由于派生类(信用、费用)对操作有依赖性我正在尝试避免任何循环依赖性。我想的是操作中的一个方法,它可以在不引用对象类的情况下强制转换对象。这有意义吗?似乎
locals()
包含了您想要的信息,所以可能只需要执行
return locals()[姓名]
尽管这已经开始进入一个相当棘手的领域,但你可能想知道是否有更好的方法来完成你想做的事情。例如,最可靠的解决方案是对每个对象进行pickle,然后将其放入MongoDB中的二进制字段中。或者至少,你可以对类本身,并存储它(这样您就不需要自己从字符串动态地重新创建它)。
self.type = self.__class__.__name__
self.module = self.__module__
    if not hasattr(doc, 'module') or not hasattr(doc, 'type'):
        return obj
    for key, value in doc.items():
        obj.__dict__[key] = value
    mod = __import__(obj.module, fromlist=[obj.type])
    obj.__class__ = getattr(mod, obj.type)