在python中动态地将dict转换为类
我知道以前也回答过类似的问题,但在花了数小时浏览网页之后,我仍然无法找到解决问题的正确方法(或“python方式”解决方案) 我使用以下“数据库”模块将任何对象插入MongoDB:在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
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)