Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`object.__setattr__(self, ..., ...)` instead of `setattr(self, ..., ...)`?

Following is the __init__ method of the Local class from the werkzeug library:

def __init__(self):
    object.__setattr__(self, '__storage__', {})
    object.__setattr__(self, '__ident_func__', get_ident)

I don't understand two things about this code:

  1. Why did they write

    object.__setattr__(self, '__storage__', {})
    

    instead of simply

    `setattr(self, '__storage__', {})`
    
  2. Why did they even use __setattr__ if the could simply write

    self.__storage__ = {}
    
like image 534
Aviv Cohn Avatar asked Oct 09 '15 15:10

Aviv Cohn


3 Answers

This ensures that the default Python definition of __setattr__ is used. It's generally used if the class has overridden __setattr__ to perform non-standard behaviour, but you still wish to access the original __setattr__ behaviour.

In the case of werkzeug, if you look at the Local class you'll see __setattr__ is defined like this:

def __setattr__(self, name, value):
    ident = self.__ident_func__()
    storage = self.__storage__
    try:
        storage[ident][name] = value
    except KeyError:
        storage[ident] = {name: value}

Instead of setting attributes in the dictionary of the object, it sets them in the __storage__ dictionary that was initialized previously. In order to set the __storage__ attribute at all (so that it may be accessed like self.__storage__ later), the original definition of __setattr__ from object must be used, which is why the awkward notation is used in the constructor.

like image 162
Simon Broadhead Avatar answered Sep 28 '22 18:09

Simon Broadhead


They want to explicitly use the base object.__setattr__ implementation instead of a possibly overridden method instance method somewhere else in the inheritance chain. Local implements its own __setattr__ so this avoids that.

like image 41
Josh J Avatar answered Sep 28 '22 19:09

Josh J


Because the same class defines __setattr__ and this needs to bypass that, since the first line says self.__ident_func__() which wouldn't work yet.

like image 35
Alex Hall Avatar answered Sep 28 '22 19:09

Alex Hall