Home > Blockchain >  Python - Call Pre-defined Function after Decorator
Python - Call Pre-defined Function after Decorator

Time:11-14

I am building a straight-forward Flask API. After each decorator for the API endpoint, I have to define a function that simply calls another function I have in a separate file. This works fine, but seems redundant. I would rather just call that pre-defined function directly, instead of having to wrap it within another function right after the decorator. Is this possible?

What I have currently:

import routes.Locations as Locations

# POST: /api/v1/locations
@app.route('/locations', methods=['GET'])
def LocationsRead ():
   return Locations.read()

Locations.read() function looks like this:

def read():
   return {
      'id': 1,
      'name': 'READ'
   }

What I am hoping to do:

import routes.Locations as Locations

# POST: /api/v1/locations
@app.route('/locations', methods=['GET'])
Locations.read()

CodePudding user response:

The @syntax of decorators is just syntactic sugar for:

def LocationsRead():
   return Locations.read()

LocationsRead = app.route('/locations', methods=['GET'])(LocationsRead)

So you could do something like:

LocationsRead = app.route('/locations', methods=['GET'])(Locations.read)

Arguably, that takes a bit longer to understand the intention and it's not that much more terse that your original code.

With exceptions and logging the stack trace, you also lose one level of the stack trace. That will make it hard to identify where and how Locations.read is being added as a route in a flask. The stack trace will jump straight from the flask library to routes.Locations:read. If you want to know how route was configured (eg.what the URL is parameterised with or what methods it works with), then you'll have to know already know which file the "decoration" took place. If you use normal decoration, you'll get a line pointing at the file containing @app.route('/locations', methods=['GET']).

That is, you get a debatable benefit and the potential to make debugging harder. Stick with the @ decorator syntax.

CodePudding user response:

Thanks to @Dunes and @RodrigoRodrigues answers, I played around with it more and found that the following works both for endpoints with and without arguments to pass, like an ID. See the code below.

# GET: /api/v1/locations
app.route(basepath   '/locations', methods=['GET'])(Locations.read)
# GET: /api/v1/locations/{id}
app.route(basepath   '/locations/<int:id>', methods=['GET'])(Locations.read)
# POST: /api/v1/locations
app.route(basepath   '/locations', methods=['POST'])(Locations.create)
# PUT: /api/v1/locations/{id}
app.route(basepath   '/locations/<int:id>', methods=['PUT'])(Locations.update)
# DELETE: /api/v1/locations/{id}
app.route(basepath   '/locations/<int:id>', methods=['DELETE'])(Locations.delete)

Now, I doubt this is standard practice, but if someone is looking to reduce the amount of code in their route declarations, this is one way to do it.

  • Related