There are some libraries in flask that are supposed to be used globally as follows.
from flask import Flask
from something import Something
class settings:
MESSAGE = "hello from something"
app = Flask(__name__)
app.config.from_object(settings)
hmm = Something(app) #this
@app.route("/")
def hello():
return hmm.hello() #here
if __name__ == "__main__":
app.run(port=4040)
Looking into the code inside, it seems that it does not substitute for app and takes app as an argument because it wants to get config information. Originally I don't want to use such a library. You may have to use it.
The implementation itself was as follows.
class Something(object):
def __init__(self, app=None):
self.init_app(app)
def init_app(self, app):
#Look at the config and do something
self.message = app.config["MESSAGE"]
def hello(self): #The method you want to call
return self.message
I don't want to put the app directly on global. For example, I think it is normal to use blueprint for the definition of view. However, if you rewrite it as follows, a problem will occur.
views.py
from flask import Blueprint
b = Blueprint("hello", __name__)
@b.route("/")
def hello():
return hmm.hello() #I want to call this
app.py
def make_app():
class settings:
MESSAGE = "hello from something"
app = Flask(__name__)
app.config.from_object(settings)
hmm = Something(app) #There is no way to touch this
app.register_blueprint(b)
return app
if __name__ == "__main__":
app = make_app()
app.run(port=4040)
If you wrap the generation of the app in a function, there is no way to access the hmm you want to use. On the other hand, if you try to return hmm as the return value of make_app, it will be in the same state as the global variable, and it will be overwhelming.
thread local object
It seems to be the culture of flask to use thread local object. For example, the request object is thread local. It may be better to do it in a way that follows this. By the way, if you want to make it thread local, you can do as follows. current_app and g are also thread local.
from flask import g, current_app
from werkzeug.local import LocalProxy
def find_hmm():
print("hoi")
if not hasattr(g, "hmm"):
print("hai")
g.hmm = Something(current_app)
return g.hmm
hmm = LocalProxy(find_hmm)
It can be shared between 1 requests. Of course, it will be regenerated every time a new request comes in. You may not like it.
If you make a request to http: // localhost: 4040 / twice, it will be as follows.
hoi
hai
hoi
hai
You may really want to have one singleton. It seems to be the culture of flask to publish a global proxy, so let's create an object with a similar interface following that.
class LazyOnceEvalObject(object):
def __init__(self, fn):
self._fn = fn
self.proxy = None
def __getattr__(self, name):
if self.proxy is None:
self.proxy = self._fn()
print("hai")
return getattr(self.proxy, name)
def find_hmm():
print("hoi")
return Something(current_app)
hmm = LazyOnceEvalObject(find_hmm)
Only on the first request, find_hmm ()
will generate hmm.
If you make a request to http: // localhost: 4040 / twice, it will be as follows.
hoi
hai
hai
The initialization process may take some time. It may be too burdensome to initialize the hmm proxy at the time of request (albeit only for the first time). In such a case, it may be better to forcibly create an application context and set it.
def make_app():
class settings:
MESSAGE = "hello from something"
app = Flask(__name__)
app.config.from_object(settings)
app.register_blueprint(b)
with app.app_context():
hmm.hello()
return app
It may be easier to explicitly create a context so that it can be retrieved with current_app, rather than trying hard to pass the app.
Creating a new context may also be useful during testing. For example, if you execute the following code, after entering a value in g.foo in f0, f0 is called after creating a new context with app_context (), so it will be None in the second f1. ..
def f0():
g.foo = "foo"
print("f0 before with")
f1()
with current_app.app_context():
print("f0 after with")
f1()
def f1():
print(getattr(g, "foo", None))
with app.app_context():
f0()
result
f0 before with
foo
f0 after with
None
Recommended Posts