A Point Free Function Composition Operator For Python
Here’s a quick implementation of a point free function composition operator for Python:
compose = lambda f, g: lambda *args, **kwargs:\ f(g(*args, **kwargs)) class composable(object): def __init__(self, f): self.f = f def __call__(self, *args, **kwargs): return self.f(*args, **kwargs) def __mul__(self, other): return composable(compose(self, other))
The composable class works as a function decorator:
@composable def append_a(string): return '{0}{1}'.format(string, 'a') @composable def append_b(string): return '{0}{1}'.format(string, 'b') @composable def append_c(string): return '{0}{1}'.format(string, 'c')
The following test prints out “dcba”, which is what you would expect if you start with “d”, append “c” to it, append “b” to it, and then append “a” to it:
f = append_a * append_b * append_c print f('d')
One use case for this is that to very elegantly and progressively add attributes to Django’s form widgets. Let’s say we want to add the HTML5, “required” attribute, and a “required” class to make sure jquery-validation works. We also want to add a “input-file” class to file fields, so that the Twitter Bootstrap renders them properly.
With the help of the add_class() function from my last entry, we make this work:
@composable def has_attrs(field): field.widget.attrs = field.widget.attrs or None return field @composable is_required(field): if field.required != False: field.widget.attrs['required'] = 'required' add_class(field.widget.attrs, 'required') return field @composable is_file(field): add_class(field.widget.attrs, 'input-file') return field def add_class(attrs, html_class): assert type(attrs) is dict if 'class' in attrs: classes = attrs['class'].split() if not html_class in classes: classes.append(html_class) attrs['class'] = ' '.join(classes) else: attrs['class'] = html_class FileField = is_file * is_required * has_attrs * FileField CharField = is_required * has_attrs * CharField