How to inherit from pre-existing class instance in Python? - python

I have a class Parent:
class Parent:
def __init__(self, foo):
self.foo = foo
I then have another class Child which extends Parent. But I want Child to take a pre-existing instance of parent and use this as the parent to inherit from (instead of creating a new instance of Parent with the same constructor parameters).
class Child(Parent):
def __init__(self, parent_instance):
""" Do something with parent_instance to set this as the parent instance """
def get_foo(self):
return self.foo
Then I would ideally be able to do:
p = Parent("bar")
c = Child(p)
print(c.get_foo()) # prints "bar"

You could copy the content of the parents's __dict__ to the child's. You can use vars() builtin function to do so, and the dictionary's update() method.
class Child(Parent):
def __init__(self, parent_instance):
vars(self).update(vars(parent_instance))
def get_foo(self):
return self.foo
p = Parent("bar")
c = Child(p)
print(c.get_foo())
# prints "bar"

You can use your own constructor - provide a classmethod that takes an instance of a parent.
class Parent:
def __init__(self, foo):
self.foo = foo
class Child(Parent):
def get_foo(self):
return self.foo
#classmethod
def from_parent(cls, parent_instance):
return cls(parent_instance.foo)
p = Parent('bar')
c = Child.from_parent(p)
c.get_foo()

I'm not sure inheritance is the right solution here as it breaks the LSP in the __init__ method.
Maybe parents and children just share a common interface.
I'd prefer something like (python3.8):
from typing import Protocol
class FoeAware(Protocol):
#property
def foe(self):
...
class Parent:
def __init__(self, foe):
self._foe = foe
#property
def foe(self):
return self._foe
class Child:
def __init__(self, parent: FoeAware):
self.parent = parent
#property
def foe(self):
return self.parent.foe
p = Parent("bar")
c = Child(p)
c.foe # bar
The key point is that it takes advantage of polymorphism with a common interface FoeAware, which is preferable to an inheritance tree.

Using getattr() to fetch the attribute from the parent instance
class Parent:
def __init__(self, foo):
self.foo = foo
class Child(Parent):
def __init__(self, parent_instance):
self.parent_instance = parent_instance
def get_foo(self):
return self.foo
def __getattr__(self, attr):
return getattr(self.parent_instance, attr)
par = Parent("bar")
ch = Child(par)
print(ch.get_foo())
#prints bar

Related

Can Python subclasses return class of type(self) from method inherited from a parent class?

Suppose I have a parent class Parent and two child classes Child1 and Child2. Suppose Parent contains a method usable by both subclasses. Is it possible for this method to return a new instance of the same class of whatever class calls it, even if the particular subclass calling it is not known when the method is defined in the parent class?
class Parent:
def __init__(self, foo):
pass
def my_method(self):
return self.__class__(foo)
class Child1(Parent):
def __init__(self, foo):
super().__init__(foo)
class Child2(Parent):
def __init__(self, foo):
super().__init__(foo)
parent = Parent('hello')
type(p.my_method())
>>> class<Parent>
child1 = Child1('hey')
type(child1.my_method())
>>> class<Child1>
child2 = Child2('yo')
type(child2.my_method())
>>> class<Child2>
EDIT
I had made a mistake in passing foo without initializing it as an attribute first. The following code achieves the behavior I'm going for, but I'd be interested to know if this could lead to design problems down the road, so feedback on that would be appreciated.
class Parent:
def __init__(self, foo):
self.foo = foo
def my_method(self):
return self.__class__(self.foo)
class Child1(Parent):
def __init__(self, foo):
super().__init__(foo)
class Child2(Parent):
def __init__(self, foo):
super().__init__(foo)
p = Parent(foo='hi')
print(type(p.my_method()))
>>>__main__.Parent
c1 = Child1(foo='hey')
print(type(c1.my_method()))
>>>__main__.Child1
c2 = Child2(foo='hey')
print(type(c2.my_method()))
>>>__main__.Child2
What you have won't work, because you have my_method being an instance method, but you're trying to call it without an instance.
If you make that a class method, it can work, although I personally think this is a bad design choice:
class Parent:
def __init__(self, foo):
pass
#classmethod
def my_method(cls):
return cls(0)
class Child1(Parent):
def __init__(self, foo):
super().__init__(foo)
class Child2(Parent):
def __init__(self, foo):
super().__init__(foo)
print(type(Parent.my_method()))
print(type(Child1.my_method()))
print(type(Child2.my_method()))
Output:
<class '__main__.Parent'>
<class '__main__.Child1'>
<class '__main__.Child2'>

