Python: печатать имя и значение переменной?
При отладке мы часто видим инструкции печати, подобные этим:
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
Ответы
Ответ 1
Вы можете просто использовать 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
Ответ 2
Синтаксис F-строки =
Python 3.8
Это прибыло!
#!/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''.
так что это также работает для произвольных выражений. Приятно!
Ответ 3
Я написал следующее, чтобы можно было напечатать что-то вроде (в строке 41 файла describe.py
):
describe('foo' + 'bar')
describe(numpy.zeros((2, 4)))
и посмотри:
[email protected] describe('foo' + 'bar') = str(foobar) [len=6]
[email protected] 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
Ответ 4
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.
Ответ 5
Довольно уродливый, но выполняет задание:
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))
Ответ 6
Простой пример:
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
Я только что создал такую функцию, которая печатает произвольное выражение:
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
модуль. Он печатает все поля объекта в удобочитаемой форме. Оказалось чрезвычайно полезным для отладки.