Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble with assigning (or re-overloading) the assignment operator in Python

Tags:

python

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
like image 760
chappy Avatar asked Apr 24 '13 22:04

chappy


People also ask

How do you overload an assignment operator in Python?

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.

How do you make an operator in Python?

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.

How do you add two class objects in Python?

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.


2 Answers

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()
like image 152
Eric Avatar answered Oct 07 '22 12:10

Eric


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)
like image 36
Benjamin Hodgson Avatar answered Oct 07 '22 13:10

Benjamin Hodgson