1

I have a base class Foo and another base class Bar.

I would like to create two sets of Baz classes (e.g., Baz1, ..., Baz20) such that for each N from 1 to 20, there's a BazN class that inherits from Foo, and also a BazN class that inherits from Bar. So I'd end up with 40 BazN classes, 20 of which are BazNFoo and 20 of which are type BazNBar.

What I have is the below snippet, which explicitly writes each BazN class twice, once inheriting from Foo and once from Bar. My question is, is there a programmatic way to do this writing each BazN class just once? My Baz classes are pretty long.

class Foo:
    def __init__(self):
        # code specific to Foo
    
class Bar:
    def __init__(self):
        # code specific to Bar

class Baz1Foo(Foo):
    def __init__(self):
        super().__init__()
        # code specific to Baz1

class Baz1Bar(Bar):
    def __init__(self):
        super().__init__()
        # code specific to Baz1

class Baz2Foo(Foo):
    ...
wkzhu
  • 1,616
  • 13
  • 23
  • Note: Foo and Bar have non-compatible information so I cannot simply use multiple inheritance (e.g., `class Baz1(Foo, Bar)`) – wkzhu Dec 04 '21 at 17:18
  • Having 20 children class from one parent is a very strange design, what different properties would they have ? That isn't a good idea, you shouldn't be finfind a solution for that, but rather a total different way to do it – azro Dec 04 '21 at 17:18
  • Can I ask why you want to a design like this? This looks a lot like an X/Y Problem... – match Dec 04 '21 at 17:22
  • 1
    One use case is if the parents `Foo` and `Bar` are two different database base classes and each `Baz` is a table schema. For example, in sqlalchemy, you can use `declarative_base` to create a Base class, or create a Base class explicity. – wkzhu Dec 04 '21 at 17:28
  • Also, apologies if my arbitrary N=20 raised flagrant design questions, the same question applies for just N=2-3 (large) child classes where one would rather not replicate the same child code twice. – wkzhu Dec 04 '21 at 17:34

1 Answers1

2

You can create dynamic subclasses using type - however this is relatively advanced and just because it can be done this way, doesn't mean it's a good idea...

# Define a parent class
class Foo():
    def __init__(self):
        print("Init Foo")

    def foo(self):
        print("Method Foo")

# Create a dict to store the sub-classes in (could use globals() instead)
classes = {}
for i in range(2):
    # Create Foo0..Foo2
    classes[f'Foo{i}'] = type(
        f'Foo{i}',
        # Inherit from Foo
        (Foo,),
        # super() must be passed child class object in type construction
        # https://bugs.python.org/issue29944
        { "__init__": lambda self: super(self.__class__, self).__init__() }
    )

# Some proof it works...
for cls in classes.values():
    # Instantiate each class
    i = cls()
    # Print the class info (name)
    print(i.__class__)
    # Call the (inherited) foo method
    i.foo()

    ### OUTPUT:
    # Init Foo
    # <class '__main__.Foo0'>
    # Method Foo
    # Init Foo
    # <class '__main__.Foo1'>
    # Method Foo
    # Init Foo
    # <class '__main__.Foo2'>
    # Method Foo
match
  • 10,388
  • 3
  • 23
  • 41
  • Thanks! Looks like dynamic subclassing is covered here as well: https://stackoverflow.com/questions/19438923/python-dynamic-subclassing https://stackoverflow.com/questions/9269902/is-there-a-way-to-create-subclasses-on-the-fly – wkzhu Dec 04 '21 at 18:42
  • Those are subtly different in that they are not dynamically naming the class, or supering the parent class, but they do give some other examples of dynamic class generation. – match Dec 04 '21 at 18:48