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?
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With