Python Forum
Need explanation on this defaultdict code
Thread Rating:
  • 1 Vote(s) - 4 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Need explanation on this defaultdict code
#1
Hi,

I am reading legacy code but I could not understand the below code line why need to do so. Can someone pls explain to me. Thanks.

    def __init__(self, initdict=None):
        defaultdict.__setattr__(self, "_configentry", set())
        defaultdict.__init__(self, initdict)
The full source code is like this:
class DictConfig(defaultdict):
  
   
    def __init__(self, initdict=None):
        defaultdict.__setattr__(self, "_configentry", set())
        defaultdict.__init__(self, initdict)

    def AUTO_OFF(self):
        """Disable autovivification - deep"""
        defaultdict.__setattr__(self, "default_factory", None)
        for value in self.itervalues():
            tt = type(value)
            if tt is DictConfig:
                value.AUTO_OFF()

    def __getattr__(self, item):
        #        if item=="__setstate__":
        #            defaultdict.__getattr__(self, item)
        return self[item]

    def OVERRIDE(self, item, value):
        """Given a key and value, override it. Useful for unittests"""
        self.__setitem__(item, value)

    def __setattr__(self, item, value):
        cfgentry = self._configentry
        if item in cfgentry:
            if self[item] is value:
                return  # Do nothing, it is the same
            ErrMsg = "Key [" + item + "] already has value " + \
                     repr(repr(self[item]).rstrip().split('\n')) + \
                     ". This can be a config error. There should be no duplicate during assignment!"
            raise KeyError(ErrMsg)

        cfgentry.add(item)
        self[item] = value

    def _recursedict(self):  # iterator
        """Iterator for __repr__, returns a string"""
        for item, value in self.iteritems():
            if isinstance(value, DictConfig):
                for nitem, nvalue in value._recursedict():
                    yield item + "." + nitem, nvalue
            else:
                yield item, value

    def __repr__(self):
        """Return the display, just like a dictionary display"""
        return repr(recurse2dict(self))

    def PRETTY(self):
        """
        Return the following string equivalent of dictionary:
           key1.key2.key3 = value1
           key4.key5.key6 = value2
           key7.key8 = value3
        """
        sorted_iter = sorted(self._recursedict(), key=lambda x: x[0])  # sort by keys (element 0)
        return '\n'.join(item + " = " + repr(value) for item, value in sorted_iter)

    def GETLEVEL(self, key):
        """Given a string key (separated by '.'), return the object with that heirarchy"""
        target = self
        for level in key.split('.'):
            if level in target:
                target = target[level]
            else:
                raise KeyError('key[%s] is not found' % key)
        return target

    def SAME_AS(self, target):
        """
        Recursively/make-a-deep-copy of target.
        This is also the proper way of doing a dictionary .update() for TVPVConfigDict().

        Cannot use simple copy.deep() since it will do infiniteloop on DictConfig.
        If you see an Exception 'TypeError: 'DictConfig' object is not callable',
        it means that the target does not exist.
        """
        for item, value in target.iteritems():
            tt = type(value)
            if tt in BUILTIN_TYPES_SIMPLE:
                self[item] = value
            elif tt is DictConfig:
                self[item].SAME_AS(value)
            elif tt is list:
                self[item] = list(value)  # make a copy
            else:
                self[item] = deepcopy(value)

    def merge(self, dict2, _d1=None):
        """
        combine/merge dict2 into self.
        dict2 will be modified
        """
        if _d1 is None:
            _d1 = self
        for item, value in _d1.items():
            if item in dict2:
                if isinstance(dict2[item], DictConfig):
                    _d1[item] = self.merge(dict2.pop(item), value)
            else:
                _d1[item] = value
        for item, value in dict2.items():
            _d1[item] = value
        return _d1


def ConfigDict():
    """
    Factory function used on TVPVConfigDict for autovivification
    """
    return DictConfig(ConfigDict)


def recurse2dict(inp):
    """
    Converts inp to a built-in dict type, for use in marshal.
    It will recursively traverse thru all values deeply.
    inp must be a dictionary-like type (collections.defaultdict, autovivication, DictDot, etc)
    For single level dictionary (e.g. defaultdict), use res=dict(<var>) directly.
      example:  res = recurse_to_dict(var)
    """
    try:
        res = dict(inp)
    except TypeError:
        return inp
    except ValueError:
        return inp

    for k, v in inp.iteritems():
        if not type(v) in BUILTIN_TYPES_ALL:
            res[k] = recurse2dict(v)
    return res


common = ConfigDict()
common.dir_tag = ''
common.debug = 'abcde'
Reply
#2
So, first off this seems really stupid, so let's get that out of the way.

Normally when you set an attribute on a class you write self.some_attrib = some_value:
class SomeClass(object):
    def __init__(self, value):
        self.attrib = value


instance = SomeClass(5)
print(instance.attrib)
Internally when you set the attribute like that the __setattr__ method of the class is called.  You can overload this to do other stuff if you have the need.
class SomeClass(object):
    def __init__(self, value):
        self.attrib = value

    def __setattr__(self, name, value):
        print("Now I can do nonsense here.")
        object.__setattr__(self, name, value)


instance = SomeClass(5)
print(instance.attrib)
In your example the writer has overloaded __setattr__, but in the __init__ he wants to set an attribute without calling his own custom __setattr__ function.  So instead he calls the __setattr__ on the base class instead.
class SomeClass(object):
    def __init__(self, value):
        object.__setattr__(self, "attrib", value)

    def __setattr__(self, name, value):
        print("I won't print now.  I'm such a tricky programmer")
        object.__setattr__(self, name, value)


instance = SomeClass(5)
print(instance.attrib)
Honestly I feel like there is probably a much better way to do this while avoiding the confusion, but you did say legacy code.
Reply
#3
Thank you Mekire for the explanation :)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Explanation of code ejKDE 4 432 Feb-26-2024, 02:50 PM
Last Post: ejKDE
  A better explanation of the last post Led_Zeppelin 9 2,442 Sep-20-2022, 05:08 PM
Last Post: deanhystad
  Operator meaning explanation Sherine 3 2,069 Jul-31-2021, 11:05 AM
Last Post: Sherine
  Explanation of except ... as : Fernando_7obink 2 1,965 Feb-13-2021, 04:45 AM
Last Post: deanhystad
  .maketrans() - a piece of code which needs some explanation InputOutput007 5 3,013 Jan-28-2021, 05:05 PM
Last Post: buran
  .remove() from a list - request for explanation InputOutput007 3 2,268 Jan-28-2021, 04:21 PM
Last Post: InputOutput007
  Explanation of the left side of this statement please rascalsailor 3 2,537 Sep-09-2020, 02:02 PM
Last Post: rascalsailor
  Need explanation of one line of code Fliberty 6 3,544 Feb-18-2020, 12:50 AM
Last Post: Fliberty
  explanation of code hikerguy62 2 2,277 Aug-01-2019, 01:37 PM
Last Post: hikerguy62
  How to list number of times element is in defaultdict and delete it mrapple2020 3 2,698 Apr-15-2019, 07:34 AM
Last Post: perfringo

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020