Search code examples
exceptionrecursionpython-3.6setattr

infinite recursion when overriding __setattr__


I want to create the class 'Human' with attributes "name" and "gender". I want to restrict assignment of the "gender" attribute to only "male" or "female". For this purpose, we have overridden __setattr__(self, name, value).

class Human(object):
    def __setattr__(self, name, value):
        if name == 'gender':
            if value in ('male', 'female'):
                self.gender = value
            else:
                raise AttributeError('Gender can only be "male" or "female"')


h = Human()
h.name = 'Sweety'
h.gender = 'female'
print(h.gender)

But I am getting below exception:

  [Previous line repeated 328 more times]
  File "/Users/admin/algorithms/betright_test.py", line 143, in **__setattr__**
    if name == 'gender':
RecursionError: maximum recursion depth exceeded in comparison

But If I pass wrong gender(h.gender = 'f') it gives me proper Error(AttributeError: Gender can only be "male" or "female")

I am not able to figure out that what went wrong when I passed the proper gender.


Solution

  • The problem is that your __setattr__ function contains the line self.gender =... which calls __setattr__ in an infinite loop. You need to store the attribute without recursively calling __setattr__ by using the superclass method:

    super().__setattr__(name, value)
    

    Note also in your example code, if you tried to print h.name, you'd get an AttributeError, as your __setattr__ function never set the attribute. So what you want is something like:

    def __setattr__(self, name, value):
        if name == 'gender':
            if value not in ('male', 'female'):
                raise AttributeError('Gender can only be "male" or "female"')
        super().__setattr__(name, value)