How can a decorator pass variables into a function without changing its signature?

You could do this with some trickery that inserts the variables passed to the decorator into the function's local variables:

import sys
from functools import wraps
from types import FunctionType


def is_python3():
    return sys.version_info >= (3, 0)


def more_vars(**extras):
    def wrapper(f):
        @wraps(f)
        def wrapped(*args, **kwargs):
            fn_globals = {}
            fn_globals.update(globals())
            fn_globals.update(extras)
            if is_python3():
                func_code = '__code__'
            else:
                func_code = 'func_code'
            call_fn = FunctionType(getattr(f, func_code), fn_globals)
            return call_fn(*args, **kwargs)
        return wrapped
    return wrapper


@more_vars(a="hello", b="world")
def test(x, y):
    print("locals: {}".format(locals()))
    print("x: {}".format(x))
    print("y: {}".format(y))
    print("a: {}".format(a))
    print("b: {}".format(b))


if __name__ == "__main__":
    test(1, 2)

Can you do this? Sure! Should you do this? Probably not!

(Code available here.)

Tags:

Python