# Use of metaclass python to override __init__ and instantiate the class later on

I m writting some API which would use configuration-like arguments.

Here is an example configuration which will be used by my API

quail.run(
quail.SolutionPacked(path='Allum1'),
quail.Installer(
name='Allum1',
icon='icon.jpeg',
binary='allum1',
console=True
),
quail.builder.Builder(
quail.builder.CmdIcon('icon.ico'),
quail.builder.CmdZip(solution_path, 'solution.zip')
)
)


The only problem with that: we will always instantiate, even when we won't use the instance, (for example if we want to uninstall we won't use the install class)

One way around I have found is to use metaclass and override __call__ to get an "EggInstance" so I can instantiate the actual class later on.

Example implementation:

import six

class InstanceEgg:
def __init__(self, cls, *args, **kwargs):
self._cls = cls
self._args = args
self._kwargs = kwargs

def __call__(self):
return self._cls(_get_instance=True, *self._args, **self._kwargs)

class Egg(type):
def __call__(cls, *args, **kwargs):
get_instance = kwargs.pop("_get_instance", False)
if get_instance:
return super().__call__(*args, **kwargs)
return InstanceEgg(cls, *args, **kwargs)

class Test:
def __init__(self, a, b):
print("init %d %d" % (a, b))


Example use:

egg = Test(1, 2)
print("got egg")
f = egg()


Output:

got egg
init 1 2


Do you think it is acceptable to use metaclass for this purpose?

And what do you recommend?

• What's the difference between instantiating an object and instantiating a factory? It's hard to advise you on whether this is appropriate, when we don't know what the constructors for these quail objects look like, and what the objects do. – 200_success May 7 '18 at 20:01
• Installer class will be used to install a solution with install() method and others. Solution class will be used to retrieve a solution (download or unzip) with open() retrieve() and close() Which means we are already initializing stuff in the constructor: like where will be the install folder. if you want more informations, here is the project github.com/mouuff/Quail – mou May 7 '18 at 20:18
• Also I forgot to mention, this classes could possibily be inherited by the "user developer" to change the default behavior – mou May 7 '18 at 21:16

From the looks of it you have objects that you only want to partially create, when you create them the first time.

To do this you can use functools.partial:

quail.run(
partial(quail.SolutionPacked, path='Allum1'),
partial(
quail.Installer,
name='Allum1',
icon='icon.jpeg',
binary='allum1',
console=True
),
partial(
quail.builder.Builder,
partial(quail.builder.CmdIcon, 'icon.ico'),
partial(quail.builder.CmdZip, solution_path, 'solution.zip')
)
)


Yeah, this isn't really that attractive. However it is what you want.

And so you can use a metaclass to perform this action automagically. I'd remove the _get_instance stuff from your Egg, remove InstanceEgg and use a partial call.

from functools import partial

class PartialInit(type):
def __call__(cls, *args, **kwargs):
return partial(super().__call__, *args, **kwargs)