Search code examples
pythonwrapperfactoryintrospectioninspect

Can a python class be declared to have the same __init__() signature as another class (including defaults)?


Consider the following wrapper:

class SomeClass:
    def __init__(arg1='default1', arg2='default2'):
        # initialize stuff

    def do_stuff(self):

    
class SomeClassWrapper:
    def __init__(arg1='default1', arg2='default2'):
        self.arg1 = arg1
        self.arg2 = arg2
    
    def doit(self):
        instance = SomeClass(arg1, arg2)
        instance.do_stuff()

SomeClassWrapper is there to delay instantiation of SomeClass objects and to abstract away the creation of a new instance every time do_stuff() needs to be performed.

SomeClassWrapper is initialized with the "template" required to later initialize SomeClass objects whose real life initialization list is much longer than in the example and subject to change as the project develops.

The goal is to reduce errors and maintenance burden by not having to manually retype the same argument list (including defaults) in SomeClassWrapper.__init__() that we already have in SomeClass.__init__().

Is there a way, perhaps using the inspect module, to do something along the lines of the below?

class SomeClassWrapper:
    # syntax to say:
    #  __init__() should be the same as SomeClass.__init__()  
    #  the arguments should be stored in say self.kwargs
    
    def doit(self)
        instance = SomeClass(self.kwargs)
        instance.do_stuff()

Solution

  • Rather than duplicate the argument passing, have the wrapper accept a zero-argument callable that creates the object.

    class SomeClass:
        def __init__(arg1='default1', arg2='default2'):
            # initialize stuff
    
        def do_stuff(self):
            ...
    
        
    class SomeClassWrapper:
        def __init__(self, maker):
            self.maker = maker
    
        def doit(self):
            instance = self.maker()
            instance.do_stuff()
    

    The caller still provides all the details, but in a slightly different fashion

    # Old version
    # w = SomeClassWrapper('foo', 'bar)
    
    # One option
    w = SomeClassWrapper(lambda: SomeClass('foo', 'bar'))
    
    # Another option
    from functools import partial
    w = SomeClassWrapper(partial(SomeClass, 'foo', 'bar'))