Debug showing variable name and value?

Asked

Viewed 658 times

1

Often when I need to debug the value of a variable at runtime I use the print().

But when there are many variables, I need to identify the variable name along with the value.

In this way, the print gets more laborious:

print ("x=", x, "y=", y, "x+y*2=", x+y*2)

The ideal would be a simple command such as:

debug (x, y, x+y*2)

... which would automatically add the name of the variables as in the print above.

The problem is I didn’t see a way to do it.

Any idea?

  • 1

    Problem that when passed to the function, the reference to the value changes, also changing the name. For example, you could define the function debug(*args) to receive as many parameters as you need, but the variable becomes args and no more x, y or an expression. To x and y you can work with the value returned by locals(), but as for expression, I don’t know if you can do it; maybe with inspect, would need to analyze it better.

  • i usually do something like print("A",x,y,z,w,p,n); (the A at the beginning is just to know what print is about, in a second I put B, or something that makes sense just to differentiate, because I know what I put inside the print, I don’t need to leave all the strings "cute" (after all is debug right? ). Now, if you need a lot of print all the time, it would be nice to review the methodology.

4 answers

8

You can print a dictionary with all local variables if you do print(locals()) .

Also, if you don’t know, I recommend learning to use the PDB (Python Debuger) - that allows you to interactively track the execution of the program, and Inspecione the value of the variables when you want. In Python 3.7, just put breakpoint() in the middle of the code. In any previous version, the line import pdb; pdb.set_trace()

  • Thank you. The idea would only be to have a simple and quick command to facilitate debugging, since during this process it would not be cool to lose focus by building a series of commands just for debugging. I already use Pycharm, which has excellent debugging. The problem is that to track the evolution of the values at runtime, I have to use print(), because Pycharm’s Debugger shows the values only during a breakpoint. Hence my question, if I had a facilitator, something simple.

4


As commented, an option to display the debug of variables is using the module inspect. With the help of function inspect.stack you can verify the context from which the function was executed and access local and global variables in that context. So, instead of you passing the variable itself to function, you can pass only its name that the function will take charge of accessing the respective value by inspection. For this example I also used the module tabulate for easy and readable formatting of the output.

import inspect
import tabulate


def debug(*args):

    # Busca o contexto de quem chamou a função debug:
    context = inspect.stack()[1][0]

    # Obtém detalhes de onde foi executado o debug:
    filename = context.f_code.co_filename
    linenumber = context.f_lineno

    # Resultados a serem exibidos:
    result = []

    # Percorre todas as variáveis a serem exibidas:
    for name in args:
        # Verifica se é uma variável local no contexto:
        if name in context.f_locals:
            result.append([name, context.f_locals[name]])
        # Verifica se é uma variável global no contexto:
        elif name in context.f_globals:
            result.append([name, context.f_globals[name]])
        # Variável não encontrada no contexto:
        else:
            result.append([name, 'Não encontrada'])

    # Exibe os resultados em forma de tabela:
    print(f'[DEBUG] {filename} ({linenumber})')
    print(tabulate.tabulate(result, headers=['Variável', 'Valor']))

An example of use would be:

>>> x, y, nome = 1, 2, 'Anderson Carlos Woss'
>>> debug('x', 'y', 'nome', 'foo')
[DEBUG] python (34)
Variável    Valor
----------  --------------------
x           1
y           2
nome        Anderson Carlos Woss
foo         Não encontrada

See working on Repl.it

Call example within a function

Making the debug of a local and global variable:

autor = "Anderson Carlos Woss"


def hello(nome):
    debug('nome', 'autor')
    print(f'Olá, {nome} (por {autor})')


hello('John Doe')

See working on Repl.it

The exit will be:

[DEBUG] python (37)
Variável    Valor
----------  --------------------
nome        John Doe
autor       Anderson Carlos Woss

Olá, John Doe (por Anderson Carlos Woss)

But for expression, such as doing x+y*2 the function will not work. It is possible to implement the function for this, but I believe it will be unviable. It will be much simpler for you to assign the expression to another variable and pass it to the function. For example:

>>> x, y = 1, 2
>>> x_plus_2y = x + 2*y
>>> debug('x', 'y', 'x_plus_2y')

Displaying:

[DEBUG] python (38)
Variável      Valor
----------  -------
x                 1
y                 2
x_plus_2y         5
  • Great. This should turn into a new native Python command! Thank you.

  • 1

    @Rogériodec There is not much need since you can very well define this function and use in your projects. Incidentally, I incremented the code by adding the file name and line number where the function debug was called, to facilitate if you have multiple outputs of these. In the examples the file name was as python just because of the structure of Repl.it.

0

Use eval is the solution.

Here’s my new job debug, which is simple. You just need to put the variable names in a string list:

 def debug (vars):
     for var in vars:
         print (var, "=", eval (var))

Example:

 t = "algum texto"
 n = 3.1416
 debug (['t', 'n'])

Upshot:

 t = algum texto
 n = 3.1416
  • 1

    The debug function thus only has access to global variables, or, places if it is defined within of the function where you are using debug. In order to call this function "debug" or a similar one, you can pass the return of locals(), and then print the keys that matter: def debug(variables, var_names): print([(var_name, variables[var_name]) for var_name in var_names), and then call with debug(locals(), ['t', 'n'])

0

They’re inside the module logging:

import logging
from random import randint

logging.basicConfig(level=logging.DEBUG)

logging.info('Iniciando o programa')

for i in range(0, 5):
    x = randint(0, 100)
    y = randint(0, 100)
    z = y if y > 100 else x
    logging.debug('x={}, y={}, z={}'.format(x,y,z))

logging.info('Finalizando o programa')

And the result would be something like this:

INFO:root:Iniciando o programa DEBUG:root:x=68, y=59, z=68 DEBUG:root:x=65, y=38, z=65 DEBUG:root:x=97, y=64, z=97 DEBUG:root:x=15, y=26, z=15 DEBUG:root:x=29, y=13, z=29 INFO:root:Finalizando o programa

Of course, they are sent to STDERR but you can direct to a file as well as customize what is displayed in the message and also set the level of record (using level=logging.INFO only the first and last messages would be displayed) when knowing the value of the variables is no longer necessary. :-)

  • 1

    Good to know. But the idea was to leave the process less laborious and with this solution becomes even more laborious than typing the names one by one within the print...

Browser other questions tagged

You are not signed in. Login or sign up in order to post.