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?
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