Skip to content Skip to sidebar Skip to footer

Inheriting From Instance In Python

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 t

Solution 1:

Once __new__ in class Child returns an instance of Child, Child.__init__ will be called (with the same arguments __new__ was given) on that instance -- and apparently it just inherits Parent.__init__, which does not take well to being called with just one arg (the other Parent, A).

If there is no other way a Child can be made, you can define a Child.__init__ that accepts either one arg (which it ignores) or three (in which case it calls Parent.__init__). But it's simpler to forego __new__ and have all the logic in Child.__init__, just calling the Parent.__init__ appropriately!

To make this concrete with a code example:

classParent(object):

    def__init__(self, x, y, z):
        print"INITIALIZING PARENT"
        self.x = x
        self.y = y
        self.z = z

    def__str__(self):
        return"%s(%r, %r, %r)" % (self.__class__.__name__,
            self.x, self.y, self.z)


classChild(Parent):

    _sentinel = object()

    def__init__(self, x, y=_sentinel, z=_sentinel):
        print"INITIALIZING CHILD"if y is self._sentinel and z is self._sentinel:
            print"HIJACKING"
            z = x.z; y = x.y; x = x.x
        Parent.__init__(self, x, y, z)
        print"CHILD IS DONE!"

p0 = Parent(1, 2, 3)
print p0
c1 = Child(p0)
print c1
c2 = Child(4, 5, 6)
print c2

Solution 2:

OK, so I didn't realize that you where happy with a static copy of the arguments until I was already halfway done with my solution. But I decided not to waste it, so here it is anyway. The difference from the other solutions is that it will actually get the attributes from the parent even if they updated.

_marker = object()

classParent(object):

    def__init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

classChild(Parent):

    _inherited = ['x', 'y', 'z']

    def__init__(self, parent):
        self._parent = parent
        self.a = "not got from dad"def__getattr__(self, name, default=_marker):
        if name in self._inherited:
            # Get it from papa:try:
                returngetattr(self._parent, name)
            except AttributeError:
                if default is _marker:
                    raisereturn default

        if name notin self.__dict__:
            raise AttributeError(name)
        return self.__dict__[name]

Now if we do this:

>>> A = Parent('gotten', 'from', 'dad')
>>> B = Child(A)
>>> print"a, b and c is", B.x, B.y, B.z
a, b and c is gotten from dad

>>> print"But x is", B.a
But x isnot got from dad

>>> A.x = "updated!">>> print"And the child also gets", B.x
And the child also gets updated!

>>> print B.doesnotexist
Traceback (most recent call last):
  File "acq.py", line 44, in <module>
    print B.doesnotexist
  File "acq.py", line 32, in __getattr__
    raise AttributeError(name)
AttributeError: doesnotexist

For a more generic version of this, look at the http://pypi.python.org/pypi/Acquisition package. It is in fact, in some cases a bloody need solution.

Solution 3:

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

classChild(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.

Solution 4:

You don't define a constructor (init) for Child, so the Parent constructor is called, expecting 4 arguments while only 2 are passed in (from new). Here's one way to accomplish what you want:

classChild(Parent):
    def__init__(self, *args, **kwargs):
        iflen(args) == 1andisinstance(args[0], Parent):
            Parent.__init__(self, args[0].x, args[0].y, args[0].z)

        else:
            # do something else

Solution 5:

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:

classParent(object):
    def__init__(self):
        # whatever you want here
        self.x = 42
        self.y = 5deff(self):
        print"Parent class, x,y =", self.x, self.y

classChild(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 = 10deff(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.

Post a Comment for "Inheriting From Instance In Python"