Create child class object using parent class instance

lets say we have class A and it has one instance - x. How to make a child class of class A where I would be able to pass x as an argument and get all its parameters and pass it to child class object. precisely speaking I want to do something like this.
class A:
def __init__(self, parameter1, parameter2):
self.parameter1 = parameter1
self.parameter2 = parameter2
class B(A):
def __init__(self, Ainstance, someParameter):
super().__init__(**Ainstance.__dict__)
self.someParameter = someParameter
x = A(parameter1='1', parameter2='2')
x = B(x, someParameter='3')
print(x.parameter1)
print(x.parameter2)
print(x.someParameter)
the goal is to create a class where I would be able to get all the parameters of parent class object, and add my own attributes. The problem in the code above is I won't be able to do that with all classes because not all of them has __dict__ attribute.
I have this example code which I use to remind myself how to construct a proxy.
#soProxyPattern
class Example:
def __init__(self):
self.tag_name = 'name'
def foo(self):
return 'foo'
def bar(self, param):
return param
class Container:
def __init__(self, contained):
self.contained = contained
self.user_name = 'username'
def zoo(self):
return 0
def __getattr__(self, item):
if hasattr(self.contained, item):
return getattr(self.contained,item)
#raise item
c = Container(Example())
print(c.zoo())
print(c.foo())
print(c.bar('BAR'))
print(c.tag_name)
print(c.user_name)
The output is:
0
foo
BAR
name
username
This shows that Container can have its own attributes (methods or variables) which you can access over and above all of the attributes of the contained instance.
Instead of dict you could use the dir and getattr like this:
class A:
def __init__(self, parameter1, parameter2):
self.parameter1 = parameter1
self.parameter2 = parameter2
class B(A):
def __init__(self, Ainstance, someParameter):
parameters = {param: getattr(Ainstance, param) for param in dir(Ainstance) if not param.startswith("__")}
super().__init__(**parameters)
self.someParameter = someParameter
For a more detailed explanation see: Get all object attributes in Python?

Most pythonic way to super parent class and pass class variables

I have a parent class and a child class. The parent class needs some predefined class variables to run call(). The objects are not defined in the child class.
Question: What is the most pythonic way to pass the variables when calling super() without changing the parent class.
Example:
class Parent:
def __init__(self):
self.my_var = 0
def call(self):
return self.my_var + 1
class Child(Parent):
def __init__(self):
self.different_var = 1
def call(self):
my_var = 0
super().__call__() # What is the most pythonic way of performing this line
I know I could just make my_var in the child class a class object and it would work, but there must be a better. If not that would be an acceptable answer as well.
Your version is just a mixin. You have to __init__ the super.
class Parent:
def __init__(self):
self.my_var = 0
def call(self):
return self.my_var + 1
class Child(Parent):
def __init__(self):
super().__init__() #init super
self.different_var = 1
def call(self):
self.my_var = 50
return super().call() #return call() from super
c = Child()
print(c.call()) #51

How to pass all class variables from a parent *instance* to a child class?

