J'ai une application Flask simple où je veux valider les demandes au format json avec un décorateur comme celui-ci:

def validate_request(*expected_args):
    """
    Validate requests decorator
    """
    # print('=======================ENTER VALIDATE_REQUEST================')
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            json_obj = request.get_json()
            for expected_arg in expected_args:
                if expected_arg not in json_obj or json_obj.get(expected_arg) is None:
                    return api_response({'error': f"You must call with all request params: {', '.join(expected_args)}"})
            return func(*args, **kwargs)
        return wrapper
    return decorator

Et du côté de la route comme ceci:

@user_api.route('/login', methods=['POST'])
@validate_request('email', 'password')
def login():
    req_data = request.get_json()
......................

Ma question est de savoir pourquoi l'instruction PRINT de Decorator n'est pas affichée lorsque j'appelle la route '/ login'?

Le message est enregistré uniquement lorsque je démarre le serveur (exécution du flacon).

Je vous remercie.

1
nipuro 11 avril 2020 à 18:40

2 réponses

Meilleure réponse

Les décorateurs Python remplacent les fonctions qu'ils décorent. Ce remplacement se produit au démarrage du programme lorsque l'interpréteur lit le code. C'est à ce moment que votre instruction d'impression sera exécutée. Passé ce délai, la fonction renvoyée est le seul code qui s'exécutera. Si vous voulez que l'impression s'exécute à chaque appel, vous devez mettre dans la fonction réelle qui sera appelée:

def validate_request(*expected_args):
    """
    Validate requests decorator
    """
    # print('=======================Function Decoration Happening================')
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print("==== ENTER VALIDATE_REQUEST ===")
            json_obj = request.get_json()
            for expected_arg in expected_args:
                if expected_arg not in json_obj or json_obj.get(expected_arg) is None:
                    return api_response({'error': f"You must call with all request params: {', '.join(expected_args)}"})
            return func(*args, **kwargs)
        return wrapper
    return decorator
1
Mark M 11 avril 2020 à 16:00

Votre relevé d'impression est en validate_request. Bien que validate_request renvoie un décorateur, ce n'est pas un décorateur lui-même. C'est une fabrique de décorateurs si vous voulez, et n'est exécutée qu'une seule fois pour créer le décorateur et décorer login lorsque python charge votre code, d'où la raison pour laquelle votre instruction print n'est exécutée qu'une seule fois lorsque vous démarrez votre serveur. Gardez à l'esprit que le décorateur lui-même est également exécuté une seule fois pour remplacer login par tout ce que le décorateur renvoie, dans ce cas, wrapper. Ainsi, wrapper est la fonction réelle qui sera appelée à chaque requête. Si vous y mettez votre relevé imprimé, vous le verrez à chaque demande.

def validate_request(*expected_args):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print("=== Enter validate request ===")
            return func(*args, **kwargs)
        return wrapper
    return decorator
1
Tomasito665 11 avril 2020 à 16:12