Be the two classes Point()
and Circle()
defined below:
class Point:
def __init__(self, x, y):
self._x = x
self._y = y
@property
def x(self):
return self._x
@x.setter
def x(self, x):
self._x = x
@property
def y(self):
return self._y
@y.setter
def y(self, y):
self._y = y
def __repr__(self):
return f"{self._x}, {self._y}"
def move(self, x, y):
self._x = x
self._y = y
return self._x, self._y
class Circle:
def __init__(self, radius, x, y):
self._radius = radius
self.x = x
self.y = y
def move(self, x, y):
Point.move(self, x, y)
def __repr__(self):
return f"radius = {self._radius}, \nx = {self.x},\ny = {self.y}"
point1 = Point(12, 3)
print(point1)
point1.y = 0
print(point1)
point1.move(55, 7)
print(point1)
circle1 = Circle(4, 1, 1)
print(circle1)
circle1.move(2, 2)
print(circle1)
I've tried to develop the method move(x,y)
in the Circle calling the method move(x,y) from the class Point, without using inheritance. Firstly an object was initialized:
circle1 = Circle(4,1,1)
but when you use circle1.move(2,2)
the circle position is still (1,1): What is wrong?
I want to use _x and _y to simulates private variables!
The problem there is that you are not using "composition" - you are just randomly calling Point.move
from within a method in your circle class. That call will fail, as it would fail if placed anywhere else: Point.move
is an instance method, and it needs an instance of point to work on.
For "composition" you need to have instances of the other class that are attributes on your class - and then you call upon the methods on those instances when required.
For example, your "Circle" could have a ".center" attribute that is a point. And then, you just call circle.center.move
in an instance - or, if you want a .move
method in the circle class itself:
class Circle:
def __init__(self, radius, x, y):
self._radius = radius
self.center = Point(x, y)
def move(self, x, y):
self.center.move(x, y)
def __repr__(self):
return f"Circle center at ({self.point}), radius: {self.radius}"
Your code attempted to call a method in Point
passing an instance of Circle
. While Python 3 allows this, it is a sheer coincidence that it almost worked (if the "x" and "y" names in Circle where the same as in "Point" it would have worked as it is demonstrated in Dani's answer) - but that is not "OOP" nor "Composition", and just does not raise a runtime error because Python 3 treats instance methods in classes just as functions.
A "circle" is not a "point". Thinking about geometry, you could say that "Circle" and "Point" partake some attributes and methods - Python allow you to share those by using multiple inheritance, and what we call "mixins" - - So you could have a "LocationMixin" class thatwould have the "x" and "y" attributes, and the "move" method and be an ancestor of both "Point" and "Circle", and that would work.
Your composition problem apart, it is important to note that in Python it is not important to try to make attributes "private", and define getters and setters for public consunption - Your point class would work just as well if it is simply written as:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"{self.x}, {self.y}"
def move(self, x, y):
self.x = x
self.y = y
return self.x, self.y
The getter and setter will make sense if you want to validate that x and y ae set to numbers, or validate value ranges - otherwise, they are just redundant.
An interesting thing is that Python designs its "properties" so that you can change the attributes to have the getters and setters and add these validations on a later point, without breaking any compatibility with the previous versions of the class (Point) .
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With