Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Complex transforming nested dictionaries into objects in python

Tags:

python

It hasn't been long since I started learning python, but I really want to dig in it. And dig it hard. So here is a task I've been studying for a while but haven't cracked yet:
I am given a mixed combination of nested dictionaries and lists (let's call it "combination"), and I need to implement function that will allow accessing nested elements as object attributes, also somehow treating combination elements as iterable. This should look something like this:

combination = {
'item1': 3.14,
'item2': 42,
'items': [
         'text text text',
         {
             'field1': 'a',
             'field2': 'b',
         },
         {
             'field1': 'c',
             'field2': 'd',
         },
         ]
}

def function(combination):
    ...

so that
list(function(combination).items.field1) will give: ['a', 'c'], and
list(function(combination).item1) will give: [3.14].
Edit As mentioned by @FM, I missed description of handling non-dict elements: list(function(combination).items[0]) >>> ['text text text']


I tried implementing a class (kudos to Marc) to help me:

class Struct:
    def __init__(self, **entries): 
        self.__dict__.update(entries)

and then using it in the function like return Struct(**combination)
While being very nifty, it is only the first step to the desired result.
But as the next step needs to go deeper, it overwhelms me and I can't make it on myself.
Therefore, I kindly ask for your help.

Michael.

like image 682
Michael Spring Avatar asked Mar 13 '11 16:03

Michael Spring


People also ask

How do you convert a dictionary to an object in Python?

Method 1 : Using the json module. We can solve this particular problem by importing the json module and use a custom object hook in the json. loads() method.

How do you flatten nested dictionaries in Python?

Basically the same way you would flatten a nested list, you just have to do the extra work for iterating the dict by key/value, creating new keys for your new dictionary and creating the dictionary at final step. For Python >= 3.3, change the import to from collections.

How do you change a nested dictionary in Python?

Adding or updating nested dictionary items is easy. Just refer to the item by its key and assign a value. If the key is already present in the dictionary, its value is replaced by the new one. If the key is new, it is added to the dictionary with its value.

How do you break nested dictionaries in Python?

In Python, we use “ del “ statement to delete elements from nested dictionary.


1 Answers

How about:

class ComboParser(object):
    def __init__(self,data):
        self.data=data
    def __getattr__(self,key):
        try:
            return ComboParser(self.data[key])
        except TypeError:
            result=[]
            for item in self.data:
                if key in item:
                    try:
                        result.append(item[key])
                    except TypeError: pass
            return ComboParser(result)
    def __getitem__(self,key):
        return ComboParser(self.data[key])
    def __iter__(self):
        if isinstance(self.data,basestring):
            # self.data might be a str or unicode object
            yield self.data
        else:
            # self.data might be a list or tuple
            try:
                for item in self.data:
                    yield item
            except TypeError:
                # self.data might be an int or float
                yield self.data
    def __length_hint__(self):
        return len(self.data)

which yields:

combination = {
    'item1': 3.14,
    'item2': 42,
    'items': [
        'text text text',
        {
            'field1': 'a',
            'field2': 'b',
            },
        {
            'field1': 'c',
            'field2': 'd',
            },
        {
            'field1': 'e',
            'field3': 'f',
            },        
        ]
    }
print(list(ComboParser(combination).item1))
# [3.1400000000000001]
print(list(ComboParser(combination).items))
# ['text text text', {'field2': 'b', 'field1': 'a'}, {'field2': 'd', 'field1': 'c'}, {'field3': 'f', 'field1': 'e'}]
print(list(ComboParser(combination).items[0]))
# ['text text text']
print(list(ComboParser(combination).items.field1))
# ['a', 'c', 'e']
like image 133
unutbu Avatar answered Sep 19 '22 21:09

unutbu