def sub3(n): return n - 3 def square(n): return n * n
It's easy to compose functions in Python:
>>> my_list [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> [square(sub3(n)) for n in my_list] [9, 4, 1, 0, 1, 4, 9, 16, 25, 36]
Unfortunately, to use the composition as a key it's awkward, you have to use them in another function which calls both functions in turn:
>>> sorted(my_list, key=lambda n: square(sub3(n))) [3, 2, 4, 1, 5, 0, 6, 7, 8, 9]
This should really just be sorted(my_list, key=square*sub3)
, because heck, function __mul__
isn't used for anything else anyway:
>>> square * sub3 TypeError: unsupported operand type(s) for *: 'function' and 'function'
Well let's just define it then!
>>> type(sub3).__mul__ = 'something' TypeError: can't set attributes of built-in/extension type 'function'
D'oh!
>>> class ComposableFunction(types.FunctionType): ... pass ... TypeError: Error when calling the metaclass bases type 'function' is not an acceptable base type
D'oh!
class Hack(object): def __init__(self, function): self.function = function def __call__(self, *args, **kwargs): return self.function(*args, **kwargs) def __mul__(self, other): def hack(*args, **kwargs): return self.function(other(*args, **kwargs)) return Hack(hack)
Hey, now we're getting somewhere..
>>> square = Hack(square) >>> sub3 = Hack(sub3) >>> [square(sub3(n)) for n in my_list] [9, 4, 1, 0, 1, 4, 9, 16, 25, 36] >>> [(square*sub3)(n) for n in my_list] [9, 4, 1, 0, 1, 4, 9, 16, 25, 36] >>> sorted(my_list, key=square*sub3) [3, 2, 4, 1, 5, 0, 6, 7, 8, 9]
But I don't want a Hack
callable class! The scoping rules are different in ways I don't fully understand, and it's arguably even uglier than just using the "lameda". Is it possible to get composition working directly with functions somehow?
In python, to multiply number, we will use the asterisk character ” * ” to multiply number. After writing the above code (how to multiply numbers in Python), Ones you will print “ number ” then the output will appear as a “ The product is: 60 ”. Here, the asterisk character is used to multiply the number.
Multiplication of Functions To multiply a function by another function, multiply their outputs. For example, if f (x) = 2x and g(x) = x + 1, then fg(3) = f (3)×g(3) = 6×4 = 24. fg(x) = 2x(x + 1) = 2x2 + x.
We can use numpy. prod() from import numpy to get the multiplication of all the numbers in the list. It returns an integer or a float value depending on the multiplication result.
You can use your hack class as a decorator pretty much as it's written, though you'd likely want to choose a more appropriate name for the class.
Like this:
class Composable(object): def __init__(self, function): self.function = function def __call__(self, *args, **kwargs): return self.function(*args, **kwargs) def __mul__(self, other): @Composable def composed(*args, **kwargs): return self.function(other(*args, **kwargs)) return composed def __rmul__(self, other): @Composable def composed(*args, **kwargs): return other(self.function(*args, **kwargs)) return composed
You can then decorate your functions like so:
@Composable def sub3(n): return n - 3 @Composable def square(n): return n * n
And compose them like so:
(square * sub3)(n)
Basically it's the same thing you've accomplished using your hack class, but using it as a decorator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With