2015-06-08 3 views
0

Этот вопрос очень похож на this, но у моего производного класса есть дополнительные члены данных. Рассмотрим два класса ниже. Мне нужно преобразовать экземпляры объектов Circle в экземпляры ColoredCircle. В моем реальном, менее упрощенном приложении я бы предпочел избежать повторной инициализации тысяч этих объектов, убедившись, что я правильно вызываю конструктор производного класса с базовыми членами экземпляра и еще что-то.Выполнение экземпляра производному классу с дополнительными элементами данных

class Circle(object): 
    def __init__(self, radius): 
     self.radius = radius 
    def area(self): 
     return pi * self.radius**2 
    def __str__(self): 
     return 'Circle: %f' % self.radius 

class ColoredCircle(Circle): 
    def __init__(self, radius, color): 
     super(ColoredCircle, self).__init__(radius) 
     self.color = color 
    def __str__(self): 
     return 'ColoredCircle: %f %s' % (self.radius, self.color) 
    def getColor(self): 
     return self.color 

кажется, что если у меня есть Circle экземпляр c, я могу изменить его __class__ к ColoredCircle, и однажды я также установил c.color, то кажется, что все работает, как если бы я инстанс его с ColoredCircle, чтобы начать с.

Вопросы:

  1. Существуют ли какие-либо крупные подводные камни или другие причины, было бы неплохо, чтобы сделать что-то вроде следующего, чтобы привести экземпляр базового класса в экземпляр производного класса?
  2. Есть ли лучший способ сделать это?

c = Circle(3) 
print c      # Circle: 3.000000 
print c.area()    # 28.274333882308138 
c.__class__ = ColoredCircle 
print c.area()    # still works 
print c.getColor()   # AttributeError: 'ColoredCircle' object has no attribute 'color' 
c.color = 'blue' 
print c      # ColoredCircle: 3.000000 blue 
+0

Вопрос 0 должен быть: зачем вы хотите это сделать? Если вы не можете объяснить причину, я закрываю этот вопрос как гипотетический. –

+0

@ 200_success Это определенно не гипотетично, поскольку это то, с чем я столкнулся на работе. У меня есть функция, которая дает мне набор экземпляров базового типа, а позже мне нужно передать производный тип, чтобы я мог использовать функциональные возможности этого типа. –

+0

Не могли бы вы объяснить, почему вы создаете неправильный круг? –

ответ

3

(1) есть какие-либо крупные подводные камни или другие причины, было бы неплохо сделать что-то вроде следующего, чтобы привести экземпляр базового класса в экземпляр производный класс?

Это грязный грязный грязный хак и нарушение всего, что хорошо и свято в этом мире. Котята погибнут в массах.

Это вопиющее нарушение инкапсуляции. Он работает только с интимным знанием производного класса. Зачем переписывать ДНК объекта грязным способом, когда вы можете легко создать чистый объект с помощью конструктора.

Если вы полностью знаете все детали целевого объекта на 100%, то обязательно, это работает, но это очень грязный хак. Если это одноразовая коррекция или что-то в этом роде, вы, вероятно, можете уйти от нее, иначе это станет кошмаром для обслуживания, как будто в какой-то день что-то изменится в целевом классе, вам придется обновить взломать.

(2) Есть ли лучший способ сделать это?

Да, используйте конструктор для создания объектов другого типа. Не совсем понятно, почему вы неохотно идут по этому очевидному пути.

+0

'Да, используйте конструктор для создания объектов другого типа.' Как я могу это сделать (более) чисто?Мой фактический базовый класс имеет ~ дюжину членов данных. Если я делаю 'cc = ColoredCircle (c.data0, c.data1, <...>, c.data10)', то передают большинство из них в суперструктор 'Circle' из конструктора' ColoredCircle', который кажется, по крайней мере, как подверженный ошибкам и недостижимый. Кроме того, 'Circle' имеет внутренние данные, которые не устанавливаются через его конструктор; Я должен был бы разоблачить этих членов в обоих конструкторах, что еще хуже ухудшит инкапсуляцию. Все это потому, что я не хочу идти по этому пути. –

+0

В вашем вопросе не упоминалось, что их так много. Имейте в виду, что наличие такого большого количества участников является огромным предупреждающим знаком о дизайне. Мы здесь очень плохо начинаем. Но тем не менее, передача дюжины членов в конструктор по-прежнему более безопасна и менее подвержена ошибкам, потому что инструменты могут помочь вам обнаружить проблемы, например неправильное количество аргументов конструктора. Если вы идете по другому пути, вы сами по себе, инструменты не могут помочь, и риск обнаружения неясных ошибок только во время выполнения выше – janos

+0

@SchighSchagh, если проблема состоит из множества аргументов конструктора, то абстрактная коллекция для держи их. – jonrsharpe

Смежные вопросы