0

I want to create a sub class "sub()" that can inherit either object "A(object)" or object "B(object)".

The following works for this:

class A(object):
    def __init__(self):
        print "Class A was inherited"


class B(object):
    def __init__(self):
        print "Class B was inherited"


class sub(A if inh==A else B):
    def __init__(self,inh):
        if inh==A:
            A.__init__(self)
        else:
            B.__init__(self)

However, "inh" is not a defined parameter when I construct my "sub()". I want to be able to construct my "sub()" with an argument "inh" that initialize either "A(object)" or "B(object)".

So that:

my_object = sub(inh = A)

will give me:

Class A was inherited

And that:

my_object = sub(inh = B)

will give me

Class B was inherited

My problem is, how do I pass "inh" to the constructor "sub()" so it can choose the right object to inherit?

7
  • 1
    You cannot. Inheriting is done when creating the type, not when instantiating it. You may create a new class dynamically however. Commented Jul 28, 2017 at 11:16
  • 4
    Why do you want to do this? Smells like an XY problem. Commented Jul 28, 2017 at 11:17
  • I think it should be possible with a metaclass and __new__, but I really don't see any scenario where this is the best option. Commented Jul 28, 2017 at 11:19
  • Why do you need to inherit? Can you compose instead? Commented Jul 28, 2017 at 11:24
  • The reason I want to inherit dynamically is that A(object) and B(object) has the same functions (functions with the same name but returns different results). Instead of doing an "if inh = A:..." for all functions in my super class, I'm simply overwriting what functions my "sub()" calls. More elegant solutions to this is appreciated. Commented Jul 28, 2017 at 11:28

2 Answers 2

2

Immortal's solution, while basically right, has a drawback: each call to Sub() will yield a new class, so things like isinstance() or class identity test will break. A solution to this is to keep a mapping of already created classes:

_CLSMAP = {}

def Sub(base, *args, **kw):
    if base not in _CLSMAP:
        class Sub(base):
            def __init__(self, *args, **kw):
                super(sub, self).__init__(*args, **kw)
    _CLSMAP[base] = Sub
    return _CLSMAP[base](*args, **kw)
Sign up to request clarification or add additional context in comments.

Comments

1

It would seem to me that what you want is a generator/factory function that will construct and return a class instance as you'd wish. For that, you can use python's ability to define classes and functions within functions, so that your definition of class sub will be done in the scope of the factory function, like this:

def Sub(inh=object):
    class sub(inh):
       def __init__(self):
           super(sub, self).__init__()
    return sub()

You can now pass the desired subclass to your generator function and get an instantiated instance of the desired type.

Run output:

>>> def Sub(inh=object):
...     class sub(inh):
...        def __init__(self):
...            super(sub, self).__init__()
...     return sub()
...
>>> class A(object):
...     def __init__(self):
...         print "Class A was inherited"
...
>>>
>>> class B(object):
...     def __init__(self):
...         print "Class B was inherited"
...
>>>
>>> Sub(A)
Class A was inherited
<__main__.sub object at 0x014E4970>
>>> Sub(B)
Class B was inherited
<__main__.sub object at 0x014E49F0>
>>>

is as desired.

2 Comments

Why type(inh) ? If you pass a class as argument, it will the use it's metaclass as base class, which is surely not what the OP asked for.
Also, this will create a new sub class on each invocation, which will screw isinstance() tests or identity tests on the class.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.