What's throwing me off -- and I'm sure it's something trivial I'm not seeing -- is how we add the functions to the routes dictionary. When is the decorator's code actually executed? Is that done at import time? My assumption is that its code is executed when its counterpart is called, though clearly that mustn't be the case.
Given my understanding from the article, there's a hole: how does serving route "/" know to call that function if (given my assumptions) the @app.route("/") decoration is not executed until the function it decorates is called?
app.route("/") is just a function call which will be run by Python on module import, like any other function that you call in the top level of your module.
The return value of the function is a decorator, so then the @ syntax applies it to the succeeding function. In the process of applying the decorator, it adds the route to the dictionary. That's also on module import.
Plain decorators work how you expect but generators are different. The decorator generator is called at import time, which is when the association between the route and the function is stored.
Well, no. The decorator generator is called first, then the decorator is called, all at the time when the line "@app.route()" is first reached during import.
You could just as easily write @foo.bar[baz]('abc').hello
and it would still work - the code after the @ is just an expression that should return a callable.
Yes I had to think about it and test it (not done much Python recently). The decorating function is called as soon as the decorated function is declared.
These are the results of a simple test in the Python console.
>>> def dec(f):
... print "Decorator ran"
... return f
...
>>> @dec
... def decorated(i):
... print "Decorated function ran"
...
Decorator ran
>>> decorated(5)
Decorated function ran
>>> decorated(5)
Decorated function ran
def function():
print("Hello World!")
function = decorator_factory(foo, bar)(function)
or in this case, app.route(path)(function). So route() needs to return something that can be called with one argument. That's executed immediately at the time the function is defined.
Also the syntactic sugar lets you do stupid things like
>>> @print
... def f():
... pass
...
<function f at 0x101cfdde8>
>>> repr(f)
'None'
because print is a function that has a side effect and returns None. (If you're on Python 2, don't forget to `from __future__ import print_function`)
Given my understanding from the article, there's a hole: how does serving route "/" know to call that function if (given my assumptions) the @app.route("/") decoration is not executed until the function it decorates is called?