Supposons que j'ai écrit un décorateur qui fait quelque chose de très générique. Par exemple, il peut convertir tous les arguments d'un type spécifique, effectuer une journalisation, de mettre en œuvre memoization, etc.
Voici un exemple:
def args_as_ints(f): def g(*args, **kwargs): args = [int(x) pour x dans args] kwargs = dict((k, int(v)) for k, v in kwargs.items()) de retour de f(*args, **kwargs) de retour g @args_as_ints def funny_function(x, y, z=3): """Calcule x*y + 2*z""" return x*y + 2*z >>> funny_function("3", 4.0, z="5") 22
Tout bien jusqu'à présent. Il y a un problème, cependant. Décoré de la fonction n'est pas de conserver la documentation de la fonction d'origine:
>>> help(funny_function) De l'aide sur la fonction g dans le module __principaux__: g(*args, **kwargs)
Heureusement, il existe une solution de contournement:
def args_as_ints(f): def g(*args, **kwargs): args = [int(x) pour x dans args] kwargs = dict((k, int(v)) for k, v in kwargs.items()) de retour de f(*args, **kwargs) g.__name__ = f.__nom__ g.__doc__ = f.__doc__ de retour g @args_as_ints def funny_function(x, y, z=3): """Calcule x*y + 2*z""" return x*y + 2*z
Cette fois, le nom de la fonction et de la documentation sont corrects:
>>> help(funny_function) De l'aide sur la fonction funny_function dans le module __principaux__: funny_function(*args, **kwargs) Calcule x*y + 2*z
Mais il y a encore un problème: la signature de la fonction est mal. L'information "*args, **kwargs" est à côté de rien.
Que faire? Je pense à deux simple mais imparfait solutions de contournement:
1 -- Inclure la signature correcte dans la docstring:
def funny_function(x, y, z=3): """funny_function(x, y, z=3) -- calcule x*y + 2*z""" return x*y + 2*z
C'est mauvais à cause de la duplication. La signature ne sera pas affiché correctement dans générée automatiquement de la documentation. Il est facile de mettre à jour la fonction et de l'oublier sur la modification de la docstring, ou de faire une faute de frappe. [Et oui, je suis conscient du fait que la docstring déjà doublons le corps de la fonction. S'il vous plaît ignorer ce; funny_function est juste un hasard.]
2 -- ne Pas utiliser un décorateur, ou utiliser à des fins spéciales de décorateur pour chaque signature:
def funny_functions_decorator(f): def g(x, y, z=3): de retour de f(int(x), int(y), z=int(z)) g.__name__ = f.__nom__ g.__doc__ = f.__doc__ de retour g
Cela fonctionne très bien pour un ensemble de fonctions ayant la même signature, mais c'est inutile en général. Comme je l'ai dit au début, je veux être en mesure d'utiliser les décorateurs entièrement de façon générique.
Je suis à la recherche d'une solution qui est entièrement en général, et de l'automatique.
La question est donc: est-il un moyen de modifier la décorées signature de fonction après qu'il a été créé?
Sinon, puis-je écrire un décorateur que des extraits de la signature de la fonction et l'utilise à la place de "*kwargs, **kwargs" lors de la construction de la décorées fonction? Comment puis-je extraire cette information? Comment dois-je construire le décoré de la fonction -- exec?
Toutes les autres approches?