0

I want to implement the move method in Shape class in has-a relation(So Shape class does not inherit CPoint class), but have a problem in setting class variables.

The given code is:

class CPoint:
    def __init__(self, x = 0, y = 0):
        self.__x = x
        self.__y = y
    
    def __str__(self):
        return f"pos({self.__x},{self.__y})"
    
    def get_x(self):
        return self.__x
    
    def set_x(self, new_x):
        self.__x = new_x
    
    def get_y(self):
        return self.__y
    
    def set_y(self, new_y):
        self.__y = new_y
    
    def move(self, a, b):
        self.__x += a
        self.__y += b
        return CPoint(self.__x,self.__y)
    

class Shape:
    def __init__(self, color = "yellow", filled = True, pos = CPoint()): 
        #So each pos must reference the different CPoint() instance 
        self.__color = color
        self.__filled = filled
        self.__pos = pos
    
    def __str__(self):
        return f"{self.__pos}({self.__color},{self.__filled})"
    
    def move(self, a, b):
        self.__pos.move(a,b)
        
        if type(self) == Shape:
            return f"{self}"
        else:
            return f"{self.__pos}{self}"


def main():
    a = Shape()
    b = Shape("red")
    a.move(2,3)
    print(b.move(4,5))
    
main()

the result is:

pos(0,0)(yellow,True)
pos(0,0)(red,True)
pos(2,3)(yellow,True)
pos(6,8)(red,True)

and the result should be like:

pos(0,0)(yellow,True)
pos(0,0)(red,True)
pos(2,3)(yellow,True)
pos(4,5)(red,True)

And I executed the code on the python tutor, and the visualization of the code is like this: python tutor visualization

So Shape() and Shape("red") objects should reference different CPoint instance (cuz they have their own position data), but they reference the same instance even though I set the default parameter like 'pos = CPoint()'.

Can someone please explain why they're referencing the same instance, and how to get around it?

2
  • I guess because the type of self is always Shape?! as in if type(self) == Shape: it is a reference to itself and that is Shape therefore always True Commented May 23, 2021 at 14:27
  • @Ivonet There're other classes like circles or rectangle in original code, so that statement is needed. I think I have a problem on constructor part... Commented May 23, 2021 at 14:34

1 Answer 1

1

This is how python does argument defaults, default arguments are initialized once during function declaration and not every time when the function is called like you might expect if you've used other languages like Javascript https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments

Because of this, the same CPoint() instance is shared between different constructor calls.

To avoid this behavior you could try setting it inside the function itself.

class Shape:
    def __init__(self, color = "yellow", filled = True, pos = None):
        if pos is None:
            pos = CPoint()
        #So each pos must reference the different CPoint() instance 
        self.__color = color
        self.__filled = filled
        self.__pos = pos
Sign up to request clarification or add additional context in comments.

3 Comments

but pos is an arg and either it needs to go before the keyword args or should have a default value...
My bad, I updated the answer with the correct fix.
Thank you so much. That's exactly what I was looking for.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.