NovFora Dev

**Thread ** Quick question about Python decorator syntax — need to understand @app.route vs a custom decorator

Stella Cook

Stella Cook

3 months ago

Body Content: Hey everyone, I'm learning Flask and seeing @app.route('/') everywhere but I don't fully get what the '@' symbol is doing under the hood. Is it just syntactic sugar for wrapping functions? If so, could you show me how to write that same thing as a plain function call instead of using the decorator syntax? Would love to see both versions side by side so I can build an intuition for when decorators are actually useful vs just a convention. Thanks!

Owen Brown

Owen Brown

3 months ago

The key thing with @app.route is that it actually returns nothing — it just registers

Lillian Young

Lillian Young

2 months ago

This is actually a great conceptual fork in the road because it's where most people hit their first wall with decorators and I want to make sure we disambiguate what's happening under the hood before you build anything custom on top of Flask's internals, which can be genuinely opaque if you haven't read the source.

The thing about @app.route('/endpoint') is that it isn't actually a decorator in the standard Python sense — well, technically it IS a decorator but not one that returns a wrapper function. It takes the view function as an argument and registers it into app.url_map by calling add_url_rule(view_func, endpoint=None, url_prefix='/endpoint', ...). So when you look at @app.route('/ping'), Python is doing add_url_rule(your_function, ..., url_prefix='/ping'). The function itself isn't modified — it's not wrapped at all. Flask later looks up the endpoint in the URL map and calls your original un-wrapped function directly when a request matches that route. This distinction matters because if you try to write @app.route as if it were wrapping your function, you'll run into bizarre issues where decorator arguments don't behave the way you expect.

Now let me contrast that with what you'd want for a custom decorator — say something like @authenticated or @cached_response. In those cases, YOU write the wrapper and THAT is where the magic happens. A proper generic decorator factory would look like this:

from functools import wraps

def authenticated(role=None):  # role argument makes it a decorator factory
    def actual_decorator(func):      # func is your decorated view function
        @wraps(func)              # CRITICAL: preserves __name__ and docstrings
        def wrapper(*args, **kwargs):
            user = flask.

Join the conversation to leave a reply.

Sign in to reply

Related topics