簡體   English   中英

Python:打印變量的名稱和值?

[英]Python: Print a variable's name and value?

在調試的時候,我們經常會看到這樣的打印語句:

print x        # easy to type, but no context
print 'x=',x   # more context, harder to type
12
x= 12

如何編寫一個 function 來獲取變量或變量名稱並打印其名稱和值? 我只對調試 output 感興趣,這不會合並到生產代碼中。

debugPrint(x)    #  or
debugPrint('x')
x=12

Python 3.8 f-string =語法

它已經到了!

#!/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``.

所以它也適用於任意表達式。 好的!

你可以只使用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

例如使用 Python3.8 中最新的f'{var = }'特性:

>>> a = 'hello'
>>> print(f'{a = }')
a = 'hello'
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:

檢查當前幀()

CPython 實現細節:此函數依賴於解釋器中的 Python 堆棧幀支持,不能保證在 Python 的所有實現中都存在。 如果在沒有 Python 堆棧框架支持的實現中運行,則此函數返回 None。

我寫了以下內容以便能夠輸入類似的內容(在文件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

對於那些還沒有使用 python 3.8 的人,這里有一個替代方案。

這是此處找到的一個已關閉的 2009 年重復問題的已接受答案的修改后的較短版本(在 15 年 8 月 14 日下面也被錯誤復制,錯誤是 re 包含硬編碼的函數名稱“varname” ' 而不是顯示的函數名稱 'getm')。 原文在這里: How can you print a variable name in python? ?

為了解釋下面的 re,inspect.getframeinfo(inspect.currentframe(), f_back)[3] 給出了列表中的函數簽名

['                p(prev)\n']

強制轉換為 str 使您不必循環遍歷一個項目的列表。 re 尋找一個 '(' 必須被轉義,下一個 '(' 是在匹配中創建一個組來引用,然后 [^)] 表示任何不是 ')' 的字符,'^' 表示'不是' 在這種情況下,方括號 [] 表示匹配其中的任何字符,后面的 '*' 是 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. build 5666) (dot 3)] 在達爾文

剛剛開發了@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

我在 jupyterlab 中這樣做是為了像變量打印一樣獲得 matlab:

def debug(var):
    stack = traceback.extract_stack()
    filename, lineno, function_name, name = stack[-2]
    print(name[6:-1] , ':' , var)

用法:

x=1
debug(x)

產量:

x : 1

實際上,為了輸入 output 格式的方便和簡潔,我使用的確切代碼是:

import traceback
def p(var):
    stack = traceback.extract_stack()
    filename, lineno, function_name, name = stack[-2]
    print( "{:<25}".format(name[2:-1]) ,  ':   ' , var)

相當丑陋,但工作:

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))

一個簡單的例子是:

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))

希望能幫助到你!

我剛剛編造了一個像這樣打印任意表達式的函數:

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模塊感興趣。 它以人類可讀的形式打印所有對象的字段。 證明對調試非常有用。

多個變量(將@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])

當從變量的值中找到變量的名稱時,
您可能有多個變量等於相同的值,
例如 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']]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM