Jony Pollon
Jony Pollon

Reputation: 51

How to inherit from pre-existing class instance in 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"

Upvotes: 5

Views: 2087

Answers (4)

C0l0red
C0l0red

Reputation: 45

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

Upvotes: 0

loutre
loutre

Reputation: 894

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.

Upvotes: 0

bbayles
bbayles

Reputation: 4507

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()

Upvotes: 3

revliscano
revliscano

Reputation: 2272

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"

Upvotes: 8

Related Questions