Design: Idiom for classes and methods that are customizable by the user?

Marko Rauhamaa marko at pacujo.net
Thu May 12 18:01:53 EDT 2016


Dirk Bächle <tshortik at gmx.de>:

> I'm one of the SCons (http://www.scons.org) developers

I take the opportunity to thank you and your colleagues for the
wonderful building tool that I have used professionally to great success
since 2003.

> We're a build system and all the code is written in Python. Even more
> so, our build scripts (build description files) are Python
> scripts...allowing the user to have the full power of this beautiful
> language at his/her fingertips whenever it's needed.

It is indeed great to have Python available when needed. However, I have
striven not to need it. SConscript files should be understood by casual
maintainers who aren't necessarily fluent with Python.

> To put it shortly, the user should be able to slip a new Taskmaster
> under the covers of SCons...and it should behave as if it would've
> been built-in.

I have tried to resist the temptation, successfully so far.

> # The built-in Taskmasters
> types = {'default' : DefaultTaskmaster,
>          'noclean' : NocleanTaskmaster}
>
> def create(key, targets, top, node):
>     """ Simple factory for creating an actual Taskmaster,
>         based on the given key.
>     """
>     if key in types:
>         return types[key](targets, top, node)
>
>     return DefaultTaskmaster(targets, top, node)
>
> def add(key, taskm_class):
>     """ Register the given Taskmaster class, if its key doesn't
>         exist yet.
>     """
>     if not key in types:
>         types[key] = taskm_class
>
> [...]
>
> - Is this a good approach

As an approach, that looks ok. The code looks a bit too lenient, though,
which can easily surprise and baffle the user. I think it would be
better to fail:

========================================================================
class AlreadyExistsError(Exception):
   pass

types = {}

def create(key, targets, top, node):
    """ Simple factory for creating an actual Taskmaster,
        based on the given key.
    """
    return types[key](targets, top, node)

def add(key, taskm_class):
    """ Register the given Taskmaster class, if its key doesn't
        exist yet.
    """
    if key in types:
        raise AlreadyExistsError("Task manager '%s' already exists" % key)
    types[key] = taskm_class

# The built-in Taskmasters
add('default', DefaultTaskmaster)
add('noclean', NocleanTaskmaster)
========================================================================

> - Are there other options that have stood the test of time under
> operational conditions? If yes, I'd be interested to get links and
> pointers to the corresponding projects (I'm prepared to read stuff and
> do further investigations on my own).

Based on the given information, I can't give recommendations. However,
in general, I'm suspicious of the factory pattern. Whenever possible, I
prefer explicit construction.

For example, why do you need a key? Couldn't you simply pass the task
master class as an argument?


Marko



More information about the Python-list mailing list