0

Let's say I have a list of dictionaries like:

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

And I have some objects like:

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

class TypeA(Base):

class TypeB(Base):

class TypeC(Base):

etc.

I want to iterate over the list and then depending on a condition, let's say:

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.

I might have many classes. How do I avoid this really long if/elif of choosing the right object? Is there a dynamic way to achieve this? Better yet, am I trying to be too clever by not explicitly choosing and setting for every type of object?

Each object may have 10+ attributes to set and this if/elif block is incredibly long and getting difficult to read/maintain.

UPDATE:

The more than likely answer is that I am going about this totally wrong. My original goal is that I have this nested dictionary and I want to "clean it up"/enhance each dictionary element a particular way. Maybe for an element with 'type'=='type_a', I want to add a couple of new keys. If 'type'=='type_b', maybe I want to edit the name of a key or two. If 'type'=='type_c', I want to edit the value of a certain key, etc. There could be 30,40 maybe 50 different types. So I start with a "messy" nested dict and get back a "clean" one, modified my way.

My original approach was to have a class for each type. And then each class could have their own @property decorated methods to set certain attributes a particular way. And they all inherit from the same base class which would have a method that returns a dictionary with all the attributes as keys.

user1087973
  • 800
  • 3
  • 12
  • 29
  • Whatever you're doing, this isn't the right way. The fact that it's so hard to figure out how to instantiate classes under this framework is evidence of that. – Two-Bit Alchemist Nov 12 '15 at 21:16
  • Can you try to clarify what you mean by 'not explicitly choosing and setting...'. Also, I'm not sure what the problem is with the objects having 10+ attributes; do you need a separate if/elif block for each attribute? Why? Can you give more examples to demonstrate the problem? – Stuart Nov 12 '15 at 21:21
  • Why do I have the feeling that you are asking for [switch statement in python](http://stackoverflow.com/questions/60208/replacements-for-switch-statement-in-python)? – styvane Nov 12 '15 at 21:23
  • It's just that let's say I could have up to 30+ different types, with each one having 10+ attributes to set. I was wonder if there was something I could do to have one class instantiation statement like: `the_obj = (attr_one=blah, attr_two=blah, attr_three=blah)` – user1087973 Nov 12 '15 at 21:32

2 Answers2

0

One approach would be to include the names of the classes directly in your list of 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)

For this to work you would have to declare the classes before the list of dicts. If that's not possible or desirable you can link them with another dictionary.

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

However I don't see anything particularly wrong with your original code, which is in some ways easier to read than these approaches.

Stuart
  • 9,597
  • 1
  • 21
  • 30
0

You could just use a small class_factory function like this: (I also improved a bit the base class logic)

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))
DevLounge
  • 8,313
  • 3
  • 31
  • 44