Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing default __dict__ for object with OrderedDict

I have two classes in my code. first is the parent, which second inherits.

class first(object):
    def __init(self,**kwargs):  
        pass

    def __setattr__(self,name,value):
        self.__dict__[name] = value

class second(first):
    def do_something(self):
        self.a = 1
        self.b = 2
        self.c = 3

when I am printing the class second (by e.g. second.__dict__) I get the unordered dictionary. This is obvious. I want to change this behavior to get an ordered dictionary using the OrderedDict class, but it does not work. I am changing implementation of first in the following way:

class first(OrderedDict):   
    def __init__(self,**kwargs):  
        super(first,self).__init__(**kwargs)  
    def __setattr__(self,name_value):  
        super(first,self).__setattr__(name_value)  

I would like to print second using __dict__ or __repr__, but I got the unordered dictionary. What should I change?

like image 912
Przemo Avatar asked Dec 05 '22 23:12

Przemo


1 Answers

You can simply redirect all attribute access to an OrderedDict:

class first(object):
    def __init__(self, *args, **kwargs):  
        self._attrs = OrderedDict(*args, **kwargs)

    def __getattr__(self, name):
        try:
            return self._attrs[name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        if name == '_attrs':
            return super(first, self).__setattr__(name, value)
        self._attrs[name] = value

Demo:

>>> from collections import OrderedDict
>>> class first(object):
...     def __init__(self, *args, **kwargs):  
...         self._attrs = OrderedDict(*args, **kwargs)
...     def __getattr__(self, name):
...         try:
...             return self._attrs[name]
...         except KeyError:
...             raise AttributeError(name)
...     def __setattr__(self, name, value):
...         if name == '_attrs':
...             return super(first, self).__setattr__(name, value)
...         self._attrs[name] = value
... 
>>> class second(first):
...     def do_something(self):
...         self.a = 1
...         self.b = 2
...         self.c = 3
... 
>>> s = second()
>>> s.do_something()
>>> s._attrs
OrderedDict([('a', 1), ('b', 2), ('c', 3)])

You can't otherwise replace the __dict__ attribute with an OrderedDict instance, because Python optimises instance attribute access by using the concrete class API to access the dictionary internals in C, bypassing the OrderedDict.__setitem__ hook altogether (see issue #1475692).

like image 143
Martijn Pieters Avatar answered Dec 10 '22 12:12

Martijn Pieters