Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems when converting a dictionary to object

I am using a technique discussed here before, to turn a dictionary into an object, so that I can access the elements of the dictionary with the dot (.) notion, as instance variables.

This is what I am doing:

# Initial dictionary
myData = {'apple':'1', 'banana':'2', 'house':'3', 'car':'4', 'hippopotamus':'5'}

# Create the container class
class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)

# Finally create the instance and bind the dictionary to it
k = Struct(**myData)

So now, I can do:

print k.apple

and the result is:

1

This works, however the issues start if I try to add some other methods to the "Struct" class. For example lets say that I am adding a simple method that just creates an variable:

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

    def testMe(self):
        self.myVariable = 67

If I do:

k.testMe()

My dictionary object is broken, "myVariable" is inserted as a key with the value "67". So If I do:

print k.__dict__

I am getting:

{'apple': '1', 'house': '3', 'myVariable': 67, 'car': '4', 'banana': '2', 'hippopotamus': '5'}

Is there a way to fix this? I kind of understand what is happening, but not sure If I need to entirely change my approach and build a class with internal methods to handle the dictionary object or is there a simpler way to fix this problem?

Here is the original link: Convert Python dict to object?

Thanks.

like image 259
mbilyanov Avatar asked Oct 21 '22 00:10

mbilyanov


1 Answers

For your needs, don't store you variables in __dict__. Use your own dictionary instead, and override .__getattr__ (for print k.apple) and __setattr__ (for k.apple=2):

# Initial dictionary
myData = {'apple':'1', 'banana':'2', 'house':'3', 'car':'4', 'hippopotamus':'5'}

# Create the container class
class Struct:
    _dict = {}
    def __init__(self, **entries):
        self._dict = entries

    def __getattr__(self, name):
        try:
            return self._dict[name]
        except KeyError:
            raise AttributeError(
                "'{}' object has no attribute or key '{}'".format(
                    self.__class__.__name__, name))


    def __setattr__(self, name, value):
        if name in self._dict:
            self._dict[name] = value
        else:
            self.__dict__[name] = value

    def testMe(self):
        self.myVariable = 67

    def FormattedDump(self):
        return str(self._dict)

# Finally create the instance and bind the dictionary to it
k = Struct(**myData)

print k.apple
print k.FormattedDump()
k.testMe()
k.apple = '2'
print k.FormattedDump()

In the alternative, if your FormattedDump() routine is bothering you, you could just fix it:

# Initial dictionary
myData = {'apple':'1', 'banana':'2', 'house':'3', 'car':'4', 'hippopotamus':'5'}

# Create the container class
class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)
        self.public_names = entries.keys()

    def testMe(self):
        self.myVariable = 67

    def GetPublicDict(self):
        return {key:getattr(self, key) for key in self.public_names}
    def FormattedDump(self):
        return str(self.GetPublicDict())

# Finally create the instance and bind the dictionary to it
k = Struct(**myData)

print k.apple
print k.FormattedDump()
k.testMe()
k.apple = '2'
print k.FormattedDump()
like image 127
Robᵩ Avatar answered Oct 23 '22 23:10

Robᵩ