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

时间:2016-01-19 13:43:52

标签: python mongodb class cursor instance

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

我想迭代光标,依次取每个字典并将其转换为特定的类实例,其类型在字典中定义为键(即形式为dict ['class_type'] =' class_type')。 我想创建变量来引用这些新的类实例,名称由另一个字典键定义,即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字符串动态选择类类型。最后一行基本上是尝试从这个类似的问题复制接受的答案(第二部分),但是使用动态变量和类名:Convert Python dict to object?。类init中的代码部分包含在基类中并继承。

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

感谢任何建议;我对编程很陌生,并且意识到我可能会以错误的方式解决这个问题。

干杯

1 个答案:

答案 0 :(得分:2)

你的设计非常糟糕。

应该在代码编写时创建 VAriable names 。您甚至可以在某些极端情况下动态设置变量。但通常情况下,如果您的描述名称(您用作变量名称的名称)已更改,则您希望使用字典。首先,如果你动态创建一个意外的变量,那么其他程序部分如何知道它是从哪里开始的呢?如果你使用字典,它可以通过keys内省。所以my_objects ['foo']比从foo变量出现的要好得多。但是,是的,它可以在不诉诸exec的情况下完成。

首先实例化你的对象。您应该在单个名称空间中拥有所有所需的类。你可以将它们放在一个模块中(它们不必在那个模块中定义 - 你只需要在那里导入它们的名字: from vehicles import Car, Bus; from plants import Flower, Tree - woukld在导入模块的命名空间中提供这四个类。

然后,您可以根据从mongodb检索的字符串名称检索类对象。如果将名称空间模块命名为“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>访问它。

同样,您可以使用命名空间模块,并使其更容易 - 一个Python模块大部分空白(或者最初设置为None的可能变量),并在您的代码中执行此操作:

setattr(namespace_module, obj[key_for_var_name], new_instance)

正如您所看到的,Python本质上是内省的,您很少需要诉诸execeval。但这可能导致可怕的代码实践。请记住,您必须分离代码和应用程​​序中的数据 - 变量名称通常是代码。