Brandon MacLeod
Brandon MacLeod

Reputation: 55

Python - point class not getting correct output

So I have a point class and a line class that both have a scale method.

class Point:

    def __init__(self, x, y):
        if not isinstance(x, float):
            raise Error("Parameter \"x\" illegal.")
        self.x = x
        if not isinstance(y, float):
            raise Error ("Parameter \"y\" illegal.")
        self.y = y

    def scale(self, f):
        if not isinstance(f, float):
            raise Error("Parameter \"f\" illegal.")
        self.x = f * self.x
        self.y = f * self.y

    def __str__(self):
        return '%d %d' % (int(round(self.x)), int(round(self.y)))

class Line:

    def __init__(self, point0, point1):
        self.point0 = point0
        self.point1 = point1

    def scale(self, factor):
        if not isinstance(factor, float):
            raise Error("Parameter \"factor\" illegal.")
        self.point0.scale(factor)
        self.point1.scale(factor)

    def __str__(self):
        return "%s %s" % (self.point0, self.point1)

So one of the tests I do on this code is to check for a shallow copy which I do in this test code.

p0.scale(2.0)
p1.scale(2.0)
print line

The problem is the print line gives me 0 2 4 6 and it should give me 0 1 2 3. So why is it printing multiples of 2 instead? The scale method is supposed to return the scaled values and for all the other test cases it prints the expected values however just with this test code it prints values I didn't expect. Here's how the values of p0 and p1 are set up:

print '********** Line'
print '*** constructor'
p0 = Point(0.0, 1.0)
p1 = Point(2.0, 3.0)
line = Line(p0,p1)
print line

Upvotes: 1

Views: 153

Answers (2)

Jared Goguen
Jared Goguen

Reputation: 9010

In your __init__ method for Line, you are assigning the names self.point0 and self.point1 to the two points that are passed in. This does not make a new copy, only gives the objects in memory another name. If you change this method to

def __init__(self, point0, point1):
    self.point0 = Point(point0.x, point0.y)
    self.point1 = Point(point1.x, point1.y)

then everything should work as intended. Or, you can use the copy module:

from copy import copy

class Line:
    def __init__(self, point0, point1):
        self.point0 = copy(point0)
        self.point1 = copy(point1)

You could also define your own __copy__ and __deepcopy__ methods on your Point class.

def __copy__(self):
    return type(self)(self.x, self.y)

def __deepcopy__(self, memo):
    return type(self)(self.x, self.y)

You can look at this question for more information.

Upvotes: 2

Andriy Ivaneyko
Andriy Ivaneyko

Reputation: 22041

Printing line after scaling p0,p1 by 2 multiply x,y pairs for p0, p1. Line instance values of point0 and point1 pointing to instances of Point which is p0 and p1 appropriately, as result of print line you can see updated value of x,y of each point.

p0 = Point(0,1)
p1 = Point(2,3)
line = Line(p0, p1)
print line # 0 1 2 3
p0.scale(2.0)
p1.scale(2.0)
print line # 0 2 4 6

Upvotes: 0

Related Questions