I have seen (a great) many tutorials and snippets of decorators w/ and w/o arguments, including those two I would look consider as canonical answers: Decorators with arguments, python decorator arguments with @ syntax, but I don't see why I get an error in my code.
The code below lives in the file decorators.py
:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Description: decorators
"""
import functools
def repeat(nbrTimes=2):
'''
Define parametrized decorator with arguments
Default nbr of repeats is 2
'''
def real_repeat(func):
"""
Repeats execution 'nbrTimes' times
"""
@functools.wraps(func)
def wrapper_repeat(*args, **kwargs):
while nbrTimes != 0:
nbrTimes -= 1
return func(*args, **kwargs)
return wrapper_repeat
return real_repeat
The first warning I get from my syntax-checker is that nbrTimes
is an "unused argument".
I tested the above in python3 interactive console with:
>>> from decorators import repeat
>>> @repeat(nbrTimes=3)
>>> def greetings():
>>> print("Howdy")
>>>
>>> greetings()
Traceback (most recent call last):
File "<stdin>", line 1 in <module>
File path/to/decorators.py, line xx in wrapper_repeat
'''
UnboundLocalError: local variable 'nbrTimes' referenced before assignment.
I just don't see where I'm bungling it. In other examples the passed parameter (here nbrTimes
) was not "used" until later in the inner function, so the "unused argument" warning and error upon execution leave me kind of high and dry. Still relatively new to Python. Help much appreciated.
Edit: (in response to duplicate flag by @recnac)
It is not clear at all what OP in your purported duplicate wanted to achieve. I can only surmise that he/she intended to have access to a counter defined inside a decorator's wrapper, from global scope, and failed to declare it as nonlocal
. Fact is we don't even know whether OP dealt with Python 2 or 3, although it is largely irrelevant here. I concede to you that the error messages were very similar, if not equivalent, if not the same. However my intent was not to access a in-wrapper-defined counter from global scope. I intended to make this counter purely local, and did. My coding errors were elsewhere altogether. It turns out the excellent discussion and solution provided by Kevin (below) are of a nature, totally different from just adding a nonlocal <var>
inside the wrapper definition block (in case of Python 3.x). I won't be repeating Kevin's arguments. They are limpid and available to all.
Finally I go out on a limb and will say that the error message is perhaps the least important of all here, even though it is clearly a consequence of my bad code. For that I make amends, but this post is definitely not a rehash of the proposed "duplicate".