Reputation: 335
Preface: From my understanding the existing answers to this question assume control over the source or work around the problem.
Given a Super
class, and MyClass
which derives from it: How can an existing instance of a Super
class be used as a base? The goal is to not call super().__init__()
with fields from existing_super
, but use the existing object. Similar to how in C++ a copy constructor would be used. Only MyClass
can be adapted, Super
has to remain unchanged.
class Super:
def __init__(self, constructed, by, the, super_factory):
""" no `existing_super` accepted """
pass
class MyClass(Super):
def __init__(self, existing_super):
""" ????? """
pass
s = super_factory()
mine = MyClass(s)
If this is not possible, would monkey patching Super
help? What if Super
uses/doesn't use slots
?
Upvotes: 1
Views: 1159
Reputation: 110506
Python has a somewhat "extra official" "copy" protocol, which can take care of copying classes instances, and which does take care of __slots__
and regular, contained in __dict__
attributes for you.
That said, if your derived class doesn't modify the slots, you can assign to the __class__
attribute, and just change a copy of the superclass instance into a subclass instance.
Then it is a matter of refactoring the subclass __init__
to set any new attributes you may have on the subclass.
def SuperCls:
__slots__ = ... # or whatever
def __init__(self, a, b):
self.a = a
self.b = b
from copy import copy
def MyClass:
def __init__(self, a, b, c, d):
super().__init__(a, b)
self.sub_init(c, d)
def sub_init(self, c, d):
self.c = c
self.d = d
@classmethod
def myclass_from_super(cls, superinstance, c, d):
new_inst = copy(superinstance)
new_inst.__class__ = cls
new_inst.sub_init(c, d)
return new_inst
I don't get from the question if you want to change the Superclass itself - i.e. the superclass instances could be instances of different copies.
As far as the class layout (for pure-python code that means not changing the __slots__
) doesn't change, this code will also work across different super-classes.
Upvotes: 0
Reputation: 1
I thought on this same problem for too long. This appears to be the solution.
class ObjectA:
def __init__(self, a, b):
self.a = a
self.b = b
class ObjectB(ObjectA):
def __init__(self, instanceA: ObjectA):
super().__init__(**instanceA.__dict__)
# instance of parent class created
y = ObjectA(a=1,b=2)
# instance of parent class used to initialize child class
x = ObjectB(y)
# child class successfully inherits attributes of parent
x.a
Upvotes: 0
Reputation: 11
One way to approach it is to convert your instance of the super class into an instance of the subclass using the __class__
attribute.
class A:
def __init__(self):
self.A_attribute = 'from_A'
class B(A):
def __init__(self):
#Create an instance of B from scratch
self.B_attribute = 'from_B'
super().__init__()
def init_A(self):
#Initializes an instance of B from what is already an instance of A
self.B_attribute = 'from_B'
myA = A()
myA.__class__ = B
myA.init_A()
Upvotes: 1