[PYTHON] Comment tromper et utiliser une terrible bibliothèque qui est censée être conservée globalement dans flask

introduction

Certaines bibliothèques sont censées être utilisées globalement dans flask.

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)  #cette


@app.route("/")
def hello():
    return hmm.hello()  #ici


if __name__ == "__main__":
    app.run(port=4040)

En regardant dans le code à l'intérieur, il semble qu'il ne se substitue pas à l'application et prend l'application comme argument parce qu'il veut obtenir des informations de configuration. À l'origine, je ne veux pas utiliser une telle bibliothèque. Vous devrez peut-être l'utiliser.

La mise en œuvre elle-même était la suivante.

class Something(object):
    def __init__(self, app=None):
        self.init_app(app)

    def init_app(self, app):
        #Regardez la configuration et faites quelque chose
        self.message = app.config["MESSAGE"]

    def hello(self):  #La méthode que vous souhaitez appeler
        return self.message

Je ne veux pas mettre l'application directement sur global

Je ne veux pas mettre l'application directement dans global. Par exemple, je pense qu'il est normal d'utiliser un plan pour la définition de la vue. Cependant, si vous le réécrivez comme suit, un problème se produira.

views.py

from flask import Blueprint
b = Blueprint("hello", __name__)


@b.route("/")
def hello():
    return hmm.hello()  #Je veux appeler ça

app.py

def make_app():

    class settings:
        MESSAGE = "hello from something"

    app = Flask(__name__)
    app.config.from_object(settings)
    hmm = Something(app)  #Il n'y a aucun moyen de toucher ça
    app.register_blueprint(b)

    return app


if __name__ == "__main__":
    app = make_app()
    app.run(port=4040)

Si vous encapsulez la génération d'application dans une fonction, il n'y a aucun moyen d'accéder au hmm que vous souhaitez utiliser. D'un autre côté, si vous essayez de renvoyer hmm comme valeur de retour de make_app, il sera dans le même état que la variable globale, et ce sera écrasant.

thread local object

Il semble que la culture de flask consiste à utiliser un objet local de thread. Par exemple, l'objet de requête est thread local. Il peut être préférable de le faire d'une manière qui suit ceci. À propos, si vous souhaitez rendre le thread local, vous pouvez procéder comme suit. current_app et g sont également des threads locaux.

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)

Il peut être partagé entre 1 demandes. Bien sûr, il sera régénéré chaque fois qu'une nouvelle demande arrive. Cela ne vous plaira peut-être pas.

Si vous faites une demande à http: // localhost: 4040 / deux fois, ce sera comme suit.

hoi
hai
hoi
hai

Interface similaire à l'objet local de thread

Vous voudrez peut-être vraiment avoir un singleton. Cela semble être la culture de flask de publier un proxy global, alors créons un objet avec une interface similaire à la suite de cela.

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)

Seulement à la première requête, find_hmm () générera hmm.

Si vous faites une demande à http: // localhost: 4040 / deux fois, ce sera comme suit.

hoi
hai
hai

Lorsque le processus d'initialisation prend du temps

Le processus d'initialisation peut prendre un certain temps. Il peut être trop fastidieux d'initialiser le proxy hmm au moment de la demande (mais seulement pour la première fois). Dans un tel cas, il peut être préférable de créer de force un contexte d'application et de le définir.

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

Il peut être plus facile de créer explicitement un contexte afin qu'il puisse être récupéré avec current_app, plutôt que d'essayer de passer l'application.

Histoire bonus

La création d'un nouveau contexte peut également être utile lors des tests. Par exemple, si vous exécutez le code suivant, après avoir entré une valeur dans g.foo dans f0, f0 est appelée après avoir créé un nouveau contexte avec app_context (), donc ce sera None dans le 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()

résultat

f0 before with
foo
f0 after with
None

Recommended Posts

