Chapter 11
Implementing more complex descriptors
We can easily write the following commands:
@f_wrap
@g_wrap
def h(x):
something
There's nothing in Python to stop us. This has a meaning somewhat like fghx ().
However, the name is merely hx(). Because of this potential confusion, we need to be
cautious when creating functions that involve deeply nested descriptors. If our intent
is simply to handle some cross-cutting concerns, then each decorator can handle a
concern without creating much confusion.
If, on the other hand, we're using a decoration to create a composite function, it
might also be better to use the following command:
f_g_h= f_wrap(g_wrap(h))
This clarifies as to what precisely is going on. Decorator functions don't correspond
precisely with the mathematical abstraction of functions being composed. The
decorator function actually contains a wrapper function that will contain the function
being composed. This distinction between a function and a decorator that creates a
composite from the function can become a problem when trying to understand
an application.
As with other aspects of functional programming, a succinct and expressive program
is the goal. Decorators who are expressive are welcome. Writing an über-meta-super-
callable that can do everything in the application with only minor customizations
may be succinct, but it's rarely expressive.
Recognizing design limitations
In the case of our data cleanup, the simplistic removal of stray characters may not
be sufficient. When working with the geolocation data, we may have a wide variety
of input formats that include simple degrees (37.549016197), degrees and minutes
(37° 32.94097′), and degrees-minutes-seconds (37° 32′ 56.46′′). Of course, there
can be even more subtle cleaning problems: some devices will create an output with
the Unicode U+00BA character, º, instead of the similar-looking degree character, °,
which is U+00B0.