2017-09-01 1 views
2

je le débogueur générique suivante:rassemblent les noms de param de votre déclaration de fonction

def debugger(method): 

    def dec(*args, **kwargs): 
     print("\ndebugging '{name}':\n".format(name=method.__name__)) 
     FOUR_SPACES = " " * 4 
     EIGHT_SPACES = " " * 8 
     if args: 
      print("{four}args:\n".format(four=FOUR_SPACES)) 
      for arg in args: 
       print("%s%s" % (EIGHT_SPACES, arg)) 
     if kwargs: 
      for key, value in kwargs.items(): 
       print("{four}{key}:\n{eight}{value}\n".format(
        four=FOUR_SPACES, 
        key=key, 
        eight=EIGHT_SPACES, 
        value=value 
       )) 

     if args or kwargs: 
      print("\n") 

     result = method(*args, **kwargs) 
     return result 

    return dec 

@debugger 
def generate_minutes_in_timespan(start, end, cutoff_date=None): 
    # cutoff_date is just example of kwarg 
    minutes_delta = (end - start).seconds/60 
    datetimes = [] 
    delta_range = range(0, minutes_delta + 1) 
    return [start + timedelta(minutes=i) for i in delta_range] 

Debugger fera:

debugging 'generate_minutes_in_timespan': 

    args: 

     2017-08-31 17:19:00 
     2017-09-01 12:05:00 

cela me plaît un peu, mais remarquez que j'ai raté la vraie information.

Ce que je veux:

debugging 'generate_minutes_in_timespan': 

    args: 

     start = 2017-08-31 17:19:00 
     end = 2017-09-01 12:05:00 

    *args: 

     not allowed 

    kwargs: 

     cutoff_date = None 

    *kwargs: 

     not allowed 

Ces args ont une signification sémantique, et peuvent être utilisés comme start et end ... ils ne sont pas *args.

Y at-il une manière profonde dans la bibliothèque standard de Python Je peux lire cette méthode generate_minutes_in_timespan et arrachez la déclaration, les noms et l'ordre des args de position nécessaires, aussi les noms des kwargs déclarés (comme déclarant cutoff_date=None, je veux savoir cutoff_date a été offert comme un kwarg, vs le **kwargs ...)

Je tire pour {'args': [('start', 'the value given'), ('end', 'the user given value')], 'star_args': None, 'kwargs': {'cutoff_date': None}, 'star_kwargs': None} pour l'information complète de débogage.

Merci

Répondre

4

De l'intérieur du décorateur, utilisez le module inspect pour découvrir les noms arg:

>>> def generate_minutes_in_timespan(start, end, cutoff_date=None): 
...  ... 
... 
>>> inspect.getargspec(generate_minutes_in_timespan) 
ArgSpec(args=['start', 'end', 'cutoff_date'], varargs=None, keywords=None, defaults=(None,)) 
      ^ ^
       |________|_____ here they are... 

correspondre les arguments passés avec les noms de arg réels est laissé comme exercice pour l'OP.

3

Utilisation inspect.signature(method).bind:

for name, val in inspect.signature(method).bind(*args, **kwargs).arguments: 
    print('{} = {}'.format(name, val)) 

Si vous êtes sur Python 2, il y a un backport de cette fonctionnalité sur PyPI vous pouvez utiliser.

+0

Je pense que l'utilisateur est sur py 2 parce qu'ils comptaient sur une division entière '/'. C'est certainement une meilleure réponse que la mienne pour les utilisateurs de py 3. – wim

1

Le résultat est agréable:

import inspect 

def debugger(method): 

    def dec(*args, **kwargs): 
     print("\ndebugging '{name}':\n".format(name=method.__name__)) 
     FOUR_SPACES = " " * 4 
     EIGHT_SPACES = " " * 8 

     inspector = inspect.getargspec(method) 

     arg_names = inspector.args 
     var_args = inspector.varargs 
     keyword_args = inspector.keywords 

     def wrap_string_in_quotes(value): 
      if isinstance(value, str): 
       return '"' + value + '"' 
      else: 
       return value 

     if args: 
      print("{four}args:\n".format(four=FOUR_SPACES)) 
      for index, arg_name in enumerate(arg_names): 
       print(
        "{eight}{name} = {arg}" \ 
        .format(
         eight=EIGHT_SPACES, 
         name=arg_name, 
         arg=wrap_string_in_quotes(args[index]) 
        ) 
       ) 

     if var_args: 
      start = len(arg_names) 
      these_args = args[start:] 
      print("\n{four}*{star_arg_name}:\n".format(four=FOUR_SPACES, star_arg_name=var_args)) 
      for this_var_arg in these_args: 
       print("{eight}{arg}".format(eight=EIGHT_SPACES, arg=wrap_string_in_quotes(this_var_arg))) 

     if kwargs: 
      print("\n{four}**{kwargs_name}:\n".format(four=FOUR_SPACES, kwargs_name=keyword_args)) 
      for key, value in kwargs.items(): 
       print("{eight}{key} = {value}\n".format(
        eight=EIGHT_SPACES, 
        key=key, 
        value=wrap_string_in_quotes(value) 
       )) 

     if args or kwargs: 
      print("\n") 

     result = method(*args, **kwargs) 
     return result 

    return dec 


@debugger 
def one_two_kwarg_three_star_args_star_kwargs(one, two, three=None, *args, **kwargs): 
    pass 

one_two_kwarg_three_star_args_star_kwargs(1, 2, 3, 'star arg 1', 'star arg 2', blah='blah, kwarg') 

-t

$ python debugger.py 

debugging 'one_two_kwarg_three_star_args_star_kwargs': 

    args: 

     one = 1 
     two = 2 
     three = 3 

    *args: 

     "star arg 1" 
     "star arg 2" 

    **kwargs: 

     blah = "blah, kwarg"