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.

4
  • 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. Commented Nov 12, 2015 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? Commented Nov 12, 2015 at 21:21
  • Why do I have the feeling that you are asking for switch statement in python? Commented Nov 12, 2015 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 = <ClassName>(attr_one=blah, attr_two=blah, attr_three=blah) Commented Nov 12, 2015 at 21:32

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

Comments

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))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.