0

Suppose I have the following classes:

class Plain(object):
    def speak(self):
        print 'ho-hum'

class Fancy(Plain):
    def exult(self):
        print 'huzzah!'

plain = Plain()
plain.speak()
# ho-hum
plain.exult()
# ---------------------------------------------------------------------------
# AttributeError                            Traceback (most recent call last)
# <ipython-input-585-5f782c9ea88b> in <module>()
# ----> 1 plain.exult()
fancy = Fancy()
fancy.speak()
# ho-hum
fancy.exult()
# huzzah!

... and suppose that, for some reason, I want to "promote" an instance of Plain so that it becomes an instance of Fancy.

I know that I can always modify the instance's __class__ attribute:

plain.__class__ = Fancy
plain.exult()
# huzzah!

...but I gather from various SO posts (e.g., here, here) that this is not a good thing to do (at least not in production code).

Is there a more "production-code-worthy" way to promote an instance to a subclass?


FWIW, the real-world use-case that brings me to this problem is the following. I'm working with a 3rd-party library that implements a client for a web service. Among the things this client can do is return instances of various classes. These classes provide very few methods, and the few they provide are very weak. I can easily write subclasses for these classes with more, and more powerful, methods, but in order for them to be useful, I'd also need to write wrappers for those API functions that currently return instances of the API's original classes. Invariably, this wrappers would only have to promote the instances returned by the original ("wrappee") functions to instances of my enhanced subclasses.

martineau
  • 119,623
  • 25
  • 170
  • 301
kjo
  • 33,683
  • 52
  • 148
  • 265
  • 1
    Possible duplicate of [How to convert (inherit) parent to child class?](http://stackoverflow.com/questions/10030412/how-to-convert-inherit-parent-to-child-class) – kwarunek Jul 30 '16 at 14:26
  • 1
    What you want to do is the ["state" design pattern](https://en.wikipedia.org/wiki/State_pattern). There should be a container object that will take care of creating an instance of the proper class. Don't try to hack by fiddling with the low-level bits. – λuser Jul 30 '16 at 15:01

1 Answers1

3

You could use of course

fancy = Fancy(plain)

and define in the constructor of Fancy, what should happen if an instance of Plain is given as argument.

Example:

class Plain:
   def __init__(self, foo, bar):
       self.foo = foo
       self.bar = bar
       self.status = 'plain'

class Fancy:
    def __init__(self, something):
         if isinstance(something, Plain):
              self.foo = something.foo
              self.bar = something.bar
         self.status = 'fancy'
Rafael Albert
  • 445
  • 2
  • 8
  • For OP's use case, I would go with a wrapper (has-a) rather than a subclass (is-a). But either way, you would use Fancy's __init__ like you have already said. – Kenny Ostrom Jul 30 '16 at 14:38