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?

Martin
  • 120
  • 1
  • 10
  • 1
    You cannot. Inheriting is done when creating the type, not when instantiating it. You may create a new class dynamically however. – spectras Jul 28 '17 at 11:16
  • 4
    Why do you want to do this? Smells like an [XY problem](https://meta.stackexchange.com/q/66377/322040). – ShadowRanger Jul 28 '17 at 11:17
  • I _think_ it should be possible with a [metaclass](https://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python) and [`__new__`](https://infohost.nmt.edu/tcc/help/pubs/python/web/new-new-method.html), but I really don't see any scenario where this is the best option. – jdehesa Jul 28 '17 at 11:19
  • Why do you need to inherit? Can you compose instead? – Peter Wood Jul 28 '17 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. – Martin Jul 28 '17 at 11:28
  • @ShadowRanger you are right. – Martin Aug 19 '17 at 02:47
  • @ShadowRanger I have one class ( could be A). That I use to instantiate different sockets and parse my SCPI instructions to the port. I want to have a debug mode where all the functions inherited from A simply returns a value that emulates my socket instead of actually extablishing connection. – Martin Aug 19 '17 at 03:10

2 Answers2

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)
bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
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.

immortal
  • 3,118
  • 20
  • 38