access decorator arguments inside the decorators wrapper function

1k views Asked by At

im trying to access my decorators arguments inside the wrapper function with no luck.

what i have is:

def my_decorator(arg1=False, arg2=None):

    def decorator(method):
        @functools.wraps(method)
        def wrapper(method, *args, **kwargs):
            # do something based on arg1 and arg2
            # accessing one of the two named arguments
            # ends up in a 'referenced before assignment'

            arg1 = arg1 # error
            arg2 = arg2 # error

            newarg1 = arg1 # working
            newarg2 = arg2 # working

            return method(*args, **kwargs)
        return wrapper
    return decorator

and i would use it like a normal decorator

@my_decorator(arg1=True, arg2='a sting or whatever else')
the_function()

i really don't understand why i can't access the decorators arguments.

2

There are 2 answers

0
Sven Marnach On BEST ANSWER

You can access arg1 and arg2, but you should not assign to these names, not even with "augmented" assign operators, because this would make them local variables in the inner function. The error message you get shows that you tried to do exactly this (though you did not show your code).

In Python 3, you can work around this problem using

nonlocal arg1, arg2

somewhere in wrapper().

8
AudioBubble On

It depends on what you do with arg1 and arg2. Generally, closures work perfectly without extra work. However, if you re-assign them in the inner function, Python assumes it's a local variable and you have to tell it otherwise.

In Python 3, declare nonlocal arg1, arg2. In Python 2, you have to cheat: Wrap the two into lists (arg1 = [arg1] in the outer function) and use arg1[0] in the inner function. If you want an explanation of why this works, either search for Python questions on this topic or refer to the documentation (somewhere in the language reference I believe, I'll search).

Your problem is that wrapper passes self to method. There's no self. You'd have to take it (and even then, you'd restrict the decorator to methods - why not let self slip into *args?).

I fail to see how you read "referenced before assignment" from "global name self is not defined"...