J'ai une fonction
def decorator(func): def new_func(*args, **kwargs): if (func.__name__ == 'func'): a = ? b = ? c = ? d = ? else: a = ? b = ? c = ? d = ? log_to_system(a, b, c, d) return func(*args, **kwargs) return new_func
et j'essaie d'écrire un décorateur qui comprend les arguments et enregistre certains d'entre eux sur un autre système.
def func(a,b,c,d): ...
3 Réponses :
Une approche simple consiste à faire en sorte que votre fonction log_to_system
accepte des paramètres variables et des paramètres de mots-clés variables en plus des paramètres connus qu'elle enregistrera réellement, de sorte que vous puissiez simplement transmettre les arguments variables et la variable arguments de mots clés de la fonction décorée vers log_to_system
et laissez l'interpréteur extraire les paramètres a
, b
, c
et d pour vous:
1 2 3 4
Ceci génère:
import inspect def log_to_system(a, b, c, d): print(a, b, c, d) def decorator(func): sig = inspect.signature(func) def new_func(*args, **kwargs): arguments = sig.bind(*args, **kwargs).arguments log_to_system(**{k: arguments[k] for k in log_to_system.__code__.co_varnames}) return func(*args, **kwargs) return new_func @decorator def func(a, b, c, d, e): pass func(1, 2, c=3, d=4, e=5)
Vous pouvez également utiliser inspect.signature
pour obtenir un dict d'arguments après avoir lié les arguments de variable et les arguments de mot-clé donnés à la signature de la fonction décorée, afin que vous puissiez appeler log_to_system
avec seulement les paramètres dont il a besoin:
XXX
Ceci génère:
1 2 3 4
C'est une idée intéressante. J'accepterai cette solution pour l'instant car elle résout mon problème.
Vous pouvez utiliser inspect
, exemple fonctionnel:
import inspect def deco(func): signature = inspect.signature(func) def _deco(*args, **kwargs): binded = signature.bind(*args, **kwargs) arguments = binded.arguments # OrderedDict print(arguments.items()) return func(*args, **kwargs) return _deco @deco def foo(a, b, c, d): pass @deco def bar(d, c, b, a): pass foo(1, 2, c=3, d=4) # odict_items([('a', 1), ('b', 2), ('c', 3), ('d', 4)]) bar(1, a=2, b=3, c=4) # odict_items([('d', 1), ('c', 4), ('b', 3), ('a', 2)])
Vous pouvez utiliser ce décorateur général pour vider les valeurs des paramètres:
def dump_args(func): # Decorator to print function call details - parameters names and effective values def wrapper(*func_args, **func_kwargs): arg_names = func.__code__.co_varnames[:func.__code__.co_argcount] args = func_args[:len(arg_names)] defaults = func.__defaults__ or () args = args + defaults[len(defaults) - (func.__code__.co_argcount - len(args)):] params = list(zip(arg_names, args)) args = func_args[len(arg_names):] if args: params.append(('args', args)) if func_kwargs: params.append(('kwargs', func_kwargs)) return func(*func_args, **func_kwargs) return wrapper
Les crédits appartiennent à @aliteralmind, il a suggéré ce décorateur dans ce StackOverflow post .
Si la solution consiste simplement à utiliser directement le résultat d'une autre question SO, il serait préférable de marquer cette question comme un double plutôt que de fournir une réponse en double.
Merci, j'ai ajouté un drapeau en double.
func (2,3,4, a = 1)
est-il un moyen valide d'utiliserfunc
? Si oui,b
est-il égal à 2?Quels quatre arguments recherchez-vous dans
new_func
? Etes-vous sûr quenew_func
doit être aussi général, si vous avez 4 arguments spécifiques en tête?@chepner oui, cela doit être général car je dois utiliser ce décorateur sur différentes fonctions et extraire des sous-ensembles de paramètres que je peux connecter à un système. Je ne veux pas tout enregistrer.
Sonne comme une mauvaise idée d'avoir un décorateur se comporter différemment pour différentes fonctions de l'OMI. Pourriez-vous utiliser deux décorateurs différents, ou utiliser un décorateur qui prend un argument pour lui dire quel style utiliser (et donc quelle fonction encapsulée renvoyer)?
Vous allez probablement devoir sortir le module
inspect
et commencer à fouiller dans l'argumentfunc
du décorateur.Copie possible de Décorateur pour imprimer les détails de l'appel de fonction - noms des paramètres et valeurs effectives