Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom addition method fails during string interpolation

#it's python 3.2.3
class point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, point):
        self.x += point.x
        self.y += point.y
        return self

    def __repr__(self):
        return 'point(%s, %s)' % (self.x, self.y)

class Test:
    def __init__(self):
        self.test1 = [point(0, i) for i in range(-1, -5, -1)]
        self.test2 = [point(i, 0) for i in range(-1, -5, -1)]

        print('%s\n+\n%s\n=\n%s' % (self.test1[0], self.test2[0], self.test1[0] + self.test2[0]))

test = Test()
input()

The output of this program is

point(-1, -1)
+
point(-1, 0)
=
point(-1, -1)

But it should be

point(-1, -1)
+
point(-1, 0)
=
point(-2, -1)

But if I do

print(point(-1, -1) + point(-1, 0))

It works perfectly

I want to know why, and how to solve this problem

p.s. sorry if my english is bad :)

like image 932
foxneSs Avatar asked May 23 '12 15:05

foxneSs


2 Answers

Your __add__ function modifies the left-hand argument to +. For example:

>>> x = point(0, 0)

>>> x + point(1, 1)
point(1, 1)

>>> x
point(1, 1)

You should change __add__ to be like

def __add__(self, oth):
    return point(self.x + oth.x, self.y + oth.y)
like image 91
Danica Avatar answered Nov 13 '22 02:11

Danica


You say the output should be:

point(-1, -1)
+
point(-1, 0)
=
point(-2, -1)

In fact it should be:

point(0, -1)
+
point(-1, 0)
=
point(-1, -1)

Because you are creating that first point with [point(0, i) for i in range(-1, -5, -1)] (note the x parameter is 0).

This is a consequence of (self.test1[0], self.test2[0], self.test1[0] + self.test2[0])) being evaluated - the addition modifies the first point in that tuple (they are the same object). This is also why your second example works correctly (or appears to) - you only print the modified object once.

The implementation of __add__ you provide is suitable for __iadd__ to implement the += operator. A correct implementation should create a completely new point object:

def __add__(self, oth):
    return point(self.x + oth.x, self.y + oth.y)
like image 38
Marcin Avatar answered Nov 13 '22 03:11

Marcin