📜 ⬆️ ⬇️

The implementation of dictionary objects, as in Javascript

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

To put it more clearly, I wanted to have a full Python dict , but only such that one could refer to its value as to the attributes of an object. Personally, I am 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 make it the means of the python itself?

Implementation 1. In the forehead.


The first thing that comes to mind is to simply implement the work of all the magical 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 seems to be not too pythonic. Looking a little closer, you can see that extra work is being done, and the code can be shortened.

Implementation 2. Tao python.


In fact, it is enough just to 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 still clumsy and not expandable. Having slept at night with this idea, in the morning it occurred to me, perhaps the most elegant solution.

Realization 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 happening? The most interesting is in the line self.__dict__ = self . In fact, our object is an ordinary dictionary, so why not it also be a dictionary of the attributes of itself? Now, when we extract, modify, or delete an attribute of an instance of the Dict class, these changes will directly affect the values ​​in this instance as a dictionary, because in fact they have become the same entities.

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


So it turned out another proof of how, together with the python, you can do a lot of useful and interesting. And if you understand how it is arranged inside, it can be done also 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 bit cleaner.

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

Source: https://habr.com/ru/post/129201/


All Articles