-1

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?

martineau
  • 119,623
  • 25
  • 170
  • 301
Amistad
  • 7,100
  • 13
  • 48
  • 75
  • Why not simply make it a property? – TigerhawkT3 Feb 26 '19 at 07:19
  • how would i do that ? – Amistad Feb 26 '19 at 07:20
  • 1
    `my_dict = {20:'key1'}` has no attr `20` it is really so, it has key `20`. – Brown Bear Feb 26 '19 at 07:21
  • https://stackoverflow.com/questions/17330160/how-does-the-property-decorator-work – TigerhawkT3 Feb 26 '19 at 07:22
  • 2
    You never actually set any attributes. Your instances doesn't have a response attribute, you've intercepted that and simply printed a message. So `getattr(my_dict,self.response)` will fail, since `self.response` does not exist. Even if it *did*, you will fail with `getattr(my_dict, 20)`, since your dict doesn't have an attribute `20` (that's not really a valid attribute to access, so it just fails with a type error, since the argument to `setattr` and `getattr` must be `str` objects) – juanpa.arrivillaga Feb 26 '19 at 07:23

1 Answers1

2

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)

rajatppn
  • 440
  • 2
  • 7
napuzba
  • 6,033
  • 3
  • 21
  • 32
  • Pycharm gives this warning..Passing Base instead of super. Is this intentional? less... (⌘F1) Inspection info: This inspection checks for calls of a method by class while passing an instance of a different class as self parameter: foo = Foo() Bar.baz(foo, *more) Sometimes this may be intentional and correct. But when unintentional, this leads to subtle bugs. Is this fine ? – Amistad Feb 27 '19 at 04:22