I wanted to demonstrate the usefulness of decorators in python for some people and could not run a simple example: consider two functions (for simplicity without arguments) f
and g
. Their sum f + g can be defined as a function that returns f () + g (). Of course, adding, subtracting, etc. Functions are not defined at all. But it’s easy to write a decorator that converts each function to an added function.
Now I would like to have a decorator that turns any function into an “operational” function, that is, a function that behaves in the described way for any operator in the standard operator
module. My implementation is as follows:
import operator class function(object): def __init__(self, f): self.f = f def __call__(self): return self.f() def op_to_function_op(op): def function_op(self, operand): def f(): return op(self(), operand()) return function(f) return function_op binary_op_names = ['__add__', '__and__', '__div__', '__eq__', '__floordiv__', '__ge__', '__gt__', '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__or__', '__pow__', '__sub__', '__truediv__', '__xor__'] for name in binary_op_names: type.__setattr__(function, name, op_to_function_op(getattr(operator, name)))
Do a little test to see if it works:
@function def a(): return 4 def b(): return 7 c = a + b print c() print c() == operator.__add__(4, 7)
Output:
11 True
This is the final version that I received after some experiments. Now, let's make two small, irrelevant modifications to see what I tried before:
First: in the definition of binary_op_names
change the square brackets to parentheses. Suddenly (for me) a completely unrelated error message appears:
Traceback (most recent call last): File "example.py", line 30, in <module> c = a + b TypeError: unsupported operand type(s) for +: 'function' and 'function'
Where does this come from?
Second: Write op_to_function_op
as a lambda expression:
op = getattr(operator, name) type.__setattr__(function, name, lambda self, other: function(lambda: op(self(), other())))
Run a slightly more complex test case:
@function def a(): return 4 def b(): return 7 c = a + b print c() print c() == operator.__add__(4, 7) print c() == operator.__xor__(4, 7)
Output:
3 False True
It looks like an area leak, but again I don't understand why this is happening.