Chapter 11
Or, we could include the conversion function as an argument to the decorator for a
cleansing function as follows:
@then_convert(converter)
def clean(text):
something
In this case, we can choose the @then_convert(converter) style decorator because
we're relying—for the most part—on the built-in conversions. Our point is to show
that the choice is not crystal clear.
The decorator looks as follows:
def then_convert(convert_function):
def clean_convert_decorator(clean_function):
@wraps(clean_function)
def cc_wrapper(text, *args, **kw):
try:
return convert_function(text, *args, **kw)
except (ValueError, decimal.InvalidOperation):
cleaned= clean_function(text)
return convert_function(cleaned, *args, **kw)
return cc_wrapper
return clean_convert_decorator
We've defined a three-layer decorator. At the heart is the cc_wrapper() function that
applies the convert_function function. If this fails, then it uses a clean_function
function and then tries the convert_function function again. This function is
wrapped around the clean_function function by the then_convert_decorator()
concrete decorator function. The concrete decorator has the convert_function
function as a free variable. The concrete decorator is created by the decorator
interface, then_convert(), which is customized by a conversion function.
We can now build a slightly more flexible cleanse and convert function as follows:
@then_convert(int)
def drop_punct(text):
return text.replace(",", "").replace("$", "")
The integer conversion is a decorator applied to the given cleansing function. In this
case, the cleansing function removes $ and , characters. The integer conversion is
wrapped around this cleansing.