Here's an example of what I'm trying to do:
class Parent():
def __init__():
self.parent_var = 'ABCD'
x = Child(self) # self would be passing this parent instance
class Child():
def __init__(<some code to pass parent>):
print(self.parent_var)
foo = Parent()
Now I know what you're thinking, why not just pass parent_var itself to the child instance? Well my actual implementation has over 20 class variables in Parent. I don't want to have to manually pass each variable to the __init__ of the Child instance that's instantiated in Parent-- is there a way to make all Parent class variables available to Child?
EDIT - SOLVED:
This is the way I found that works:
class Parent():
def __init__(self):
self.parent_var = 'ABCD' # but there are 20+ class vars in this class, not just one
x = Child(self) # pass this parent instance to child
class Child():
def __init__(self, parent):
for key, val in vars(parent).items():
setattr(self, key, val)
print(self.parent_var) # successfully prints ABCD
foo = Parent()
If you inherit from the parent class all variables will be present in child classes. Use super init in the child to make sure the parent class instantiates.
class Parent:
def __init__(self):
self.parent_var = 'ABCD'
class Child(Parent):
def __init__(self):
super().__init__()
child = Child()
print(child.parent_var)
prints:
'ABCD'
You would pass the instance of Parent like you would any value.
class Parent:
def __init__(self):
self.parent_var = 'ABCD'
x = Child(self)
class Child:
def __init__(self, obj):
print(obj.parent_var)
Found a solution and wanted to post the answer in case anyone who finds this needs it:
class Parent():
def __init__(self):
self.parent_var = "ABCD" # just an example
x = Child(self) # pass this parent instance (this object) to child
class Child():
def __init__(self, parent):
# copies variables from passed-in object to this object
for key, val in vars(parent).items():
setattr(self, key, val)
print(self.parent_var) # successfully prints ABCD
foo = Parent()

How to call child constructor from parent?

In inheritance, most of the time we want to create child classes that inherit from the parent, and in the process of instantiation they have to call the parent constructor. In python we use super for this, and that's great.
I want to do somewhat the opposite: I have a parent class which is a template for a number of child classes. Then I want the child classes to each have a function that allows an instance to clone itself:
class Parent(object):
def __init__(self, ctype, a):
print('This is the parent constructor')
self._ctype = ctype
self._a = a
#property
def a(self):
return self._a
#property
def ctype(self):
return self._ctype
class ChildOne(Parent):
def __init__(self, a):
super(ChildOne, self).__init__('one', a)
print('This is the child One constructor')
self.one = 1
def clone(self):
return ChildOne(self._a)
class ChildTwo(Parent):
def __init__(self, a):
super(ChildTwo, self).__init__('two', a)
print('This is the child Two constructor')
self.two = 2
def clone(self):
return ChildTwo(self._a)
Now, if I create an instance of one of the children, I can clone it:
>>> k = ChildOne(42)
>>> k.ctype
'one'
>>> l = k.clone()
>>> l.a
42
>>> l is k
False
The problem is, the clone method is repeated- and nearly identical- in both sub-classes, except I need to specify explicitly which constructor to call. Is it possible to design a clone method that I define in the parent class, that correctly inherits to the children?
This can be done with:
Code:
class Parent(object):
def clone(self):
return type(self)(self._a)
Test Code:
class Parent(object):
def __init__(self, ctype, a):
print('This is the parent constructor')
self._ctype = ctype
self._a = a
#property
def a(self):
return self._a
#property
def ctype(self):
return self._ctype
def clone(self):
return type(self)(self._a)
class ChildOne(Parent):
def __init__(self, a):
super(ChildOne, self).__init__('one', a)
print('This is the child One constructor')
self.one = 1
class ChildTwo(Parent):
def __init__(self, a):
super(ChildTwo, self).__init__('two', a)
print('This is the child Two constructor')
self.two = 2
k = ChildOne(42)
print(k.ctype)
l = k.clone()
print(l.a)
print(type(l))
Results:
This is the parent constructor
This is the child One constructor
one
This is the parent constructor
This is the child One constructor
42
<class '__main__.ChildOne'>

Categories

Resources