I’ve made myself a simple event system in python, and I found that the way I fired the events was pretty much the same every time: either at the end of a call, or before it. It felt like this would be a nice thing to have as a decorator. Here’s the code I’m using:
from functools import wraps
def fires(event):
"""
Returns a decorater that causes an `Event` to fire immediately before the
decorated function is called
"""
def beforeDecorator(f):
"""Fires the event before the function executes"""
@wraps(f)
def wrapped(*args, **kargs):
event.fire(*args, **kargs)
return f(*args, **kargs)
return wrapped
def afterDecorator(f):
"""Fires the event after the function executes"""
@wraps(f)
def wrapped(*args, **kargs):
result = f(*args, **kargs)
event.fire(*args, **kargs)
return result
return wrapped
# Should allow more explicit `@fires(event).uponCompletion` and
# `@fires(event).whenCalled`
afterDecorator.onceComplete = afterDecorator
afterDecorator.whenCalled = afterDecorator
return afterDecorator
With this code, I can successfully write this:
@fires(myEvent)
def foo(y):
return y*y
print func(2)
And everything works. The problem comes when I try to write this:
@fires(myEvent).onceComplete
def foo(y):
return y*y
print func(2)
That gives me a syntax error. Is there some special syntax for complex decorators? Does the parser stop after the first set of parentheses?
Nope, according to the grammar specification, not possible:
funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite decorators ::= decorator+ decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE dotted_name ::= identifier ("." identifier)* parameter_list ::= (defparameter ",")* ( "*" [parameter] ("," defparameter)* [, "**" parameter] | "**" parameter | defparameter [","] ) parameter ::= identifier [":" expression] defparameter ::= parameter ["=" expression] funcname ::= identifierDecorators must have their parentheses at the end