I'm having trouble assigning the assignment operator.
I have successfully overloaded __setattr__
. But after the object is initialized, I want __setattr__
to do something else, so I try assigning it to be another function, __setattr2__
.
Code:
class C(object):
def __init__(self):
self.x = 0
self.__setattr__ = self.__setattr2__
def __setattr__(self, name, value):
print "first, setting", name
object.__setattr__(self, name, value)
def __setattr2__(self, name, value):
print "second, setting", name
object.__setattr__(self, name, value)
c = C()
c.x = 1
What I get:
first, setting x
first, setting __setattr__
first, setting x
What I want/expect:
first, setting x
first, setting __setattr__
second, setting x
To perform operator overloading, Python provides some special function or magic function that is automatically invoked when it is associated with that particular operator. For example, when we use + operator, the magic method __add__ is automatically invoked in which the operation for + operator is defined.
Python does not allow to create own operators, a design decision which was made for a good reason and you should accept it instead of seeing this as a problem and inventing ways around it. It is not a good idea to fight against the language you are writing the code in.
In other words, to add two objects together in Python, the class implementing the objects needs to implement the __add__() method. Another related method is the __radd__() method. This flips a+b with b+a.
From the docs:
Special method lookup for new-style classes
For new-style classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary. That behaviour is the reason why the following code raises an exception (unlike the equivalent example with old-style classes):
>>> class C(object): ... pass ... >>> c = C() >>> c.__len__ = lambda: 5 >>> len(c) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: object of type 'C' has no len()
Why not use a flag to indicate that __init__
is still in progress?
class C(object):
def __init__(self):
# Use the superclass's __setattr__ because we've overridden our own.
super(C, self).__setattr__('initialising', True)
self.x = 0
# the very last thing we do in __init__ is indicate that it's finished
super(C, self).__setattr__('initialising', False)
def __setattr__(self, name, value):
if self.initialising:
print "during __init__, setting", name
# I happen to like super() rather than explicitly naming the superclass
super(C, self).__setattr__(name, value)
else:
print "after __init__, setting", name
super(C, self).__setattr__(name, value)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With