0

Preface

I'm using single dispatching with functools.singledispatch decorator like

from functools import singledispatch
from typing import Any


@singledispatch
def serialize(object_: Any) -> str:
    raise TypeError('Serialization for objects '
                    'of type "{type}" is not supported.'
                    .format(type=type(object_)))


@serialize.register(int)
def serialize_int(object_: int) -> str:
    return str(object_)

now if I want to conditionally decorate serialize_int like

log_int_overload = True  # some condition here

if log_int_overload:
    from functools import wraps


    def log(function):
        @wraps(function)
        def wrapped(*args, **kwargs):
            result = function(*args, **kwargs)
            print('For {args}, {kwargs} function returned: {result}.'
                  .format(args=args,
                          kwargs=kwargs,
                          result=result))
            return result

        return wrapped


    serialize_int = log(serialize_int)

then call

>>> serialize(1)
'1'

as we can see invokes "old", undecorated version. This happens because we've registered only "old" one overload and serialize don't know anything about decorated since it is a new function object.

Problem

How to modify overloads so "dispatcher"-function will grab changes?

I understand that we can register serialize_int again after decorating, but it looks like a code repetition issue, is there any other way?

Or more generally: can we somehow modify function object in-place? Decorating __call__ attribute won't help.

Azat Ibrakov
  • 9,998
  • 9
  • 38
  • 50
  • 1
    You prolly want to decorate with `log` first, then register the decorated version and use your flag to log (or not log) inside the `wrapper` function. – Moses Koledoye Oct 18 '18 at 20:13
  • @MosesKoledoye: yes, I can, but it won't work if I want to decorate overload that is not written by me – Azat Ibrakov Oct 19 '18 at 06:56

0 Answers0