32

Assume that we have an object k of type class A. We defined a second class B(A). What is the best practice to "convert" object k to class B and preserve all data in k?

Ivan Chaer
  • 6,980
  • 1
  • 38
  • 48
zoli2k
  • 3,388
  • 4
  • 26
  • 36
  • 2
    In what way are you looking to convert from one to the other? Do you wish to keep all of the member variables of the class B object, but use the parent class A's set of methods? – BrainCore Jan 28 '10 at 09:04
  • 3
    Is this Pretty Poor Polymorphism? Are A and B subclasses of a common superclass? If so, this is the wrong thing to do? Do you wish that A had the same methods as B? This is done through multiple-inheritance. Please explain why you think you need this because -- in Python -- you're doing it wrong if you think you need casting or type conversion. – S.Lott Jan 28 '10 at 11:52
  • Also really curious about your use case. Is this just for fun, or have you found this to be a better way of adressing some problem, other than with the help of classical polymorphism? – vlad-ardelean Jan 04 '15 at 01:04
  • Depending on your problem, one of [these two methods](http://stackoverflow.com/a/597243/952580) for achieving a similar result might be suitable, without feeling like a hack. – Beetle Jan 13 '15 at 16:45

3 Answers3

20

This does the "class conversion" but it is subject to collateral damage. Creating another object and replacing its __dict__ as BrainCore posted would be safer - but this code does what you asked, with no new object being created.

class A(object):
    pass

class B(A):
    def __add__(self, other):
        return self.value + other


a = A()
a.value = 5

a.__class__ = B

print a + 10
jsbueno
  • 99,910
  • 10
  • 151
  • 209
8
a = A() # parent class
b = B() # subclass
b.value = 3 # random setting of values

a.__dict__ = b.__dict__ # give object a b's values

# now proceed to use object a

Would this satisfy your use case? Note: Only the instance variables of b will be accessible from object a, not class B's class variables. Also, modifying variables in a will modify the variable in b, unless you do a deepcopy:

import copy
a.__dict__ = copy.deepcopy(b.__dict__)
BrainCore
  • 5,214
  • 4
  • 33
  • 38
  • 1
    Actually, no variables will be copied. Since `a` and `b` now both share the same `__dict__`, setting `a.value` changes `b.value` too. – Robert Rossney Jan 28 '10 at 10:08
  • Actually on doing this, the "a" object should be destroyed immediately. Else one does end up with two different objects, in different classes sharing the same attributes - there are few worse scenarios than this. (It is scary to play around even at the interactive prompt) – jsbueno Nov 25 '14 at 16:28
2
class A:
    def __init__(self, a, b):
        self.a = a
        self.b = b

class B(A):
    def __init__(self, parent_instance, c):
        # initiate the parent class with all the arguments coming from
        # parent class __dict__
        super().__init__(*tuple(parent_instance.__dict__.values()))
        self.c = c

a_instance = A(1, 2)
b_instance = B(a_instance, 7)
print(b_instance.a + b_instance.b + b_instance.c)
>> 10

Or you could have a sperate function for this:

def class_converter(convert_to, parent_instance):
    return convert_to(*tuple(parent_instance.__dict__.values()))

class B(A):
    def __init__(self, *args):
        super().__init__(*args)
            self.c = 5

But using the 2nd method, I wasn't able to figure out how to pass additional values

Yaniv K.
  • 237
  • 4
  • 12