15

I am looking for a way to quickly print a variable name and value while rapidly developing/debugging a small Python script on a Unix command line/ssh session.

It seems like a very common requirement and it seems wasteful (on keystrokes and time/energy) to duplicate the variable_names on every line which prints or logs its value. i.e. rather than

print 'my_variable_name:', my_variable_name

I want to be able to do the following for str, int, list, dict:

log(my_variable_name)
log(i)
log(my_string)
log(my_list)

and get the following output:

my_variable_name:some string
i:10
my_string:a string of words
my_list:[1, 2, 3]

Ideally the output would also log the function name.

I have seen some solutions attempting to use locals, globals, frames etc., But I have not yet seen something that works for ints, strings, lists, and works inside functions too.

Thanks!

Sean
  • 200
  • 1
  • 9
  • 1
    Sounds like a macro... – Willem Van Onsem Oct 11 '13 at 12:12
  • why not using pdb : http://docs.python.org/2/library/pdb.html ? – lucasg Oct 11 '13 at 12:18
  • 2
    Evil hacks: http://stackoverflow.com/questions/932818/retrieving-a-variables-name-in-python-at-runtime, http://stackoverflow.com/questions/2553354/how-to-get-a-variable-name-as-a-string-in-python – doctorlove Oct 11 '13 at 12:32
  • 1
    Any good text editor should be able to define some sort of macro for generating a simple `print >>sys.stderr, "var={0}".format(var)` (or the logging construct of your choice. – chepner Oct 11 '13 at 13:04
  • Thank you for the macro and pdb suggestions. A macro might be the simplest answer. Re pdb for the small scripts I am running I find it easier to execute the program and have it automatically report it's values. Rather than repeatedly stepping and querying them in pdb. – Sean Oct 13 '13 at 12:10
  • Thank you for the evil hacks here, and below in the answers. – Sean Oct 13 '13 at 12:42
  • I have implemented a vim macro bdwaprint '^[pa:{}:'.format(^[pa)^[ – Sean Oct 18 '13 at 11:21

4 Answers4

11

Sorry to Necro this ancient thread, but this was surprisingly difficult to find a good answer for.

Using the '=' sign after the variable achieves this. For instance:

import pathlib as pl
import logging

logging.basicConfig(level=logging.DEBUG)

data_root = pl.Path("D:\Code_Data_Dev\Data\CSV_Workspace_Data")

logging.debug(f'{data_root=}')

This outputs

DEBUG:root:data_root=WindowsPath('D:/Code_Data_Dev/Data/CSV_Workspace_Data')
ShazaMcgowan
  • 111
  • 1
  • 4
  • 3
    This is available starting in python 3.8: https://docs.python.org/3/reference/lexical_analysis.html#f-strings – Gus Aug 18 '22 at 22:32
  • This is a great answer, but unfortunately I get a `pylint(logging-fstring-interpolation)` . – Wtower Dec 13 '22 at 10:56
7

If the tool you need is only for developing and debugging, there's a useful package called q.

It has been submitted to pypi, it can be installed with pip install q or easy_install q.

import q; q(foo)

# use @q to trace a function's arguments and return value
@q
def bar():
   ...

# to start an interactive console at any point in your code:
q.d()

The results are output to the file /tmp/q (or any customized paths) by default, so they won't be mixed with stdout and normal logs. You can check the output with tail -f /tmp/q. The output is highlighted with different colors.

The author introduced his library in a lightning talk of PyconUS 2013. The video is here, begins at 25:15.

nonimportant
  • 406
  • 4
  • 15
Leonardo.Z
  • 9,425
  • 3
  • 35
  • 38
  • 1
    Excellent tool. I will certainly use that in the future, thank you for pointing that out. Personally I would prefer to be able to send the output to stdout, but maybe there is an option in q for that. – Sean Oct 13 '13 at 12:38
  • @Sean I too would like to send a variable's name and value to stdout. Did you find a way? – Johnny Utahh Apr 06 '15 at 20:36
4

Here is another evil hack:

import inspect

def log(a):
    call_line = inspect.stack()[1][4][0].strip()
    assert call_line.strip().startswith("log(")
    call_line = call_line[len("log("):][:-1]
    print "Log: %s = %s" % (call_line, a)

b=3
log(b)

This obviously would need some range checks, better parsing, etc. Also works only if the calls is made always in the same way and has probably more - unknown to me - assumptions...

dornhege
  • 1,500
  • 8
  • 8
0

I don't know any way to simply get the name of a variable of a string. you can however get the list of argument of the current fonction log.

import inspect

def log(a):
    frame = inspect.currentframe()
    args, _, _, values = inspect.getargvalues(frame)
    print "%s:%s" % (args[0], values[args[0]])
log0
  • 10,489
  • 4
  • 28
  • 62