【问题标题】:Pymongo: Convert MongoDB query (cursor) to class instance with defined variable namePymongo:将 MongoDB 查询(光标)转换为具有定义变量名的类实例
【发布时间】:2016-01-19 13:43:52
【问题描述】:

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

我想遍历光标,依次获取每个字典并将其转换为特定的类实例,其类型在字典内部定义为键(即 dict['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 的部分代码包含在基类中并被继承。

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

感谢任何建议;我对编程很陌生,我知道我可能以错误的方式处理这个问题。

干杯

【问题讨论】:

  • 您的示例中的缩进有点偏离,您能否在发布问题时确认其唯一的复制粘贴错误?缩进在 Python 中很重要。干杯。
  • 很好发现 Wan,是的,这是一个复制和粘贴错误,原始代码中不存在。已编辑。

标签: python mongodb class cursor instance


【解决方案1】:

你的设计很糟糕。

可变名称​​应该在编写代码时创建。在某些极端情况下,您甚至可以动态设置 变量。但通常,如果您的描述名称(您用作变量名称的名称)发生更改,您希望使用字典。一方面,如果您动态创建一个意外变量,其他程序部分如何知道它是从那里开始的?如果您使用字典,则可以通过其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。但这会导致可怕的代码实践。请记住,您必须在应用程序中区分什么是代码和什么是数据 - 变量名称通常是代码。

【讨论】:

  • 感谢 jsbueno 的深入建议。我正在设计一个大型的面向对象模型,它将使用和引用几种不同的类类型和实例进行计算。正确的做法是拥有一个主字典对象并在初始化每个类实例时将它们分配给一个唯一的字典键?
猜你喜欢
  • 2018-11-02
  • 2018-03-11
  • 2012-10-25
  • 1970-01-01
  • 2018-03-21
  • 1970-01-01
  • 2013-06-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多