0

I want to override the __setattr__ method on python classes using python 3.4.3. I found this answer but it does not seem to work as I get an error.

The full code is as follows:

class TestClass(object):

    def __init__(self):
        self.x = 4

    def __setattr__(self, name, value):
        # do something special given the 'name'

        #default behavior below
        super(TestClass).__setattr__(name, value)

test = TestClass()

and the error is

Traceback (most recent call last):
  File "client_1.py", line 26, in <module>
    test = TestClass()
  File "client_1.py", line 17, in __init__
    self.x = None
  File "client_1.py", line 23, in __setattr__
    super(TestClass).__setattr__(name, value)
AttributeError: 'super' object has no attribute 'x'

I assume the attribute x cannot be set as it is not yet defined. And the line trying to define this atribute (in __init__) cannot define the attribute, as it calls the overwritten method...

How to define the attribute x without implicity calling the overwritten __setattr__ method then?

Community
  • 1
  • 1
Alex
  • 41,580
  • 88
  • 260
  • 469

2 Answers2

4

super doesn't need arguments in Python3 (at least in the case of overriding instance methods):

super().__setattr__(name, value)

is the equivalent of Python2's

super(MyClass, self).__setattr__(name, value)

which still works though.

user2390182
  • 72,016
  • 6
  • 67
  • 89
  • 4
    Never pass `self.__class__` to `super`. `self.__class__` is the wrong class if you create a grandchild class. – user2357112 Jun 06 '16 at 19:31
  • 1
    I must have called it with python2 by accident. Your suggestion (and the one I linked) works fine... – Alex Jun 06 '16 at 19:34
3

You called super with just the class, which is valid in some cases, but in this case you wanted super for the instance. In Python 2, you would call it with the class and self, in Python 3 you can call it without arguments.

class Spam:
    def __setattr__(self, name, value):
        # super(Spam, self).__setattr__(name, value)  # old, but still works
        super().__setattr__(name, value)  # new and cool

spam = Spam()
spam.eggs = 'python'  # works
davidism
  • 121,510
  • 29
  • 395
  • 339