micheles/decorator

Name collision between decorator arguments and function arguments

joaoe opened this issue · 1 comments

joaoe commented

Hi.
From the docs, this example

@decorator
def blocking(f, msg='blocking', *args, **kw):
     # (...)

@blocking(msg="Please wait ...")
def read_data(nbytes):
     # (...)

I'm concerned about collisions in argument names, e.g., both the decorator and the decorated have a msg argument.

So 1. raise a TypeError() when decorating a function with an argument which name matches a name of an argument to the decorator. Would definitely cause issues for code already specifying the same argument names on purpose to capture those variables. Perhaps passing an extra argument to decorator like @decorator(validate=True) or something which would cause that decorator to check for collisions.
or 2. Find a way to pass the decorator arguments and function arguments separately to the decorator function. Cumbersome. Would also require some extra parameter to maintain backwards compatibility. Perhaps something like

@decorator(decorator_args="extra_args")
def blocking(f, extra_args, *args, **kw):
    args, kwds = extra_args # tuple and dict
    return f(*args, **kw)

I think option 2 might be the most useful one.

Thank you,

joaoe commented

After further testing, I can see parameters to the decorator and to the decorated function are handled separately always, so there is no problem they share names. So issue closed.

Testcase:

class TestArgumentNameCollision(unittest.TestCase):
    def test_main(self):
        @decorator
        def dec0(func, a=None, *args, **kwds):
            return [a, func(*args, **kwds)]

        def func0(a):
            return a

        self.assertEqual(dec0(a=1)(func0)(a=2), [1, 2])