Search code examples
pythonpython-3.xclassgetattrsetattr

Using __setattr__ method with getattr in a class


I have a Python class as follows:

class Base:
    def __init__(self, response=20):
        self.response = response

    def func1(self):
       self.response = 10

    def func2(self):
        self.response = 20

    def func3(self):
        self.response = 30

Every time the value of response changes, I need it to be captured. So I defined a __setattr__ method as follows:

class Base:
    def __init__(self, response=20):
        self.response = response

    def __setattr__(self, name, value):
        if name == 'response':
            print('{} is set to {}'.format(name, value))

    def func1(self):
       self.response = 10

    def func2(self):
        self.response = 20

    def func3(self):
        self.response = 30

Output:

=============================================================
In [10]: a = Base()
response is set to 20

In [11]: a.func1()
response is set to 10

In [12]: a.func2()
response is set to 20

Works really well.

Now I introduced one more class attribute whose value is initialized by a dictionary lookup as follows:

my_dict = {20:'key1'}

class Base:
    def __init__(self, response=20):
        self.response = response
        self.key = getattr(my_dict,self.response).value

    def __setattr__(self, name, value):
        if name == 'response':
            print('{} is set to {}'.format(name, value))

    def func1(self):
        self.response = 10

    def func2(self):
        self.response = 20

    def func3(self):
        self.response = 30

This gives an error stating:

 ----> 6         self.key = getattr(my_dict,self.response)
AttributeError: 'Base' object has no attribute 'response'

What am I doing wrong.Also if I remove the __setattr__ method, the getattr starts working. What is the issue here?


Solution

  • You should call the parent implementation of __setattr__ to actually create the attribute:

    def __setattr__(self, name, value):
        if name == 'response':
            print('{} is set to {}'.format(name, value))
        super.__setattr__(self,name,value)
    

    Also if you want the value associated with dictionary's key use :

    self.key = my_dict.get(self.response)
    

    You can find more details by looking at the official documentation here(3.7) and here(2.7)