Comment tromper et utiliser une terrible bibliothèque qui est censée être conservée globalement dans flask
Comment utiliser une bibliothèque qui n'est pas initialement incluse dans Google App Engine
Comment utiliser is et == en Python
Comment utiliser hmmlearn, une bibliothèque Python qui réalise des modèles de Markov cachés
Comment utiliser la bibliothèque C en Python
Comment utiliser la bibliothèque d'images Python dans la série python3
Conseils pour ceux qui ne savent pas comment utiliser is et == en Python
Comment installer la bibliothèque Python qui peut être utilisée par les sociétés pharmaceutiques
Un mémorandum sur l'utilisation de keras.preprocessing.image de Keras
Comment vérifier s'il est dans le type de dictionnaire (Dictionary, Hash) en utilisant tout ou partie
Remarques sur l'utilisation de StatsModels qui peuvent utiliser la régression linéaire et GLM en python
Comment utiliser Docker pour conteneuriser votre application et comment utiliser Docker Compose pour exécuter votre application dans un environnement de développement
[C / C ++] Passez la valeur calculée en C / C ++ à une fonction python pour exécuter le processus et utilisez cette valeur en C / C ++.
Comment configurer un serveur SMTP simple qui peut être testé localement en Python
[Python] Qu'est-ce qu'un tuple? Explique comment utiliser sans toucher et comment l'utiliser avec des exemples.
L'utilisation du japonais pour les noms de dossier et les noms de bloc-notes dans Databricks peut poser problème
Comment tester cette exception est déclenchée dans python unittest
Comment utiliser la méthode __call__ dans la classe Python
Comment utiliser pyenv et pyenv-virtualenv à votre manière
[Introduction à l'application Udemy Python3 +] 36. Utilisation de In et Not
Comment créer et utiliser des bibliothèques statiques / dynamiques en langage C
Comparaison de l'utilisation des fonctions d'ordre supérieur dans Python 2 et 3
Comment écrire une classe méta qui prend en charge à la fois python2 et python3
Remarques sur l'utilisation de la guimauve dans la bibliothèque de schémas
Comment comparer des listes et récupérer des éléments communs dans une liste
Utilisez networkx, une bibliothèque qui gère les graphiques en python (Partie 2: Tutoriel)
Comment donner et signifier l'option des contraintes dans scipy.optimize.minimize
Comment utiliser les fonctions dans des fichiers séparés version Perl et version Python
Comment déterminer qu'une clé croisée a été entrée dans Python3
Comment utiliser l'astérisque (*) en Python. C'est peut-être tout? ..
Est-ce que do.call () de R est une fonction classique d'ordre supérieur? Apprendre à utiliser
[Ln] Comment coller le lien symbolique du répertoire est compliqué
Comment utiliser les classes dans Theano
Comment utiliser .bash_profile et .bashrc
Comment installer et utiliser Graphviz
Comment utiliser Mysql avec python
Comment utiliser ChemSpider en Python
Comment utiliser PubChem avec Python
Comment saisir une chaîne de caractères en Python et la sortir telle quelle ou dans la direction opposée.
CNN détermine dans quelle université une belle femme est susceptible d'être
Comment obtenir un nom de colonne et un nom d'index spécifiques avec Pandas DataFrame
Comment créer un bot Janken qui peut être facilement déplacé (commentaire)
Comment mettre un espace demi-largeur avant les lettres et les chiffres en Python.
Comment rendre le nom du conteneur accessible dans Docker en tant que sous-domaine
Qu'est-ce qu'une bibliothèque en langage C? Quelles informations sont ouvertes au public?
Utilisation pratique des couches lors du chargement de bibliothèques sur Lambda
Comment arrêter le programme jusqu'à une date et une heure spécifiques en python
Comment enregistrer les informations de point caractéristique de l'image dans un fichier et l'utiliser pour la mise en correspondance
Je pensais qu'il serait lent d'utiliser l'instruction for dans NumPy, mais ce n'était pas le cas.
Comment utiliser les colonnes calculées dans CASTable
[Introduction à Python] Comment utiliser la classe en Python?
Comment diviser et enregistrer un DataFrame
Comment installer et utiliser pandas_datareader [Python]
[Pandas] Qu'est-ce que set_option [Comment utiliser]
Comment utiliser Google Test en langage C
Comment obtenir stacktrace en python
Connaissances minimales pour utiliser Form avec Flask
Comment utiliser l'interpréteur d'Anaconda avec PyCharm
python: Comment utiliser les locals () et globals ()
Comment utiliser __slots__ dans la classe Python