Pymongo:将 MongoDB 查询(游标)转换为具有已定义变量名称的 class 实例

Pymongo: Convert MongoDB query (cursor) to class instance with defined variable name

我有一个来自 MongoDB find() 查询的游标对象。这本质上是一个由多个字典条目组成的可迭代对象。

我想遍历游标,依次获取每个字典并将其转换为特定的 class 实例,其类型在字典中定义为键(即形式为 dict[ 'class_type']='class_type')。 我想创建变量来引用这些新的 class 实例,名称由另一个字典键定义,即 dict['variable_name'] = 'name'。这些名称将是唯一的。

到目前为止,我尝试了以下方法:

def mongo_query_to_variable(mongo_query):

    for obj in mongo_query:
        class_type = obj['class_type']
        var_name = obj[key_for_var_name]

        exec(var_name + '=' + class_type + '(**obj)', globals())

当我在 shell 中逐行实现这段代码时,它似乎可以工作,但当我尝试将它用作函数时却没有。我收到错误:

NameError: name 'class_type' is not defined

我知道最好尽量避免使用 eval/exec,但我不确定我还能如何使用 class_type 字符串动态选择 class 类型。最后一行本质上是试图从这个类似的问题中复制已接受的答案(第 2 部分),但使用动态变量和 class 名称:Convert Python dict to object?。 class init 中的代码部分包含在基础 class 中并被继承。

我在那里有全局变量,因为查询的长度是可变的,我不太确定如何 return 变量的动态数量并为它们分配在函数内定义的名称。我听说最好避免全局,那么有没有更好的方法将 class 实例分配给变量?

如有任何建议,我们将不胜感激;我对编程还很陌生,我知道我可能以错误的方式解决了这个问题。

干杯

你的设计很糟糕。

可变名称应该在code-writing时创建。在某些特殊情况下,您甚至可以动态地 set 变量。但通常情况下,如果您的描述名称(您用作 variable-name 的名称)发生更改,您会希望使用字典。其一,如果您动态地创建了一个意想不到的变量,其他程序部分如何知道它是从哪里开始的?如果你使用字典,它可以通过它的 keys 进行内省。所以 my_objects['foo'] 比不知从哪里出现的 foo 变量要好得多。但是,是的,无需诉诸 exec.

就可以做到

首先实例化你的对象。您应该在一个名称 space 中包含所有需要的 classes。您可以将它们放在一个模块中(它们不必在该模块中定义 - 您只需要在那里导入它们的名称: from vehicles import Car, Bus; from plants import Flower, Tree - 应该使这四个 class 在进行导入的模块的名称 space 中可用。

然后您可以根据从 mongodb 检索到的字符串名称检索 class 对象。如果将namespace模块命名为"myclasses":

import myclasses
   ...
   for obj in mongoquery: 
       cls = getattr(myclasses, obj['class_type']
       new_instance = cls(**obj)

现在,要将其存储在您的程序以后可以找到的某个位置,正如我上面所说,更好的方法是将其保存在字典中。所以:

   my_objects[obj[key_for_var_name]] = new_instance

就够了。

要将其设置为当前模块(此代码所在的模块 运行)中的全局变量,您可以改为:

   globals()[obj[key_for_var_name]] = new_instance

按照所有建议执行此操作,指示的变量将在当前模块中可用。其他模块中的代码可以使用module_name.<variable_name>访问它。

同样,您可以求助于 namespace 模块,让这一切变得更容易 - Python 模块大部分是空白的(或者可能的变量最初设置为 None ),并在您的代码中执行此操作:

setattr(namespace_module, obj[key_for_var_name], new_instance)

如您所见,Python 本质上是真正的内省,您很少需要求助于 execeval。但这会导致可怕的代码实践。请记住,您必须将应用程序中的代码和数据分开 - 变量名通常是代码。