nelt22
nelt22

Reputation: 410

Constructor overwrites previous values of already created object

I'm relatively new to Python. I was working in a project to create objects Square and Points. A Square is composed of 4 points which are the upper left corner, upper right corner and so on.

Now in my main function I create 4 point objects and I send them to the constructor of Square class, it creates my Square.

When I do the same for another Square with different values for the point objects, the values for my previously created Square are overwritten, so at the end I have two same objects. Do you know why this is happening?

This is my code:

class Point(object):
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y

class Square(object):
    ul = Point()
    ll = Point()
    ur = Point()
    lr = Point()
    def __init__(self, ul, ll, ur, lr):
        self.ul.x = ul.x
        self.ll.x = ll.x
        self.ur.x = ur.x
        self.lr.x = lr.x
        self.ul.y = ul.y
        self.ll.y = ll.y
        self.ur.y = ur.y
        self.lr.y = lr.y

def main():
    ul1 = Point(1, 2)
    ll1 = Point(1, 1)
    ur1 = Point(2, 2)
    lr1 = Point(2, 1)
    s1 = Square(ul1, ll1, ur1, lr1)

    ul2 = Point(3, 3)
    ll2 = Point(3, 2)
    ur2 = Point(4, 3)
    lr2 = Point(4, 2)
    s2 = Square(ul2, ll2, ur2, lr2)

    #At this point s1 and s2 have the same values...

if __name__ == '__main__':
    main()

Any kind of help will be highly appreciated ;)

Cheers!

Upvotes: 1

Views: 706

Answers (1)

msvalkon
msvalkon

Reputation: 12077

It's happening because you've defined the four corner variables in the Square class as class variables. This means that they are shared between all instances of that class.

Here's a cleaner version of your Square class. There are instance variables self.ul, self.ll and so forth. You don't need to specify a Point instance for these in the __init__ because you're already doing that in the main function where you pass them as arguments.

class Square(object):
    def __init__(self, ul, ll, ur, lr):
        self.ul = ul
        self.ll = ll
        self.ur = ur
        self.lr = lr 

def main():
    s1 = Square(Point(1, 2), Point(1, 1), Point(2, 2), Point(2, 1))
    s2 = Square(Point(3, 3), Point(3, 2), Point(4, 3), Point(4, 2))
    print s1.ul.x # 1
    print s1.lr.y # 2

HyperBoreus makes a good point about passing points as arguments, as if you pass the same point object to two squares and modify it, any changes you make will reflect in both squares.

You can get around this by passing corner values to the __init__ instead of Point objects, and then create the instances in the __init__

Here's a complete example:

class Point(object):
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y

class Square(object):
    def __init__(self, ul, ll, ur, lr):
        self.ul = Point(ul[0], ul[1])
        self.ll = Point(ll[0], ll[1])
        self.ur = Point(ur[0], ur[1])
        self.lr = Point(lr[0], lr[1])

def main():
    square_one = Square((1, 2), (1, 1), (2, 2), (2, 1))
    square_two = Square((3, 3), (3, 2), (4, 3), (4, 2))

I'd also advice you to use more readable variable names. You save nothing by shortening upper_right to ur. On the contrary, when you return to this code in a year, you'll curse at yourself.

Upvotes: 5

Related Questions