Is __setattr__ called when an existing attribute is incremented?

overloading, python, setattr

Solution

Python: Is __setattr__ called when an existing attribute is incremented?

The answer is yes. This is easily seen with a simplified version of your code:

class C(object):

    def __init__(self, a):
        object.__setattr__(self, 'a', a)

    def __setattr__(self, name, value):
        print('Setting {} to {}'.format(name, value))
        object.__setattr__(self, name, value)


c = C(10)
c.a += 1

Running that snippet produces:

Setting a to 11

The issue with the code you posted is that `+=` calls `__getattribute__` first before it calls `__setattr__`. That is what fails if the attribute doesn't already exist.

The solution is to make sure the attributes are initialized before the call to bump():

class C(object):

    def __init__(self, a, b, c):
        object.__setattr__(self, 'a', a)
        object.__setattr__(self, 'b', a)
        object.__setattr__(self, 'c', a)

In addition to that fix, there are other errors as well (in inspect for example) but this should get you started.

Problem

Is __setattr__ called when an existing attribute is incremented? I have a class called C, and I'm trying to overload __setattr__. This is a section of code from inside the class C: ``` class C: def bump(self): self.a += 1 self.b += 1 self.c += 1 def __setattr__(self,name,value): calling = inspect.stack()[1] if 'private_' in name: raise NameError("\'private_\' is in the variable name.") elif '__init__' in calling.function: self.__dict__['private_' + name] = value elif name.replace('private_', '') in self.__dict__: if self.in_C(calling): if name.replace('private_', '') in self.__dict__.keys(): old_value = self.__dict__[name.replace('private_', '')] new_value = old_value + value self.__dict__[name.replace('private_', '')] = new_value else: self.__dict__[name.replace('private_','')] = value else: raise NameError() else: self.__dict__[name] = value ``` __setattr__, according to the Python docs, object.__setattr__(self, name, value): Called when an attribute assignment is attempted. This is called instead of the normal mechanism (i.e. store the value in the instance dictionary). name is the attribute name, value is the value to be assigned to it. I know you can assign a value to a variable (ex: `C.__dict__[name] = value`), but what about when an existing attribute is incremented, like `self.a += 1` in `bump()`? Assuming that the attributes a, b, and c already already defined, I called `bump()`, which then called `__setattr__`. However, I get this error: ``` Error: o.bump() raised exception TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int' ``` Is setattr called when an existing attribute is incremented? If so, how would I increment the existing attribute inside setattr? Note: Assume that `bump()` is called after a, b, and c are defined. Also, `in_C(calling)` is a function that checks if `__setattr__` was called from `__init__`, some method inside C, or a method outside of C. Tell me if any further clarification is needed.

Original source

Related problems