Is it possible to dynamically inherit from a class that is only known at runtime in python?

TL;DR: Yes, using python closures

"The class Bar is somewhat dynamically generated" That's fine... as long as it follows the blueprint (of a class that should be extended by Foo), you can leverage python closures here. Dynamically create a new class by creating it inside, and returning it from a function.

def get_class(superclass):
    class Foo(superclass):
        def __init__(self, ...):
           ...

    return Foo

DynamicFoo = get_class(Bar)
myobj = DynamicFoo()

This is a common pattern you'll see in python - leveraging closures to dynamically create callbacks and classes.


The answer above assumes that Bar is correctly defined, when it in fact is not. The super_cool_function is missing a self parameter. Instance methods are always called with the first parameter (the instance itself) automatically being passed in as the first attribute.

So, the correct definition for Bar would be:

class Bar:
   def super_cool_function(self):
       print("Cool")

Now, defining get_class with the simplest definition of the inner class Foo:

def get_class(superclass):
    class Foo(superclass):
        pass

    return Foo

DynamicFoo = get_class(Bar)
myobj = DynamicFoo()
myobj.super_cool_function()
# Cool

Your desired use is a little strange:

foobar = Foo(Bar)

You're constructing a Foo instance by handing it the Bar class object, and expecting to get back something that acts like a Bar instance. Normally, a proxy class is designed to take an object to proxy to, or look on up somewhere, not just construct one with no arguments.

But, other than that oddness, which just means an __init__ method that constructs the object, this is just a bog-standard proxy class. So:

class Foo:
    def __init__(self, cls):
        self._inst = cls()
    def __getattr__(self, name):
        return getattr(self._inst, name)
    def __setattr__(self, name, value):
        if name in {'_inst'}:
            super().__setattr__(name, value)
        else:
            setattr(self._inst, name, value)
    def __delattr__(self, name):
        delattr(self._inst, name)

Of course you still won't be able to call that super_cool_function on a foobar any more than you could on a Bar instance, because it's defined as a method and doesn't have a self parameter. But you'll get the same error from the Foo instance that you would have gotten from a Bar instance:

>>> foobar.super_cool_function
<bound method Bar.super_cool_function of <__main__.Bar object at 0x129f95080>>
>>> foobar.super_cool_function()
TypeError: super_cool_function() takes 0 positional arguments but 1 was