¿Convertir un objeto BaseClass en un objeto SubClass idiomáticamente?

Hay una clase base Base y una subclase Special .

 class Base(object): def __init__(self, name): self.name = name def greet(self): return 'Hello %s' % self.name class Special(Base): def __init__(self, name): super(Special, self).__init__(name) def rhyme(self): return 'Hi %s! How are you? Fine, thanks. What about you?' % self.name 

¿Cómo puedo convertir una instancia de Base en una instancia Special ? Actualmente tengo un classmethod definido en Special que simplemente reasigna __dict__ :

 class Special(Base): ... @classmethod def from_base(cls, baseobj): special = Special() special.__dict__ = baseobj.__dict__ return special 

¿Es esto idiomático? Si no, ¿qué sería?

PS Un escenario de ejemplo: la clase base es alguna implementación predeterminada. En la naturaleza, es probable que encuentre objetos de la clase base. Ahora, en algún proyecto, la clase base ha sido subclases y se han agregado métodos especiales a la subclase. Ahora, en su mayoría, todavía trabaja con objetos de clase base, pero de vez en cuando querrá “actualizar” a la clase especial, porque necesitará acceso a algunos métodos.

Puede lograr esto definiendo un constructor alternativo y reasignando el atributo __class__ la instancia.

 class Base(object): def __init__(self, name): self.name = name def greet(self): return 'Hello %s' % self.name @classmethod def alt_constructor(cls, *args, **kwargs): obj = cls(*args, **kwargs) obj.__class__ = Special return obj class Special(Base): def __init__(self, name): super(Special, self).__init__(name) def rhyme(self): return 'Hi %s! How are you? Fine, thanks. What about you?' % self.name >>> s = Base.alt_constructor("test") >>> print s.rhyme() Hi test! How are you? Fine, thanks. What about you? 

EDITAR:

Trasladado el constructor de Special a Base .

Si no puede modificar la clase Base , puede agregar un método de clase a Special que cambiará la clase de cualquier objeto que se le pase.

 class Base(object): def __init__(self, name): self.name = name def greet(self): return 'Hello %s' % self.name class Special(Base): def __init__(self, name): super(Special, self).__init__(name) def rhyme(self): return 'Hi %s! How are you? Fine, thanks. What about you?' % self.name @classmethod def convert_to_special(cls, obj): obj.__class__ = Special >>> b = Base("test") >>> print type(b)  >>> Special.convert_to_special(b) >>> print type(b)  

Una solución más general sería crear una mezcla que se pueda agregar a cualquier clase.

 class ConverterMixin(object): @classmethod def convert_to_class(cls, obj): obj.__class__ = cls class Special(ConverterMixin, Base): def __init__(self, name): super(Special, self).__init__(name) def rhyme(self): return 'Hi %s! How are you? Fine, thanks. What about you?' % self.name >>> b = Base("test") >>> print type(b)  >>> Special.convert_to_class(b) >>> print type(b)  

En realidad puedes, pero no creo que debas. Python, en lugar de encasillado, tiene que tipear el pato para resolver este tipo de situaciones.

De todos modos, aquí está el código:

 >>> base = Base("I'm a base!") >>> hasattr(base, 'rhyme') False >>> base.__class__ = Special >>> hasattr(base, 'rhyme') True >>> base.rhyme() "Hi I'm a base!! How are you? Fine, thanks. What about you?"