Implementation of dictionary objects, as in Javascript

    Recently, after a long interaction of my brain with Javascript, I returned to the usual Python for me, and realized that I was missing something, namely objects like in Javascript, those that have hash tables, yeah. Fuuuuu, maybe you will say, and perhaps in vain.

    Speaking more clearly, I wanted to have a full-fledged Pythonic dict, but only such that it would be possible to refer to its value as attributes of an object. Personally, I’m much nicer to write a.name, instead of a["name"]:

    >>> a.id = 42
    >>> a.name = "Jon"
    >>> print a
    {'id': 42, 'name': 'Jon'}


    In this case, of course, it is important to maintain the standard dictionary functionality:

    >>> print "id:% (id) d, name:% (name) s"% a
    id: 42, name: Jon
    >>> a.keys ()
    ['id', 'name']


    Pretty nice, right? So why not do it with python itself?

    Implementation 1. On the forehead.


    The first thing that comes to mind is simply to implement the work of all the magic methods we need:

    class Dict (dict):
        def __getattr __ (self, key):
            return self [key]
        def __setattr __ (self, key, value):
            self [key] = value
        def __delattr __ (self, key):
            del self [key]


    But it does not seem to be too pythonic. If you look a little closer, you can see that extra work is being done, and the code can be reduced.

    Implementation 2. Tao of python.


    In fact, it’s enough to simply replace some unbound methods with others, since they have the same signature:

    class Dict (dict):
        __getattr__ = dict .__ getitem__
        __setattr__ = dict .__ setitem__
        __delattr__ = dict .__ delitem__


    It certainly looks better, but it's clumsy and non-extensible anyway. Having slept with this idea at night, in the morning it occurred to me, perhaps the most elegant solution.

    Implementation 3. Little magic.


    class Dict (dict):
        def __new __ (cls, * args, ** kwargs):
            self = dict .__ new __ (cls, * args, ** kwargs)
            self .__ dict__ = self
            return self


    Do you understand what is going on? The most interesting is in the line self.__dict__ = self. In fact, our object is an ordinary dictionary, so why shouldn't it also be a dictionary of attributes of oneself? Now, when we retrieve, modify, or delete the attribute of an instance of the Dict class, these changes will directly affect the values ​​in this instance as a dictionary, because in essence they have become the same entities.

    >>> d = Dict (a = 1, b = 2, c = 3)
    >>> print d
    {'a': 1, 'c': 3, 'b': 2}
    >>> print da == d ["a"]
    True
    >>> db = 7
    >>> del dc
    >>> dx = 4
    >>> print d
    {'a': 1, 'x': 4, 'b': 7}
    >> > print d.keys (), d.items ()
    ['a', 'x', 'b'] [1, 4, 7]


    So we got one more proof of how a lot of useful and interesting things can be done together with python. And if you understand how it is arranged inside, it can also be done beautifully and elegantly.
    Of course, I did not create anything fundamentally new, but in those projects where I have to work with half-typed entities, I no longer have to choose between a dictionary and an object, and the code has become a little cleaner.

    Any comments are welcome why this is bad or how to solve the problem even more elegantly.

    Also popular now: