Проблема в том, что вы не используете «состав» - вы просто случайным образом вызываете Point.move
из метода в вашем классе круга. Этот вызов потерпит неудачу, как и если бы он был помещен где-либо еще: Point.move
- это метод экземпляра, и ему нужен экземпляр точки для работы.
Для "композиции" вам нужно иметь экземпляры другой класс, являющийся атрибутами вашего класса, а затем при необходимости вы вызываете методы в этих экземплярах.
Например, ваш «Круг» может иметь атрибут «.center», который является точкой. И затем, вы просто вызываете circle.center.move
в экземпляре - или, если вам нужен метод .move
в самом классе круга:
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}"
То, что вы пытались сделать
Ваш код попытался вызвать метод в Point
, передав экземпляр Circle
. Хотя Python 3 позволяет это, это чистое совпадение, что это почти сработало (если имена «x» и «y» в Circle, где то же самое, что и в «Point», это сработало бы, как показано в ответе Дани) - но это не "OOP" и не "Composition", и просто не вызывает ошибку времени выполнения, потому что Python 3 рассматривает методы экземпляра в классах как функции.
«Круг» - это не «точка». Думая о геометрии, вы можете сказать, что «Круг» и «Точка» разделяют некоторые атрибуты и методы - Python позволяют вам делиться ими, используя множественное наследование, и то, что мы называем «миксинами» - - так что вы можете иметь «LocationMixin» класс, который будет иметь атрибуты «x» и «y», а также метод «move» и будет предком «Point» и «Circle», и это будет работать.
Упрощенный код
Помимо проблем с составлением, важно отметить, что в Python не важно пытаться сделать атрибуты "приватными" и определять методы получения и установки для публикации c consunption - Ваш класс точек будет работать так же, как хорошо, если это просто записать как:
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
Получатель и установщик будут иметь смысл, если вы захотите проверить, что x и y установлены как числа, или проверить диапазоны значений - в противном случае они просто избыточны.
Интересно то, что Python проектирует его "свойства", так что вы можете изменить атрибуты, чтобы получить геттеры и сеттеры и добавить t эти проверки на более позднюю точку, не нарушая совместимость с предыдущими версиями класса (точка).