Lets look at decorators again. They're related to what we call "function composition" in that the decorator "eats" what's defined just below it, and returns a proxy with the same name, likewise a callable.
Here's a decorator that tells the identity function under it what letter to tack on (concatenate) to the end of string s, the argument.
The decorator itself takes an argument. The callable it then returns, the adder function, is ready to do the work of finally "eating" ident and extending what it does by the one letter).
In :def plus(char): """ returns a prepped adder to eat the target, and to build a little lambda that does the job. """ def adder(f): return lambda s: f(s) + char return adder @plus('R') def ident(s): return s ident('X') # do the job!
Now let's stack up some decorators, showing how each swallows the result below. Work from the bottom up...
In :# append from the bottom up, successive wrappings @plus('W') @plus('A') @plus('R') def ident(s): return s print("ident('X') :", ident('X')) print("ident('WAR'):", ident('WAR'))
ident('X') : XRAW ident('WAR'): WARRAW
Now let's bring Compose into the mix, a decorator class makes our proxies able to compose with one another by means of multiplication. Even powering has been implemented. We're free to make our target functions composable, in addition to controlling what letters to add.
In :class Compose: """ make function composible with multiply also make self powerable e.g. f ** 3 == f * f * f From: https://repl.it/@kurner """ def __init__(self, f): self.func = f def __mul__(self, other): return Compose(lambda x: self(other(x))) def __pow__(self, n): if n == 0: return Compose(lambda x: x) # identity function if n == 1: return self if n > 1: me = self for _ in range(n-1): me *= self # me times me times me... return me def __call__(self, x): # callable instances return self.func(x)
In :@Compose @plus('W') @plus('A') @plus('R') def ident(s): return s H = ident ** 3 H('X')
In :@Compose @plus('T') @plus('Y') @plus('P') def F(s): return s @Compose @plus('N') @plus('O') @plus('H') def G(s): return s H = F * G * G * F H('')
In :@plus('EXPERIMENT!') @plus('ANOTHER ') @plus('DO ') @plus('LETS ') def ident(s): return s ident('')
Out:'LETS DO ANOTHER EXPERIMENT!'