I'd just like to put in a good word for decorators... I have no idea why these confused me for so long, but they did.
Consider this code:
Anyone can see that in that code you're creating a function, then printing it. That code is actually identical to:
So using a decorator is exactly the same as calling the decoratING function with the decoratED function as the first argument.
When I'm writing tests as using throw-away functions (usually print), I'll often do something like:
assert decorator(print) is print
This is because the usual form is to return the decorated form of the function.
To give a more useful example:
from time import time, sleep
def timer(func):
"""Time how long it takes for func to complete."""
def inner(*args, **kwargs):
started = time()
ret = func(*args, **kwargs)
print(
'Function %r completed in %.2f seconds.' % (func, time() - started)
)
return ret
return inner
@timer
def print_after(seconds, message):
sleep(seconds)
print(message)
print_after(5.0, 'Hello world.')
Running python timer.py gives me:
Hello world.
Function <function print_after at 0x055990C0> completed in 5.00 seconds.
Depending on how you're structuring your code, decorators make a lot of sense.
With Mindspace I'm using the for commands.
I could do:
from mindspace_protocol import MindspaceParser
class Parser(MindspaceParser):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.commands['message'] = self.message
def message(self, con, msg):
print(msg)
parser = Parser()
Or I could do:
from mindspace_protocol import MindspaceParser
parser = MindspaceParser()
@parser.command
def message(self, con, msg):
print(msg)
You can see at a glance which is less typing.
Either way, decorators are syntactic sugar and should not be treated as any great mystery. They're another tool available to the Python programmer to either use or not.
If I've still not convinced you, consider this:
Would you rather have one function which handles all keypresses in your game with a snakes nest of if statements? Or would you rather have a list of lines like:
@key('SPACE')
def handle_space():
"""Fire a weapon."""
shoot()
-----
I have code on
GitHub