Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Decorateur sur un appel de fonction

+1 vote

En python, on ne peut décorer une fonction qu'à la définition de celle-ci, pourquoi ne pas avoir étendu aux appels de fonction ?

L'idée typiquement serait de pouvoir décorer une fonction d'une lib externe et donc d'éviter d'avoir à la wrapper en changeant son nom

Un exemple concret avec la librairie requests, on veut vérifier à chaque appel des fonctions get et post que la connection internet est toujours ok et donc on écrit un code qui ressemblerait à ça:

def check_connection(func):
    def wrapper(*args, **kwargs):
        try:
            func(*args, **kwargs)
        except ConnectionError:
            print('No internet.')
            sys.exit(0)


    return wrapper


@check_connection
html = requests.get('https://google.fr')

[....]

@check_connection
requests.post('http://httpbin.org/post', data = {'key':'value'})

Je me retrouve souvent dans un cas de figure où cette fonctionnalité me manque et donc je me pose la question, y a t-il une méthode Pythonique déjà existante qui m'aurait échappé ?

Sinon, pensez-vous que cette idée est interessante et mérite d'ếtre débattue sur python-ideas ?

demandé 23-Sep-2018 par superlevure (120 points)

Je ne pense pas que ça soit pertinent d'en discuter sur python-idea parce que ça produit du code ambigü. Par exemple, que ce passe-t-il si on fait quelque chose comme ça:

@decorator
a = fun(foo(x) + bar(y))

Dans ce cas, doit-on appliquer le décorateur seulement à fun, aussi à foo et à bar? On peut aussi imaginer vouloir utiliser des décorateurs différents sur les différentes fonctions appelées.

1 Réponse

+3 votes
 
Meilleure réponse

oui, c'est possible.

Sans modifier ton code d'exemple :

html = check_connection(requests.get)('https://google.fr')
check_connection(requests.post)('http://httpbin.org/post', data = {'key':'value'})

Par ailleurs, dans le cas de ton exemple, on peut aller voir vers un context manager pour pour écrire:

with check_connection():
    html = requests.get('https://google.fr')

with check_connection():
    requests.post('http://httpbin.org/post', data = {'key':'value'})

une possiblité d'implémentation étant:

from contextlib import contextmanager

@contexmanager
def check_connection():
    try:
        yield
    except ConnectionError:
        print('No internet.')
        sys.exit(0)
répondu 24-Sep-2018 par bubulle (2,256 points)
sélectionné 24-Sep-2018 par superlevure
...