I have some code like this:
class Person(object):
def drive(self, f, t):
raise NotImplementedError
class John(Person):
def drive(self, f, t):
print "John drove from %s to %s" % (f,t)
class Kyle(Person):
def drive(self, f, t):
print "Kyle drove from %s to %s" % (f,t)
class RandomPerson(Person):
# instansiate either John or Kyle, and inherit it.
pass
class Vehicle(object):
pass
class Driver(Person, Vehicle):
def __init__(self):
# instantiate and inherit a RandomPerson somehow
pass
d1 = Driver()
d1.drive('New York', 'Boston')
>>> "John drove from New York to Boston"
d2 = Driver()
d2.drive('New Jersey', 'Boston')
>>> "Kyle drove from New Jersey to Boston"
How could i implement RandomPerson, with the following requirements:
- calling
person = RandomPerson()must return aRandomPersonobject. RandomPersonshould subclass eitherJohnorKylerandomly.
In my original answer (which I deleted because it was just plain wrong) I said I would consider doing it like this:
This way is an adaptation of the Python Borg idiom; the idea was that everything that matters about an object is contained in its
__dict__.However, this only works when overwriting objects of the same class (which is what you are doing in the Borg idiom); the object
__dict__only contains state information pertaining to object instance, not the object class.It is possible to switch out the class of an object like so:
However, doing it this way would mean that the call to
RandomPersonwould then not return an instance ofRandomPersonper your requirement, but ofKyleor ofJohn. So this is a no go.Here is a way to get a
RandomPersonobject that acts likeKyleorJohn, but isn't:This one - very similar to the Borg idiom, except doing it with classes instead of instance objects and we're only copying the current version of the chosen class dict - is really pretty evil: we have lobotomized the
RandomPersonclass and (randomly) stuck the brains of aKyleorJohnclass in place. And there is no indication, unfortunately, that this happened:So we still haven't really subclassed
KyleorJohn. Also, this is really really evil. So please don't do it unless you have a really good reason.Now, assuming you do in fact have a good reason, the above solution should be good enough if all you are after is making sure you can use any class state information (methods and class attributes) from
KyleorJohnwithRandomPerson. However, as illustrated prior,RandomPersonstill isn't a true subclass of either.Near as I can tell there is no way to actually randomly subclass an object's class at instance creation AND to have the class maintain state across multiple instance creations. You're going to have to fake it.
One way to fake it is to allow
RandomPersonto be considered a subclass ofJohnandKyleusing the abstract baseclass module and__subclasshook__, and adding that to yourPersonclass. This looks like it will be a good solution since thePersonclass is an interface and isn't going to be directly used, anyway.Here's a way to do that:
Now
RandomPerson- though it technically is not a subclass - is considered to be a subclass ofKyleorJohn, and it also shares the state ofKyleorJohn. In fact, it will switch back and forth between the two, randomly, every time a new instance is created (or whenRandomPerson.identityis changed). Another effect of doing things this way: if you have multipleRandomPersoninstances, they all share the state of whateverRandomPersonhappens to be in that moment -- i.e.,rperson1might start out beingKyle, and then whenrperson2is instantiated, bothrperson2ANDrperson1could beJohn(or they could both beKyleand then switch toJohnwhenrperson3is created).Needless to say, this is pretty weird behavior. In fact it is so weird, my suspicion is that your design needs a complete overhaul. I really don't think there is a very good reason to EVER do this (other than maybe playing a bad joke on someone).
If you don't want to mix this behavior into your
Personclass, you could also do it separately: