【问题标题】:Iterating a list of dictionaries and converting to objects in Python迭代字典列表并在 Python 中转换为对象
【发布时间】:2015-11-12 21:15:33
【问题描述】:

假设我有一个字典列表,例如:

list_of_dicts = [
    {'id': 'something', type: 'type_a', blah...},
    {'id': 'anotherthing', type: 'type_b', blah...},
    {'id': 'yetanotherthing', type: 'type_c', blah...},
    etc.
]

我有一些对象,例如:

class Base(object):
    def __init__(self, blah):
        self.blah = blah

class TypeA(Base):

class TypeB(Base):

class TypeC(Base):

etc.

我想遍历列表,然后根据条件,假设:

for elem in list_of_dicts:
    if elem['type'] == 'type_a':
        my_obj = TypeA(blah)
    elif elem['type'] == 'type_b':
        my_obj = TypeB(blah)

    etc.

我可能有很多课。如果/elif 选择正确的对象,我该如何避免这个非常长的时间?有没有动态的方法来实现这一目标?更好的是,我是不是太聪明了,没有为每种类型的对象明确选择和设置?

每个对象可能有 10 多个要设置的属性,而且这个 if/elif 块非常长并且难以阅读/维护。

更新:

最有可能的答案是我完全错了。我最初的目标是拥有这个嵌套字典,并且我想以特定的方式“清理”/增强每个字典元素。也许对于具有 'type'=='type_a' 的元素,我想添加几个新键。如果'type'=='type_b',也许我想编辑一两个键的名称。如果 'type'=='type_c',我想编辑某个键的值等。可能有 30,40 种或 50 种不同的类型。所以我从一个“凌乱”的嵌套字典开始,然后得到一个“干净”的字典,修改了我的方式。

我最初的方法是为每种类型设置一个类。然后每个类都可以有自己的@property 装饰方法来以特定方式设置某些属性。它们都继承自同一个基类,该基类有一个方法,该方法返回一个包含所有属性作为键的字典。

【问题讨论】:

  • 无论您在做什么,这都不是正确的方法。很难弄清楚如何在这个框架下实例化类这一事实就是证明。
  • 您能否尝试澄清“未明确选择和设置...”的意思。另外,我不确定具有 10 多个属性的对象有什么问题;每个属性都需要单独的 if/elif 块吗?为什么?你能举出更多的例子来说明这个问题吗?
  • 为什么我有种你要switch statement in python的感觉?
  • 只是假设我可以有多达 30 多种不同的类型,每种类型都有 10 多种属性要设置。我想知道是否可以做一些事情来获得一个类实例化语句,例如:the_obj = <ClassName>(attr_one=blah, attr_two=blah, attr_three=blah)

标签: python object dictionary dynamic-class-creation


【解决方案1】:

一种方法是将类的名称直接包含在您的字典列表中:

list_of_dicts = [
    {'id': 'something', 'class': TypeA, blah...},
    {'id': 'anotherthing', 'class': TypeB, blah...},
    {'id': 'yetanotherthing', 'class': TypeC, blah...},
    etc.
]
...
for elem in list_of_dicts:
    my_obj = elem['class'](attributes)

为此,您必须在字典列表之前声明类。如果这不可行或不可取,您可以将它们与另一部字典链接。

classes = {'type_a': TypeA, 'type_b': TypeB, 'type_c': TypeC}
for elem in list_of_dicts:
    my_obj = classes[elem['type']](attributes)

但是我看不出您的原始代码有什么特别的问题,在某些方面它比这些方法更容易阅读。

【讨论】:

    【解决方案2】:

    你可以像这样使用一个小的 class_factory 函数: (我还对基类逻辑做了一点改进)

    list_of_dicts = [
        {'id': 'something', 'type': 'type_a', 'name': 'batman'},
        {'id': 'anotherthing', 'type': 'type_b', 'city': 'NYC', 'country': 'USA'},
        {'id': 'yetanotherthing', 'type': 'type_c', 'foo': 'bar'},
        {'id': 'one with no type', 'best_city': 'Paris'},
        {'id': 'one with an unknown type', 'type': 'type_z', 'result': 'it still works'},
    
    ]
    
    class Base(object):
        def __init__(self, **kwargs):
            kwargs.pop('type', None)
            for attr_name, attr_value in kwargs.items():
                setattr(self, attr_name, attr_value)
    
    class TypeA(Base):
        pass
    
    class TypeB(Base):
        pass
    
    class TypeC(Base):
        pass
    
    
    def class_factory(a_dict):
    
        mapping = {
            'type_a': TypeA,
            'type_b': TypeB,
            'type_c': TypeC,
        }
    
        return mapping.get(a_dict.get('type'), Base)
    
    
    my_dynamic_objects = []
    for elem in list_of_dicts:
        my_dynamic_objects.append(class_factory(elem)(**elem))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-28
      • 2012-07-03
      • 1970-01-01
      • 2021-04-04
      • 1970-01-01
      相关资源
      最近更新 更多