Reputation: 12253
Having a parent and a child class I would like to initialize the child class with a parent instance. My way seems very cumbersome (see below):
I define a staticmethod to extract init
parameters for parent initialization:
class Parent(object):
@staticmethod
get_init_params(parent_obj):
a = parent_obj.a
b = parent_obj.b
return (a, b)
def __init__(self, a, b):
self.a = a
self.b = b
class Child(Parent):
def __init__(self, parent):
super(Parent, self).__init__(*get_init_params(parent))
Is there possibly a more direct way?
EDIT now the classes are simpler
Upvotes: 10
Views: 31016
Reputation: 6606
Make your parent (and hence child) constructor take changed a and b. You should have as little behavior in init methods as possible. Create a class method that takes unchanged a and b, changes them, and then applies the class constructor to them -- this would be good for both parent and child. Then write a static method on the child class that takes a parent object and passes its changed a and b attributes to the init method that expects changed a and b.
class Parent(object):
@classmethod
def from_unchanged(cls, a, b):
changed_a = change_a(a)
changed_b = change_b(b)
return cls(a, b)
@classmethod
def from_parent(cls, parent):
return cls(parentchanged_a, parentchanged_b)
def __init__(self, changed_a, changed_b) :
selfchanged_a = changed_a
selfchanged_b = changed_b
Upvotes: -1
Reputation: 532418
Based on your comments in my original answer, I believe you don't want to subclass Parent
; rather, you just want alternate constructors.
class Parent(object):
# The basic initializer; just use whatever values are
# passed directly to it
def __init__(self, a, b):
self.a = a
self.b = b
@classmethod
def type_1(cls, a, b):
return cls(change_a1(a), change_b1(b))
@classmethod
def type_2(cls, a, b):
return cls(change_a2(a), change_b2(b))
# etc
If you really do want a subclass of Parent
, then there's no need to back out any changes; Parent
only includes functionality that applies to all children.
class Child(Parent):
def __init__(self, a, b):
super(Child, self).__init__(a, b)
# Any Child-specific initialization
Upvotes: 1
Reputation: 532418
I think you want to separate the notion of intializing a Child
object from the notion of creating one from a Parent
. The get_init_params
is just adding a layer of complexity you don't need; access the attributes directly.
class Child(Parent):
@classmethod
def from_parent(cls, parent):
return cls(parent.a, parent.b)
def __init__(self, a, b):
super(Child, self).__init__(a, b)
# Note: the fact that yo have to do this,
# or not call the parent's __init__ in the first
# place, makes me question whether inheritance
# is the right tool here.
self.a = revert_change(self.a)
self.b = revert_change(self.b)
p = Parent(3, 5)
c1 = Child.from_parent(p)
c2 = Child(6, 6)
If there are changes to make to the values you get from the parent, apply them in to_parent
before creating the Child
object.
def from_parent(cls, parent):
return cls(revert_change(parent.a), revert_change(parent.b))
# Or, if you save the original values
# return cls(parent.orig_a, parent.orig_b)
Upvotes: 12
Reputation: 54273
Why not save the init parameters and create a new bound method on Parent
to make_child()
?
class Parent(object):
def __init__(self, *args, **kwargs):
self.init_args = {'args':args, 'kwargs':kwargs}
self.children = list()
... # whatever else a Parent does
def make_child(self, child_cls, *args, **kwargs):
if args is None:
args = self.init_args['args']
if kwargs is None:
kwargs = self.init_args['kwargs']
child = child_cls(self, *args, **kwargs)
self.children.append(child)
return child
class Child(Parent):
def __init__(self, parent, *args, **kwargs):
self.parent = parent
... # whatever else a Child does
DEMO
>>> p = Parent()
>>> c = p.make_child(Child)
>>> c in p.children
True
Upvotes: 0