Question

Je veux construire des classes pour être utilisé comme décorateurs avec les principes intacts suivants:

  1. Il devrait être possible d'empiler plusieurs de ces décorateurs de classe au-dessus de 1 fonction.
  2. Le pointeur de nom de la fonction résultante doit être impossible à distinguer de la même fonction sans un décorateur, sauf peut-être pour tout type / classe est.
  3. Commande hors les décorateurs ne doivent pas être pertinents à moins effectivement mandaté par les décorateurs. C'est à dire. décorateurs indépendants pourraient être appliqués dans un ordre quelconque.

Ceci est un projet Django, et le cas particulier, je travaille maintenant la méthode a besoin de 2 décorateurs, et apparaissent en fonction de python normal:

@AccessCheck
@AutoTemplate
def view(request, item_id) {}

@AutoTemplate change la fonction de sorte qu'au lieu de retourner un HttpResponse, il retourne juste un dictionnaire pour une utilisation dans le contexte. Un RequestContext est utilisé, et le nom de modèle est déduit du nom de la méthode et le module.

@AccessCheck ajoute des contrôles supplémentaires sur l'utilisateur en fonction du item_id.

Je suppose que c'est juste pour obtenir le bon constructeur et copier les attributs appropriés, mais quels attributs sont ces?

Le décorateur suivant ne fonctionne pas comme je le décris:

class NullDecl (object):
    def __init__ (self, func):
        self.func = func
    def __call__ (self, * args):
        return self.func (*args)

Comme le montre le code suivant:

@NullDecl
@NullDecl
def decorated():
    pass

def pure():
    pass

# results in set(['func_closure', 'func_dict', '__get__', 'func_name',
# 'func_defaults', '__name__', 'func_code', 'func_doc', 'func_globals'])
print set(dir(pure)) - set(dir(decorated));

De plus, essayez d'ajouter dans le constructeur NullDecl, et il travaillera pour le premier décorateur, mais pas la seconde « Fonction d'impression nom . » -. Comme le nom sera manquant

raffiné eduffy de répondre un peu, et il semble fonctionner assez bien:

class NullDecl (object):
    def __init__ (self, func):
        self.func = func
        for n in set(dir(func)) - set(dir(self)):
            setattr(self, n, getattr(func, n))

    def __call__ (self, * args):
        return self.func (*args)
    def __repr__(self):
        return self.func
Était-ce utile?

La solution

Une classe de décorateur ne rien faire ressembler à ceci:

class NullDecl (object):
   def __init__ (self, func):
      self.func = func
      for name in set(dir(func)) - set(dir(self)):
        setattr(self, name, getattr(func, name))

   def __call__ (self, *args):
      return self.func (*args)

Et vous pouvez alors appliquer normalement:

@NullDecl
def myFunc (x,y,z):
   return (x+y)/z

Autres conseils

Le décorateur le module vous permet d'écrire des décorateurs préservant la signature.

PythonDecoratorLibrary pourrait fournir des exemples utiles pour les décorateurs.

Pour créer un décorateur qui enveloppe les fonctions dans une affaire qui les rendent impossibles à distinguer de la fonction d'origine, utilisez functools.wraps.

Exemple:


def mydecorator(func):
    @functools.wraps(func):
    def _mydecorator(*args, **kwargs):
        do_something()
        try:
            return func(*args, **kwargs)
        finally:
            clean_up()
    return _mydecorator

# ... and with parameters
def mydecorator(param1, param2):
    def _mydecorator(func):
        @functools.wraps(func)
        def __mydecorator(*args, **kwargs):
            do_something(param1, param2)
            try:
                return func(*args, **kwargs)
            finally:
                clean_up()
        return __mydecorator
    return _mydecorator

(ma préférence personnelle est de créer décorateurs utilisant des fonctions, non classes)

L'ordre des décorateurs se présente comme suit:


@d1
@d2
def func():
    pass

# is equivalent to
def func():
    pass

func = d1(d2(func))
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top