When debugging, we often see print statements like these:
print x # easy to type, but no context
print \'x=\',x # more context, harder to type
12
x=
Quite ugly , but does the job :
import inspect, re
def getm(p):
for line in inspect.getframeinfo(inspect.currentframe().f_back)[3]:
match = re.search(r'\bvarname\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)', line)
if match:
return match.group(1)
x=21
search = getm(x);
print (search , '=' , eval(search))
I've just concocted a function like this that prints an arbitrary expression:
import inspect, pprint
def pp(n):
print()
print(n,"=")
f=inspect.stack()[1].frame
pprint.pprint(eval(n,f.f_globals,f.f_locals))
(I used a blank line before the name and a newline before the value 'cuz in my case, I needed to print large data structures. It's easier to read such an output with the line breaks.)
It's safe as long as you don't pass it untrusted input.
You might also be interested in my dump module. It prints all the object's fields in a human-readable form. Proved extremely useful for debugging.
You can just use eval
:
def debug(variable):
print variable, '=', repr(eval(variable))
Or more generally (which actually works in the context of the calling function and doesn't break on debug('variable')
, but only on CPython):
from __future__ import print_function
import sys
def debug(expression):
frame = sys._getframe(1)
print(expression, '=', repr(eval(expression, frame.f_globals, frame.f_locals)))
And you can do:
>>> x = 1
>>> debug('x + 1')
x + 1 = 2
For those who are not using python 3.8 yet, here is an alternative.
This is a modified, shorter version of the accepted answer from a closed 2009 duplicate question found here, (which was also copied with a mistake in the below Aug 14, '15, the mistake being the re contains the hard coded function name 'varname' instead of the function name shown 'getm'). Original found here: How can you print a variable name in python??
To explain the re below, the inspect.getframeinfo(inspect.currentframe(), f_back)[3] gives the function signature in a list
[' p(prev)\n']
Casting to str saves you from having to loop through the list of one item. The re looks for an '(' which has to be escaped, the next '(' is to create a group within the match to reference, then [^)] means any character not ')', the '^' means 'not' in this context, brackets [] mean match any character within, and the following '*' is a quantifier for 0 or more times. Then close the group with a ')', match the closing ')' and voila:
def p(x):
import inspect
import re
m = re.search('\(([^)]*)\)',str(inspect.getframeinfo(inspect.currentframe().f_back)[3]))
print(f' {m.group(1)}: {x}')
Does this work with 2.7? Wait here while I check ... No, seemingly not. I did see one or two other variations that didn't use inspect.getframeinfo(inspect.currentframe().f_back)[3], so perhaps one of those would work. You'd have to check the duplicates and comb through the answers. Also to caution, some answers said to beware of python interpreters that may not be compatible with various solutions. The above worked on
Python 3.6.4 (v3.6.4:d48ecebad5, Dec 18 2017, 21:07:28)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
import inspect
import re
def debugPrint(x):
frame = inspect.currentframe().f_back
s = inspect.getframeinfo(frame).code_context[0]
r = re.search(r"\((.*)\)", s).group(1)
print("{} = {}".format(r,x))
This won't work for all versions of python:
inspect.currentframe()
CPython implementation detail: This function relies on Python stack frame support in the interpreter, which isn’t guaranteed to exist in all implementations of Python. If running in an implementation without Python stack frame support this function returns None.
Python 3.8 f-string =
syntax
It has arrived!
#!/usr/bin/env python3
foo = 1
bar = 2
print(f"{foo=} {bar=}")
output:
foo=1 bar=2
Added in commit https://github.com/python/cpython/commit/9a4135e939bc223f592045a38e0f927ba170da32 "Add f-string debugging using '='." which documents:
f-strings now support = for quick and easy debugging
-----------------------------------------------------
Add ``=`` specifier to f-strings. ``f'{expr=}'`` expands
to the text of the expression, an equal sign, then the repr of the
evaluated expression. So::
x = 3
print(f'{x*9 + 15=}')
Would print ``x*9 + 15=42``.
so it also works for arbitrary expressions. Nice!