我知道之前已经回答了类似的问题,但在花了几个小时浏览网页后,我仍然无法正确解决我的问题(或'python-way'解决方案)
我正在使用以下'数据库'模块将任何对象插入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重新加载一个对象并将其强制转换回正确的类。
我有一个通用类'Operation'(表示可以对银行/资金帐户执行的操作:
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}))
在此之前一切正常,我可以实例化任何Operation对象,将其插入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
和
import uuid
from operation import Operation
class Fee(Operation):
def __init__(self):
Operation.__init__(self)
self._id = 'FEE-{}'.format(uuid.uuid1())
@property
def id(self):
return self._id
我们的想法是保留代码以保存/加载'Operation'类中的对象,并在需要时创建简单的派生类。 所以'Operation'类应该能够动态地将加载的对象从Operation转换为Credit / Fee / Transfer ......
我尝试做的是在所有类上添加以下行以存储对象类型:
self.type = self.__class__
或者(因为类不能直接序列化为json)
self.type = self.__name__
但我不知道如何实现:
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()方法并返回相应的类? 对于优秀的Python主义者来说还有一个问题:这是正确的方法吗?
答案 0 :(得分:1)
使用您建议的self.type = self.__name__
提示,您可以尝试get_type_from_name
函数的此实现:
def get_type_from_name(name):
name_to_type = {'Credit': Credit, 'Fee':Fee}
return name_to_type[name]
我不太确定我是否完全理解你的问题,所以请告诉我这是不是你想要的。
答案 1 :(得分:0)
我认为我设法让它发挥作用:
将此添加到我想要(de)序列化的类:
self.type = self.__class__.__name__
self.module = self.__module__
然后从PyMongo加载json doc:
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)
最后两行导入包含该类的模块,并动态修改对象 class 。
感谢user3030010的回答。 但我仍然很想知道你们是否认为这是一个好的设计,或者可能导致更多的问题。