2015-11-12 11 views
0

Скажем, у меня есть список словарей, таких как:Итерация список словарей и преобразования к объектам в Python

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 невероятно длинный и становится трудным для чтения/обслуживания.

UPDATE:

Более чем вероятно, ответ в том, что я буду об этом совершенно неправильно. Моя первоначальная цель состоит в том, что у меня есть этот вложенный словарь, и я хочу «очистить его»/улучшить каждый элемент слова особым образом. Может быть, для элемента с 'type' == 'type_a', я хочу добавить пару новых ключей. Если 'type' == 'type_b', возможно, я хочу изменить имя ключа или два. Если 'type' == 'type_c', я хочу отредактировать значение определенного ключа и т. Д. Может быть 30,40, может быть, 50 разных типов. Поэтому я начинаю с «грязного» вложенного дикта и возвращаю «чистый», меняя свой путь.

Мой первоначальный подход состоял в том, чтобы иметь класс для каждого типа. И тогда у каждого класса могут быть свои собственные @property декорированные методы, чтобы установить определенные атрибуты определенным образом. И все они наследуются от того же базового класса, который будет иметь метод, который возвращает словарь со всеми атрибутами в качестве ключей.

+0

Все, что вы делаете, это не правильный путь. Об этом свидетельствует тот факт, что так сложно понять, как создавать экземпляры классов в рамках этой структуры. –

+0

Можете ли вы попытаться пояснить, что вы подразумеваете под «неявным выбором и настройкой ...». Кроме того, я не уверен, что проблема с объектами, имеющими 10 + атрибуты; вам нужен отдельный блок if/elif для каждого атрибута? Зачем? Можете ли вы привести больше примеров, чтобы продемонстрировать проблему? – Stuart

+0

Почему у меня возникает ощущение, что вы запрашиваете [оператор switch в python] (http://stackoverflow.com/questions/60208/replacements-for-switch-statement-in-python)? – styvane

ответ

0

Один подход должен был бы включать имена классов непосредственно в списке dicts:

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) 

Для этой работы вы должны объявить классы перед списком dicts. Если это невозможно или желательно, вы можете связать их с другим словарем.

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

Однако я не вижу ничего особенного в вашем исходном коде, который в некотором смысле более легко читается, чем эти подходы.

0

Вы могли бы просто использовать небольшую 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))