Local variable referenced before assignment in decorated method
decorator, python, python-3.x, python-decorators
Solution
You are assigning to `message` in the innermost function:
message = message.format(
name=self.name,
cd=method_wrapper.cooldown.remaining,
max_cd=method_wrapper.cooldown.limit
)
That assignment makes it a local variable, but you cannot make that assignment without first accessing `message`. You cannot do that with a local.
Since you don't want to modify the closed-over argument, you want to use a new local name here:
formatted_message = message.format(
name=self.name,
cd=method_wrapper.cooldown.remaining,
max_cd=method_wrapper.cooldown.limit
)
SayText2(message=formatted_message).send(eargs['player'].index)
Problem
I'm creating a decorator that would allow me to do stuff like: ``` @cooldownf(lambda self, **eargs: 30 - self.level) def method(self, **eargs): ... ``` Which would simply decorate the method so that it has a cooldown. This all worked just fine and the method can now be executed every `30 - self.level` seconds. However, I wanted to add a message that would be displayed if the method is still on cooldown. I added a `message` parameter for the `cooldownf` decorator, but then I got an error `UnboundLocalError: local variable 'message' referenced before assignment` from the line `ìf message:` in my decorator's code: ``` def cooldownf(fn, message=None): """Decorates a method to have a dynamic cooldown. Decorator function for easily adding cooldown as a dynamic time (function) into skill's methods. The function gets called when the cooldown is needed, and the skill is passed to the function. Args: fn: Function to determine the cooldown of the method message: Optional message sent if there's still cooldown left Returns: Decorated method with a dynamic cooldown """ # Create a decorator using the function and message provided def method_decorator(method): # Create a wrapper method @wraps(method, assigned=WRAPPER_ASSIGNMENTS+('__dict__',), updated=()) def method_wrapper(self, **eargs): # If the method's cooldown is over if method_wrapper.cooldown.remaining <= 0: # Restart the cooldown method_wrapper.cooldown.start(1, fn(self, **eargs)) # And call the function return method(self, **eargs) # If there was cooldown remaining and a message is provided if message: # Format the provided message message = message.format( name=self.name, cd=method_wrapper.cooldown.remaining, max_cd=method_wrapper.cooldown.limit ) # Send it to the player SayText2(message=message).send(eargs['player'].index) # And exit with code 3 return 3 # Create the cooldown object for the wrapper method_wrapper.cooldown = TickRepeat(lambda: None) # And return the wrapper return method_wrapper # Return the decorator return method_decorator ``` What's causing this? I can print `message` just fine inside of `cooldownf` or `method_decorator`, but adding a print into the `method_wrapper` will cause the error to raise. That's exact code and I can't replicate it in IDLE with functions, does it have something to do with me using methods in particular?