There is one too many blank line after your imports.
It is debatable if there is too many blank lines in your decorator too. I personally think it's good without the blank lines.
If you ignore the docstring then 17.6% of the function is blank lines.
Use blank lines in functions, sparingly, to indicate logical sections.
You may feel the white space is needed, and so this section can be happily ignored.
Multi-line docstrings consist of a summary line just like a one-line docstring, followed by a blank line, followed by a more elaborate description.
Yours has this short summary with the elaborate description.
I would be thrown off if your summery came up in my IDE,as I would be confused where this example is.
The docstring is a phrase ending in a period. It prescribes the function or method's effect as a command ("Do this", "Return that"), not as a description; e.g. don't write "Returns the pathname ..."
Your summary line is more of a description. I'm not good with words, but the summary could be changed to, "Decorate a function inside a pygame loop, at the specified tick-rate.".
The docstring for a function or method should summarize its behavior and document its arguments, return value(s), side effects, exceptions raised, and restrictions on when it can be called (all if applicable). Optional arguments should be indicated. It should be documented whether keyword arguments are part of the interface.
Yours does not explain what
tick_rate is. A good way to do this is also explained in the PEP.
"""Form a complex number.
real -- the real part (default 0.0)
imag -- the imaginary part (default 0.0)
I was thrown off a bit to see the event handler below the main of the code. I think there is no difference, however it's probably best to keep to the norm.
Overall there's almost no problems with your style. Your docstrings could follow PEP257 more, as the biggest problem would be the summarized line at the beginning.
You should add the ability to pass a function to handle pygame events.
This is as the programmer currently would have to use a hack to get user input, or not use the decorator. Both bad options.
for a rudimentary example of what the handler could look like:
if event.type == pygame.QUIT:
You could however use
pygame.quit();sys.exit(0), but then if you exit multiple times you would need to make a function to exit, and it would remove a little added abstraction.
you would then need to add it to the decorator. The nicest way would probably be:
def game_loop(event_function, tick_rate=60):
# replace the current event handler.
for event in pygame.event.get():
This has the downside of having to pass an event-handler, unless you pass a default one, like the one above. However it allows the programmer to handle user input, a must in most pygame applications.