Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
410 views
in Technique[技术] by (71.8m points)

inheritance - 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 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!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

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


class Child(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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...