调试时,我们经常会看到如下的打印语句:
print x # easy to type, but no context
print 'x=',x # more context, harder to type
12
x= 12
如何编写一个函数来获取变量或变量名称并打印其名称和值?我只对调试输出感兴趣,这不会被合并到生产代码中。
debugPrint(x) # or
debugPrint('x')
x=12
答案 0 :(得分:17)
您可以使用eval
:
def debug(variable):
print variable, '=', repr(eval(variable))
或者更一般地说(它实际上在调用函数的上下文中工作并且不会在debug('variable')
上中断,但仅在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)))
你可以这样做:
>>> x = 1
>>> debug('x + 1')
x + 1 = 2
答案 1 :(得分:7)
例如使用 Python3.8 中最新的 f'{var = }'
特性:
>>> a = 'hello'
>>> print(f'{a = }')
a = 'hello'
答案 2 :(得分:3)
我写了以下内容,以便能够输入类似的内容(在文件describe.py
的第41行):
describe('foo' + 'bar')
describe(numpy.zeros((2, 4)))
并看到:
describe.py@41 describe('foo' + 'bar') = str(foobar) [len=6]
describe.py@42 describe(numpy.zeros((2, 4))) = ndarray(array([[0., 0., 0., 0.],
[0., 0., 0., 0.]])) [shape=(2, 4)]
以下是:
# Print the line and filename, function call, the class, str representation and some other info
# Inspired by https://stackoverflow.com/a/8856387/5353461
import inspect
import re
def describe(arg):
frame = inspect.currentframe()
callerframeinfo = inspect.getframeinfo(frame.f_back)
try:
context = inspect.getframeinfo(frame.f_back).code_context
caller_lines = ''.join([line.strip() for line in context])
m = re.search(r'describe\s*\((.+?)\)$', caller_lines)
if m:
caller_lines = m.group(1)
position = str(callerframeinfo.filename) + "@" + str(callerframeinfo.lineno)
# Add additional info such as array shape or string length
additional = ''
if hasattr(arg, "shape"):
additional += "[shape={}]".format(arg.shape)
elif hasattr(arg, "__len__"): # shape includes length information
additional += "[len={}]".format(len(arg))
# Use str() representation if it is printable
str_arg = str(arg)
str_arg = str_arg if str_arg.isprintable() else repr(arg)
print(position, "describe(" + caller_lines + ") = ", end='')
print(arg.__class__.__name__ + "(" + str_arg + ")", additional)
else:
print("Describe: couldn't find caller context")
finally:
del frame
del callerframeinfo
https://gist.github.com/HaleTom/125f0c0b0a1fb4fbf4311e6aa763844b
答案 3 :(得分:2)
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))
这对所有版本的python都不起作用:
<强> inspect.currentframe()强>
CPython实现细节: 此函数依赖于解释器中的Python堆栈帧支持,并不保证在Python的所有实现中都存在。如果在没有Python堆栈帧支持的实现中运行,则此函数返回None。
答案 4 :(得分:1)
Python 3.8 f字符串=
语法
已经到了!
#!/usr/bin/env python3
foo = 1
bar = 2
print(f"{foo=} {bar=}")
输出:
foo=1 bar=2
在落实https://github.com/python/cpython/commit/9a4135e939bc223f592045a38e0f927ba170da32中添加了“使用'='添加f字符串调试。”哪些文件:
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``.
因此它也适用于任意表达式。很好!
答案 5 :(得分:1)
刚刚开发了@Padraic Cunningham 的答案以采用任意数量的变量。我喜欢这种方法,因为它就像 print(x1, x2, x3)
一样工作 - 无需在 ''
中包装 var 名称。
import inspect
import re
def prinfo(*args):
frame = inspect.currentframe().f_back
s = inspect.getframeinfo(frame).code_context[0]
r = re.search(r"\((.*)\)", s).group(1)
vnames = r.split(", ")
for i,(var,val) in enumerate(zip(vnames, args)):
print(f"{var} = {val}")
x1 = 1
x2 = 2
x3 = 3
prinfo(x1, x2, x3)
输出为:
x1 = 1
x2 = 2
x3 = 3
答案 6 :(得分:0)
一个简单的例子是:
def debugPrint(*expr):
text = traceback.extract_stack()[-2][3]
begin = text.find('debugPrint(') + len('debugPrint(')
end = text.find(')',begin)
text=[name.strip() for name in text[begin:end].split(',')]
for t, e in text, expr:
print(str(t) + " = " + str(e))
希望有帮助!
答案 7 :(得分:0)
我刚刚炮制了这样的函数,该函数可以打印任意表达式:
import inspect, pprint
def pp(n):
print()
print(n,"=")
f=inspect.stack()[1].frame
pprint.pprint(eval(n,f.f_globals,f.f_locals))
(在我的情况下,我在名称前使用空白行,在值'cuz之前使用换行符,我需要打印大型数据结构。使用换行符更容易读取此类输出。)
只要您不传递不受信任的输入,它都是安全的。
您可能也对我的dump
模块感兴趣。它以人类可读的形式打印对象的所有字段。被证明对调试非常有用。
答案 8 :(得分:0)
对@Blender响应采取进一步的措施,其中包含多个变量:
def debug(variables, sep =''):
vars = variables.split(',')
for var in vars:
print(var, '=', repr(eval(var)), end = sep)
示例:
import bumpy as np
gPrimeLinear = lambda z: np.ones(np.array(z).size)*z
gPrimeSigmoid = lambda z: 1./(1+np.exp(-z))*(1-1./(1+np.exp(-z)))
gPrimeTanh = lambda z: 1- np.tanh(z)**2
z = np.array([ 0.2, 0.4, 0.1])
debug("z, gPrimeLinear(z), gPrimeSigmoid(z), gPrimeTanh(z)", '\n')
这将返回:
> z = array([0.2, 0.4, 0.1])
> gPrimeLinear(z) = array([0.2, 0.4, 0.1])
> gPrimeSigmoid(z) = array([0.24751657, 0.24026075, 0.24937604])
> gPrimeTanh(z) = array([0.96104298, 0.85563879, 0.99006629])
答案 9 :(得分:0)
对于尚未使用python 3.8的用户,这是替代方法。
这是从此处找到的2009年一个封闭重复问题的已接受答案的修改后的简短版本(该错误也在15年8月14日的以下错误中被复制,该错误是re包含硬编码函数名称'varname'而不是显示为'getm'的函数名称)。原始文件在这里找到: How can you print a variable name in python??
为了解释下面的内容,inspect.getframeinfo(inspect.currentframe(),f_back)[3]在列表中给出了函数签名
[' p(prev)\n']
强制转换为str可以使您不必遍历一项的列表。 re查找将要转义的'(',下一个'('将在要匹配的引用中创建一个组,然后[^)]表示不是')'的任何字符,'^'表示'not在此情况下,方括号[]表示与其中的任何字符匹配,并且后面的'*'是0次或多次的量词。然后以')'结束群组,匹配结尾的')'并瞧:
def p(x):
import inspect
import re
m = re.search('\(([^)]*)\)',str(inspect.getframeinfo(inspect.currentframe().f_back)[3]))
print(f' {m.group(1)}: {x}')
此功能在2.7上有效吗?我检查时在这里等待...不,似乎没有。我确实看到了另外一两个不使用inspect.getframeinfo(inspect.currentframe()。f_back)[3]的变体,所以也许其中一种会起作用。您必须检查重复项并梳理答案。 同样要注意的是,有些答案要当心可能与各种解决方案不兼容的python解释器。上面的工作
Python 3.6.4(v3.6.4:d48ecebad5,2017年12月18日,21:07:28)
达尔文上的[GCC 4.2.1(Apple Inc.内部版本5666)(第3点)]
答案 10 :(得分:0)
当从变量的值中找到变量的名称时,
您可能有多个变量等于相同的值,
例如 var1 = 'hello' 和 var2 = 'hello'。
我对您问题的解决方案:
def find_var_name(val):
dict_list = []
global_dict = dict(globals())
for k, v in global_dict.items():
dict_list.append([k, v])
return [item for item in dict_list if item[1] == val]
var1 = 'hello'
var2 = 'hello'
find_var_name('hello')
输出
[['var1', 'hello'], ['var1', 'hello']]