I want to create method (say copy) in a class (Parent) that will return an object of either the class or the subclass that invokes it. I want type(x) == type(x.copy()).
None of the approaches I tried were satisfactory.
init_me in each subclass that the super class uses but that defeats the purpose of inheritance. __new__ and __init__, but quickly decided Python must have a better way.Sample code
class Parent(object):
def __init__(self, p1=p1_default, p2=p2_default, p3=p3_default):
... # common stuff
self._special_suff()
def copy_works_if_subclass_does_extra(self):
return self.init_me()
def copy_only_does_superclass(self):
return Parent()
def copy_with_init(self):
return self.__init__()
def whoami(self):
print('I am just a parent')
class Dad(Parent):
def _special_stuff():
... # Dad special stuff
return
def whoami(self):
print('I am a dad')
def init_me(self):
return Dad()
class Mom(Parent):
def _special_stuff():
... # Mom special stuff
return
def whoami(self):
print('I am a mom')
If I understand correctly, you're trying to write a copy method in your base class that will still work when called on an instance of a derived class. This can be made to work, but it's only easy if your child classes only expect the same set of arguments as the base class. If their __init__ method expects different arguments you'll need separate copy methods for each derived class.
Here's a quick example of how it can work. The trick is to call type(self) to get the right class, and then call the class with appropriate constructor arguments to get the new instance:
class Base(object):
def __init__(self, arg1, arg2, arg3):
self.attr1 = arg1
self.attr2 = arg2
self.attr3 = arg3
def copy(self):
cls = type(self)
return cls(self.attr1, self.attr2, self.attr3)
class Derived(Base):
def __init__(self, arg1, arg2, arg3):
super().__init__(arg1, arg2, arg3)
self.some_other_attr = "foo"
In practice this tends not to work as well, since the Derived class will usually want to take an extra argument to set up its extra attribute. An option that might work in that situation is to use the copy module rather than writing your own copy method. The function copy.copy will be able to copy many Python instances without any special support.
You are overcomplicating things a lot. Minimal example with a simple constructor implemented on the child class:
import copy
class Parent():
def whoami(self):
print('Just a parent')
def __init__(self, name):
self.name = name
def copy(self):
# Maybe copy.deepcopy instead
return copy.copy(self)
class Dad(Parent):
def whoami(self):
print('I am a dad')
def __init__(self, name):
super().__init__(name)
self.gender = 'Male'
You don't even need a constructor in Python if you don't need. Or you can have one on the superclass and nothing on the child.
Some usage:
>>> dad = Dad("Clark Griswold")
>>> dad.name
'Clark Griswold'
>>> dad.whoami()
I am a dad
>>> isinstance(dad, Dad)
True
>>> isinstance(dad, Parent)
True
>>> type(dad.copy()) == type(dad)
True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With