Python:打印变量的名称和值?

时间:2015-08-14 01:22:08

标签: python debugging

调试时,我们经常会看到如下的打印语句:

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

11 个答案:

答案 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']]