Suppose I have a function which I have written as a binary-operator (binop), how do I extend it to a multi-operator (multiop) which takes an arbitrary number of arguments? Is there such a decorator in a library (e.g. in functools)?
For example (I want a decorator to give this behaviour):
@binop_to_multiop
def mult(a,b):
return a*b
mult(2,3,4) # 2*3*4 = 24
mult(7) # 7
mult(2,3) # 6
Obviously I can’t ask a question about decorators without mentioning, this answer.
.
I’ve tried writing my own, but can’t quite get it working, any explanation of where I’m going wrong would also be welcome:
def binop_to_multiop(f):
@functools.wraps(f)
def wrapper(*args, **kwds):
if len(args) == 1: return args[0] # fails
return f(args[0],(f(*args[1:], **kwds)), **kwds) #recursion attempt fails
return wrapper
Gives a TypeError: mult() takes exactly 2 arguments (N given) (for various N!=2).
Your attempt to code it yourself was very close to working. You just need to change the recursive step to recurse on
wrapperrather passing all but one argument tof:I didn’t have any problems with the base case, so I’m not sure what your comment
#failswas about.You may also need to think about which end of the list you start solving from (that is, does your operator have left or right associativity). For operators like multiplication and addition it won’t matter since
(a+b)+c = a+(b+c), but for other you may get strange results. For instance, subtraction may not work as you might expect:With the decorator defined above,
sub(a, b, c)will give a different result thana-b-c(it will doa-(b-c)instead of(a-b)-c). If you want them to behave the same way, you can redefine the decorator to be left associative (like most mathematical operators do in most computer languages) like this:A more sophisticated approach would be to make the associativity be a parameter to the decorator, but that gets tricky if you don’t want the parameter to be required.