356 votes

Quelles sont les utilisations courantes des décorateurs Python ?

Bien que j'aime à penser que je suis un codeur Python raisonnablement compétent, les décorateurs sont un aspect du langage que je n'ai jamais réussi à maîtriser.

Je sais ce qu'ils sont (superficiellement), j'ai lu des tutoriels, des exemples, des questions sur Stack Overflow, et je comprends la syntaxe, je peux écrire les miens, utiliser occasionnellement @classmethod et @staticmethod, mais il ne m'est jamais venu à l'esprit d'utiliser un décorateur pour résoudre un problème dans mon propre code Python. Je ne rencontre jamais un problème où je me dis : "Hmm... ça ressemble à un travail pour un décorateur !".

Je me demandais donc si vous pouviez me donner des exemples d'utilisation de décorateurs dans vos propres programmes, et j'espère que j'aurai un moment "A-ha ! obtenir les.

6 votes

Les décorateurs sont également utiles pour la mémorisation, c'est-à-dire la mise en cache du résultat d'une fonction dont le calcul est lent. Le décorateur peut renvoyer une fonction qui vérifie les entrées et, si elles ont déjà été présentées, renvoie un résultat mis en cache.

1 votes

Notez que Python dispose d'un décorateur intégré, functools.lru_cache qui fait exactement ce que Peter a dit, depuis Python 3.2, publié en février 2011.

0 votes

Le contenu de la Bibliothèque de décorateurs Python devrait vous donner une bonne idée de leurs autres utilisations.

133voto

RSabet Points 2887

J'utilise les décorateurs principalement pour des raisons de timing

def time_dec(func):

  def wrapper(*arg):
      t = time.clock()
      res = func(*arg)
      print func.func_name, time.clock()-t
      return res

  return wrapper

@time_dec
def myFunction(n):
    ...

16 votes

Sous Unix, time.clock() mesure le temps CPU. Vous pouvez utiliser time.time() à la place si vous voulez mesurer le temps d'une horloge murale.

24 votes

Un bel exemple ! Mais je n'ai aucune idée de ce qu'il fait. Une explication de ce que vous faites là, et comment le décorateur résout le problème serait très bien.

9 votes

Eh bien, il mesure le temps qu'il faut pour myFunction pour courir ...

103voto

John Fouhy Points 14700

Je les ai utilisés pour la synchronisation.

import functools

def synchronized(lock):
    """ Synchronization decorator """
    def wrap(f):
        @functools.wraps(f)
        def newFunction(*args, **kw):
            lock.acquire()
            try:
                return f(*args, **kw)
            finally:
                lock.release()
        return newFunction
    return wrap

Comme indiqué dans les commentaires, depuis Python 2.5, vous pouvez utiliser un fichier with dans le cadre d'une threading.Lock (ou multiprocessing.Lock depuis la version 2.6) pour simplifier l'implémentation du décorateur en le réduisant à un simple objet :

import functools

def synchronized(lock):
    """ Synchronization decorator """
    def wrap(f):
        @functools.wraps(f)
        def newFunction(*args, **kw):
            with lock:
                return f(*args, **kw)
        return newFunction
    return wrap

Quoi qu'il en soit, vous l'utilisez ensuite comme ceci :

import threading
lock = threading.Lock()

@synchronized(lock)
def do_something():
  # etc

@synchronzied(lock)
def do_something_else():
  # etc

En gros, ça met juste lock.acquire() / lock.release() de part et d'autre de l'appel de fonction.

21 votes

Cela peut être justifié, mais les décorateurs sont intrinsèquement déroutants, surtout pour les novices de première année qui viennent derrière vous et essaient de modifier votre code. Évitez cela avec la simplicité : faites en sorte que do_something() enferme son code dans un bloc sous 'with lock:' et tout le monde peut clairement voir votre objectif. Les décorateurs sont largement surutilisés par des personnes qui veulent paraître intelligentes (et beaucoup le sont en réalité) mais le code est ensuite transmis aux simples mortels et est altéré.

22 votes

@KevinJ.Rice Contraindre votre code pour que les "noobs de première année" puissent mieux le comprendre est une pratique terrible. La syntaxe des décorateurs est bien plus facile à lire et découple considérablement le code.

19 votes

@TaylerJones, la lisibilité du code est ma plus grande priorité lorsque j'écris. Le code est lu plus de 7 fois à chaque fois qu'il est modifié. Un code difficile à comprendre (pour les novices ou pour les experts qui travaillent sous pression) est une dette technique qui doit être payée chaque fois que quelqu'un visite l'arbre des sources.

76voto

Simon Points 4162

J'utilise les décorateurs pour vérifier le type des paramètres qui sont passés à mes méthodes Python via un RMI. Ainsi, au lieu de répéter encore et encore le même charabia de comptage de paramètres et de levée d'exceptions.

Par exemple, au lieu de :

def myMethod(ID, name):
    if not (myIsType(ID, 'uint') and myIsType(name, 'utf8string')):
        raise BlaBlaException() ...

Je viens de déclarer :

@accepts(uint, utf8string)
def myMethod(ID, name):
    ...

et accepts() fait tout le travail pour moi.

17 votes

Pour toute personne intéressée, il existe une implémentation de @accepts en PEP 318.

2 votes

Je pense qu'il y a une faute de frappe la première méthode devrait être accepts vous avez déclaré les deux comme "myMethod".

1 votes

@DevC Non, cela ne ressemble pas à une faute de frappe. Puisque ce n'est clairement pas une implémentation de "accepts(..)", et qu'ici "accepts(..)" fait le travail qui serait autrement fait par les deux lignes au début de "myMethod(..)" - c'est la seule interprétation qui colle.

49voto

cdleary Points 18869

Les décorateurs sont utilisés pour tout ce que vous souhaitez "envelopper" de manière transparente avec des fonctionnalités supplémentaires.

Django les utilise pour envelopper fonctionnalité "login requis" sur les fonctions de vue ainsi que pour enregistrement des fonctions du filtre .

Vous pouvez utiliser des décorateurs de classe pour ajouter des journaux nommés aux classes .

Toute fonctionnalité suffisamment générique que vous pouvez ajouter au comportement d'une classe ou d'une fonction existante peut être décorée.

Il y a aussi un discussion des cas d'utilisation sur le newsgroup Python-Dev indiqué par PEP 318 -- Les décorateurs pour les fonctions et les méthodes .

0 votes

Cherrypy utilise @cherrypy.expose pour distinguer les fonctions publiques des fonctions cachées. C'était ma première introduction et je m'y suis habitué à partir de là.

36voto

Pratik Deoghare Points 9766

Voici un très bon tutoriel avec de bons exemples

Bruce Eckel sur les décorateurs

Exemple : un système de construction basé sur les décorateurs

J'ai trouvé l'article très utile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X