coady / multimethod

Multiple argument dispatching.
https://coady.github.io/multimethod
Other
277 stars 24 forks source link

Stacking custom decorators with @multimethod #120

Closed ritik-kansal closed 4 months ago

ritik-kansal commented 4 months ago

Question

is there a way to apply separate, decorators for separate signatures, without using register, because with register i need to create a default function with @multimethod.

Code

from multipledispatch import dispatch
import time

def greeting_wrapper(func):
    def wrapper(*args, **kwargs):
        print("Hi")
        return func(*args, **kwargs)
    return wrapper

def time_taken_wrapper(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        time.sleep(1)
        end = time.time()
        print(f"Time taken: {end-start}")
        return result
    return wrapper

@multimethod
@greeting_wrapper #<- is there a way to apply separate, decorators for separate signatures?
def add(a: int, b: int):
    return a + b

@multimethod
@time_taken_wrapper #<- this wrapper is getting applied to all overloaded functions
def add(a: str, b: str):
    return a + b

print(add("1", "2"))
print(add(1, 2))

Output

Time taken: 1.0009300708770752
12
Time taken: 1.0050899982452393
3

Code

This works fine but dont want to have the default implementation of add

@multimethod
def add(): ...

@add.register(int, int)
@greeting_wrapper
def _(a,b):
    return a + b

@add.register(str, str)
@time_taken_wrapper
def _(a,b):
    return a + b

print(add(1, 2))
print(add("1", "2"))
coady commented 4 months ago

The issue is that wrapper does not have the func metadata, particularly its annotations. functools.update_wrapper provides this feature.

    return update_wrapper(wrapper, func)
ritik-kansal commented 4 months ago

Thanks @coady, that solved the issue.