Не могу разобраться до конца в классах Python. Задаю объекты:
p1 = Point(50,70) # объект класса Point, задающий начальную координату c1 = Color(10,15,10) # задает цвет r1 = Rectangle(p1,40,70,c1) #в нем и загвоздка, а точнее в p1 и c1
Как сделать так, чтобы r1 имел также аргументы x и y и r,g,b, которые имеют p1 и c1 соответственно.
!!! в моем классе Rectangle self.pointIn = pointIn
и self.color = color
явно заданы неправильно
class Point(object): def __init__(self,x=0, y=0): self.x = x self.y = y def modify_point(self, x1,y1): self.x = x1 self.y = y1 def to_tuple(self): return (self.x, self.y) class Color(object): def __init__(self,r=0, g=0, b=0): self.r = r self.g = g self.b = b def to_tuple(self): return (self.r, self.g, self.b) class Rectangle(Point, Color): def __init__(self, pointIn, width, hight, color): self.width = width self.hight = hight self.pointIn = pointIn self.color = color
Прямоугольник может иметь цвет. Прямоугольник сам по себе цветом не является. То есть логичнее использовать: rectangle.color.r
вместо rectangle.r
и не наследовать от Color
(тем более вы уже используете композицию: self.color
определён).
Как сделать так, чтобы r1 имел также аргументы x и y и r,g,b, которые имеют p1 и c1 соответственно.
Если забыть, что это прямоугольники, точки, цвета и рассматривать задачу как упражнение по использованию множественного наследования (которое следует избегать, если вы не знаете точно зачем оно вам нужно в конкретном случае), то чтобы правильно проинициализировать унаследованные атрибуты базовых классов, необходимо вызывать super().__init__(**kwargs)
:
#!/usr/bin/env python3 class A: def __init__(self, a, **kwargs): super().__init__(**kwargs) self.a = a def __repr__(self): keys = sorted(self.__dict__) items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys) return "{}({})".format(type(self).__name__, ", ".join(items)) class B: def __init__(self, b, **kwargs): super().__init__(**kwargs) self.b = b class C(A, B): def __init__(self, c, **kwargs): super().__init__(**kwargs) self.c = c print(C(a=1, b=2, c=3))
super().__init__()
вызов только один в C.__init__()
, не смотря на то что C имеет два базовых класса.
A.__init__()
и B.__init__()
существуют и также вызывают super().__init__()
и все эти методы имеют совместимые аргументы (за счёт **kwargs
). См. Python’s super() considered super!
__repr__
метод (с реализацией из документации types.SimpleNamespace
) определён, чтобы напечатать C объект. Вывод показывает, что все атрибуты правильно установлены.
Ключевое понятие здесь—порядок разрешения методов (MRO)—порядок, в котором вызываются методы базовых классов:
>>> [klass.__name__ for klass in C.mro()] ['C', 'A', 'B', 'object']
С.__init__
ожидаемо вызывает родительский A.__init__
(через super().__init__()
). A
класс не наследует от B
, но A.__init__
вызывает (через super().__init__()
) B.__init__
согласно MRO, который вызывает object.__init__
и цепочка заканчивается.
object
встречается в этом списке только один раз, хотя он является базовым классом как для A
так и B
классов (то есть C
наследует от object
класса дважды). Чтобы вычислить порядок вызовов, в Питоне используется C3-линеаризация суперкласса.