Q:

Purely static classes in Python - Use metaclass, class decorator, or something else?

In part of a program I'm developing I want to perform a linear regression with terms that are some function of a data set X. The exact model used is configurable by the user, particularly which terms (or sets of terms) to use. This involves generating the matrix X' where every row of X' is a function of the corresponding row of X. The columns of X' will be the predictors for my regression.
For example, say my data set is two-dimensional (X has 2 columns). If we denote x and x' as corresponding rows of X and X', then assuming x is two-dimensional x' might be something like
[ 1, x[0], x[1], x[0] * x[1], sqrt(x[0]), sqrt(x[1]), x[0]**2, x[1]**2 ]

You can see these terms come in groups. First is just a 1 (constant), then the untransformed data (linear), then the product of the two data elements (would be all pairwise products if x had more than two dimensions), then square roots and squares of the individual terms.
I need to define all these sets of terms somehow in python, such that each has a user-readable name, function to generate the terms, function to get the number of terms from the dimensions of the input, function to generate labels for the terms based on column labels for the data, etc. Conceptually these all feel like they should be instances of a TermSet class or something similar, but this doesn't quite work because their methods would need to differ. My first thought was to go with something like this:
termsets = {} # Keep track of sets

class SqrtTerms:
    display = 'Square Roots' # user-readable name

    @staticmethod
    def size(d):
        """Number of terms based on input columns"""
        return d

    @staticmethod
    def make(X):
        """Make the terms from the input data"""
        return numpy.sqrt(X)

    @staticmethod
    def labels(columns):
        """List of term labels based off of data column labels"""
        return ['sqrt(%s)' % c for c in columns]

termsets['sqrt'] = SqrtTerms # register class in dict

class PairwiseProductTerms:
    display = 'Pairwise Products'

    @staticmethod
    def size(d):
        return (d * (d-1)) / 2

    @staticmethod
    def make(X):
        # Some more complicated code that spans multiple lines
        ...

    @staticmethod
    def labels(columns):
        # Technically a one-liner but also more complicated
        return ['(%s) * (%s)' % (columns[c1], columns[c2])
            for c1 in range(len(columns)) for c2 in range(len(columns))
            if c2 > c1]

termsets['pairprod'] = PairwiseProductTerms

This works: I can retrieve the classes from the dictionary, put the ones I want to use in a list, and call the appropriate methods on each. Still, creating classes with only static attributes and methods seems ugly and unpythonic. Another idea I came up with would be to create a class decorator that could be used like:
# Convert bound methods to static ones, assign "display" static
# attribute and add to dict with key "name"
@regression_terms(name='sqrt', display='Square Roots')
class SqrtTerms:
    def size(d):
        return d
    def make(X):
        return numpy.sqrt(X)
    def labels(columns):
        return ['sqrt(%s)' % c for c in columns]

This gives the same result but is cleaner and much nicer (for myself) to read and write (especially if I need a lot of these). However, the way things actually work under the hood is obscured and anyone else reading this might have a hard idea figuring out what is going on at first. I also thought of creating a metaclass for these but that sounds like overkill. Is there a better pattern I should use here? 

A:

Some people will always say that this is an abuse of the language.  I say Python was designed to be abusable, and the ability to create DSLs that don't require parsers yet that don't look like lisp is one of its core strengths.
If you really have a lot of these, go with the metaclass. If you do that, in addition to having a term dictionary, you can have attributes that reference the terms, as well.  It's really nice, because you can have code like this:
print Terms.termsets
print Terms.sqrt
print Terms.pairprod
print Terms.pairprod.size(5)

return results like this:
{'pairprod': <class '__main__.PairwiseProductTerms'>,
 'sqrt': <class '__main__.SqrtTerms'>}
<class '__main__.SqrtTerms'>
<class '__main__.PairwiseProductTerms'>
10

The full code that can do that is here:
from types import FunctionType

class MetaTerms(type):
    """
    This metaclass will let us create a Terms class.
    Every subclass of the terms class will have its
    methods auto-wrapped as static methods, and
    will be added to the terms directory.
    """
    def __new__(cls, name, bases, attr):
        # Auto-wrap all methods as static methods
        for key, value in attr.items():
            if isinstance(value, FunctionType):
                attr[key] = staticmethod(value)
        # call types.__new__ to finish the job
        return super(MetaTerms, cls).__new__(cls, name, bases, attr)

    def __init__(cls, name, bases, attr):
        # At __init__ time, the class has already been
        # built, so any changes to the bases or attr
        # will not be reflected in the cls.
        # Call types.__init__ to finish the job
        super(MetaTerms, cls).__init__(name, bases, attr)
        # Add the class into the termsets.
        if name != 'Terms':
            cls.termsets[cls.shortname] = cls

    def __getattr__(cls, name):
        return cls.termsets[name]

class Terms(object):
    __metaclass__ = MetaTerms
    termsets = {} # Keep track of sets

class SqrtTerms(Terms):
    display = 'Square Roots' # user-readable name
    shortname = 'sqrt'  # Used to find in Terms.termsets

    def size(d):
        """Number of terms based on input columns"""
        return d

    def make(X):
        """Make the terms from the input data"""
        return numpy.sqrt(X)

    def labels(columns):
        """List of term labels based off of data column labels"""
        return ['sqrt(%s)' % c for c in columns]

class PairwiseProductTerms(Terms):
    display = 'Pairwise Products'
    shortname = 'pairprod'

    def size(d):
        return (d * (d-1)) / 2

    def make(X):
        pass

    def labels(columns):
        # Technically a one-liner but also more complicated
        return ['(%s) * (%s)' % (columns[c1], columns[c2])
            for c1 in range(len(columns)) for c2 in range(len(columns))
            if c2 > c1]

print Terms.termsets
print Terms.sqrt
print Terms.pairprod
print Terms.pairprod.size(5)

If you hide away the metaclass and the base Terms class in a separate module, then nobody has to look at it -- just from baseterm import Terms.  You could also do some cool auto-discovery / auto-import where dumping modules in the right directory automatically adds them to your DSL.
With the metaclass, the feature set can easily grow organically as you find other things you would like your mini-language to do.

