Inheriting from instance in Python

By : Peter
Source: Stackoverflow.com
Question!

In Python, I would like to construct an instance of the Child's class directly from an instance of the Parent class. For example:

A = Parent(x, y, z)
B = Child(A)

This is a hack that I thought might work:

class Parent(object):

    def __init__(self, x, y, z):
        print "INITILIZING PARENT"
        self.x = x
        self.y = y
        self.z = z

class Child(Parent):

    def __new__(cls, *args, **kwds):
        print "NEW'ING CHILD"
        if len(args) == 1 and str(type(args[0])) == "<class '__main__.Parent'>":
            new_args = []
            new_args.extend([args[0].x, args[0].y, args[0].z])
            print "HIJACKING"
            return Child(*new_args)
        print "RETURNING FROM NEW IN CHILD"
        return object.__new__(cls, *args, **kwds)

But when I run

B = Child(A)

I get:

NEW'ING CHILD  
HIJACKING  
NEW'ING CHILD  
RETURNING FROM NEW IN CHILD  
INITILIZING PARENT  
Traceback (most recent call last):  
  File "classes.py", line 52, in <module>  
    B = Child(A)  
TypeError: __init__() takes exactly 4 arguments (2 given)

It seems the hack works just as I expected but the compiler throws a TypeError at the end. I was wondering if I could overload TypeError to make it ignore the B = Child(A) idiom but I wasn't sure how to do that. In any case, would you please give me your solutions for inheriting from instances?

Thanks!

By : Peter


Answers

I know this is an extremely old thread, but I recently ran into the same challenge as Alexandra, and this was the most relavent topic I could find. I had a parent class with many, many attributes, and I wanted to essentially 'patch' an instance of it, by keeping all of its methods and attributes, adding a few, and modifying/overwriting others. A simple subclass wouldn't work because the attributes would be filled in by the user during runtime, and I couldn't just inherit the default values from the parent class. After a lot of tinkering I found a very clean (though rather hacky) way to do it by using __new__. Here's an example:

class Parent(object):
    def __init__(self):
        # whatever you want here
        self.x = 42
        self.y = 5
    def f(self):
        print "Parent class, x,y =", self.x, self.y

class Child(Parent):
    def __new__(cls, parentInst):
        parentInst.__class__ = Child
        return parentInst
    def __init__(self, parentInst):
        # You don't call the Parent's init method here
        self.y = 10
    def f(self):
        print "Child class, x,y =", self.x, self.y

c = Parent()
c.f()  # Parent class, x,y = 42 5
c.x = 13
c.f()  # Parent class, x,y = 13 5
c = Child(c)
c.f()  # Child class, x,y = 13 10

The only special part is changing the __class__ attribute of the Parent class in the Child's constructor. Because of this, the Child's __init__ method will be called as usual, and to my knowledge the Child class should function exactly as any other inherited class.



I find this (encapsulation) to be the cleanest way:

class Child(object):
    def __init__(self):
        self.obj = Parent()

    def __getattr__(self, attr):
        return getattr(self.obj, attr)

This way you can use all Parent's method and your own without running into the problems of inheritance.

By : elyase


This video can help you solving your question :)
By: admin