In this question I asked about a function composition operator in Python. @Philip Tzou offered the following code, which does the job.
import functools
class Composable:
def __init__(self, func):
self.func = func
functools.update_wrapper(self, func)
def __matmul__(self, other):
return lambda *args, **kw: self.func(other.func(*args, **kw))
def __call__(self, *args, **kw):
return self.func(*args, **kw)
I added the following functions.
def __mul__(self, other):
return lambda *args, **kw: self.func(other.func(*args, **kw))
def __gt__(self, other):
return lambda *args, **kw: self.func(other.func(*args, **kw))
With these additions, one can use @
, *
, and >
as operators to compose functions. For, example, one can write print((add1 @ add2)(5), (add1 * add2)(5), (add1 > add2)(5))
and get # 8 8 8
. (PyCharm complains that a boolean isn't callable for (add1 > add2)(5)
. But it still ran.)
All along, though, I wanted to use .
as a function composition operator. So I added
def __getattribute__(self, other):
return lambda *args, **kw: self.func(other.func(*args, **kw))
(Note that this fouls up update_wrapper
, which can be removed for the sake of this question.)
When I run print((add1 . add2)(5))
I get this error at runtime: AttributeError: 'str' object has no attribute 'func'
. It turns out (apparently) that arguments to __getattribute__
are converted to strings before being passed to __getattribute__
.
Is there a way around that conversion? Or am I misdiagnosing the problem, and some other approach will work?