Let's say I have a very simple web app in python Tornado framework with a single endpoint. All I'm interested in is returning a value calculated before starting the server. Slightly modified example from https://www.tornadoweb.org/en/stable/index.html will do just fine.
handler.py
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write('I want to return var `expensive_value`')
main.py
import tornado.ioloop
import tornado.web
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
# calculate some var here before starting the server
expensive_value = 'value from long_calculation()'
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
When running python main.py
and sending a request to the endpoint it returns only a string of course. But I'd like to return the actual value of expensive_value
. Currently I'm aware of two solutions to the problem.
handler.py
import tornado.web
global_variable = None
def setter(val):
global global_variable
global_variable = val
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write(global_variable)
main.py
import tornado.ioloop
import tornado.web
from handler import MainHandler, setter
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
expensive_value = 'value from long_calculation()'
setter(expensive_value)
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
Having a global var and setting its value from some other module sounds like an antipattern to me.
handler.py
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def initialize(self, expensive_value):
self.expensive_value = expensive_value
def get(self):
self.write(self.expensive_value)
main.py
import tornado.ioloop
import tornado.web
from handler import MainHandler
def make_app(parameter):
return tornado.web.Application([
(r"/", MainHandler, {'expensive_value': parameter}),
])
if __name__ == "__main__":
expensive_value = 'value from long_calculation()'
app = make_app(expensive_value)
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
This solution is better. But initialize
method is called for every request. I realize the overhead for that would be rather small but I think it might be misleading for potential reader of the code since expensive_value
never changes.
Both of these solution work. But I don't like any of them and it seems like I'm missing some Tornado functionality. What would be a pythonic way to solve this?
For example I believe Flask has app.config
dictionary that is accessible in handlers and it seems to be a nice solution to this as expensive_value
is indeed a configuration to the app. But I'm not aware of anything similar in Tornado.
Handlers have access to self.application.settings
which is a dictionary containing additional arguments passed to the Application
constructor.
So you can pass expensive_value
directly to the Application
class like this:
def make_app(parameter):
return tornado.web.Application(
[
(r"/", MainHandler),
],
expensive_value=parameter
)
And access this value in any handler like this:
def initialize(self):
self.expensive_value = self.application.settings.get('expensive_value')