Fonctions de décoration Python avant appel
Question
J'ai un décorateur assez complexe écrit par quelqu'un d'autre. Ce que je veux faire, c'est appeler une version décorée de la fonction une fois basée sur une décision ou appeler la fonction d'origine (non décorée) une autre fois. Est-ce possible?
La solution
Avec:
decorator(original_function)()
Sans:
original_function()
Un décorateur est juste une fonction qui prend une fonction en argument et en retourne un autre. La syntaxe @ est totalement optionnelle. Peut-être qu'une sélection de la documentation pourrait aider à clarifier les choses.
Autres conseils
def original_function():
pass
decorated_function= decorator(original_function)
if use_decorated:
decorated_function()
else:
original_function()
Décorez une seule fois, puis choisissez la version à appeler.
Voici la recette que j'ai proposée pour le problème. J'avais aussi besoin de garder les signatures identiques alors j'ai utilisé le module décorateur mais vous pouvez re-gabarir pour éviter cela. Fondamentalement, l'astuce consistait à ajouter un attribut à la fonction. La fonction "originale" étant non liée, vous devez donc indiquer un "self" en tant que premier paramètre. J'ai donc ajouté du code supplémentaire pour le vérifier également.
# http://www.phyast.pitt.edu/~micheles/python/decorator-2.0.1.zip
from decorator import decorator, update_wrapper
class mustbe : pass
def wrapper ( interface_ ) :
print "inside hhh"
def call ( func, self, *args, **kwargs ) :
print "decorated"
print "calling %s.%s with args %s, %s" % (self, func.__name__, args, kwargs)
return interface_ ( self, *args, **kwargs )
def original ( instance , *args, **kwargs ) :
if not isinstance ( instance, mustbe ) :
raise TypeError, "Only use this decorator on children of mustbe"
return interface_ ( instance, *args, **kwargs )
call = decorator ( call, interface_ )
call.original = update_wrapper ( original, call )
return call
class CCC ( mustbe ):
var = "class var"
@wrapper
def foo ( self, param ) :
"""foo"""
print self.var, param
class SSS ( CCC ) :
@wrapper ( hidden_=True )
def bar ( self, a, b, c ) :
print a, b, c
if __name__ == "__main__" :
from inspect import getargspec
print ">>> i=CCC()"
i=CCC()
print ">>> i.var = 'parrot'"
i.var = 'parrot'
print ">>> i.foo.__doc__"
print i.foo.__doc__
print ">>> getargspec(i.foo)"
print getargspec(i.foo)
print ">>> i.foo(99)"
i.foo(99)
print ">>> i.foo.original.__doc__"
print i.foo.original.__doc__
print ">>> getargspec(i.foo.original)"
print getargspec(i.foo.original)
print ">>> i.foo.original(i,42)"
i.foo.original(i,42)
print ">>> j=SSS()"
j=SSS()
print ">>> j.bar(1,2,3)"
j.bar(1,2,3)