我想创建一个debug_print()
,它将输出调用者的变量和值,然后我将其扩展为仅部分打印列表和字典等。这篇文章只关注打印调用者变量和值的第一部分。
这篇文章有以下几个部分:
-
debug_print
的当前版本 构建的测试用例测试用例输出 - 我想要的输出和问题区域
- 相关问题列表
很抱歉,这篇文章有点长,但我只是想表明我已经做了一些研究,并且真的希望得到一些帮助来解决我的问题(如倒数第二部分所列)。
debug_print
的当前版本
import inspect
def debug_print(*args):
try: # find code_context
# First try to use currentframe() (maybe not available in all implementations)
frame = inspect.currentframe()
if frame:
# Found a frame, so get the info, and strip space from the code_context
code_context = inspect.getframeinfo(frame.f_back).code_context[0].strip()
else:
# No frame, so use stack one level above us, and strip space around
# the 4th element, code_context
code_context = inspect.stack()[1][4][0].strip()
finally:
# Deterministic free references to the frame, to be on the safe side
del frame
print('Code context : {}'.format(code_context))
print('Value of args: {}n'.format(args))
已构建的测试用例
# Test with plain variables
a = 0.2
b = 1.2
c = a + 1
debug_print(a, b, c, b+2)
# Test with list, list of lists, tuples and dict's
debug_print([4.1, 4.2], [[4.00, 4.01], ["4.1.0", '4.1.1']])
debug_print((5.1, 5.2), {6.1: 6.2})
# Test with func's or func aliases
def my_func():
return 7
my_alias_func = my_func
debug_print(my_func, my_alias_func, my_alias_func())
# Test with nested func's and list slices
my_list = [1, 2, 3, 4, 5]
def first_level():
def second_level():
debug_print(my_list[:2], my_list[3:])
second_level()
# Execute
first_level()
# Test with multi-line call
debug_print(a, b,
'multi-line call', c)
测试用例输出
Code context : debug_print(a, b, c, b+2)
Value of args: (0.2, 1.2, 1.2, 3.2)
Code context : debug_print([4.1, 4.2], [[4.00, 4.01], ["4.1.0", '4.1.1']])
Value of args: ([4.1, 4.2], [[4.0, 4.01], ['4.1.0', '4.1.1']])
Code context : debug_print((5.1, 5.2), {6.1: 6.2})
Value of args: ((5.1, 5.2), {6.1: 6.2})
Code context : debug_print(my_func, my_alias_func, my_alias_func())
Value of args: (<function my_func at 0x110393668>, <function my_func at 0x110393668>, 7)
Code context : debug_print(my_list[:2], my_list[3:])
Value of args: ([1, 2], [4, 5])
Code context : 'multi-line call', c)
Value of args: (0.2, 1.2, 'multi-line call', 1.2)
需要的输出和问题区域
我希望输出如下内容:
a: 0.2; b: 1.2; c: 1.2; 3.2
<list>: [4.1, 4.2]; <list of lists>: [[4.0, 4.01], ['4.1.0', '4.1.1']]
<tuple>: (5.1, 5.2); <dict>: {6.1: 6.2}
func: my_func; func: my_alias_func -> my_func; my_func(): 7
my_list[:2]: [1, 2]; my_list[3:]: [4, 5]
然而,我确实从相关问题中看到,这可能把标准定得有点高。但我越靠近,感觉就越好。
理想情况下,我可以遍历一些原始参数编码的字典
然而,我不能简单地分割,
上的代码上下文,因为它也可能是列表,字典或元组的一部分。如果可以使用某些python解析器来拆分代码上下文,那么这可能是一种可供探索的替代途径。但是我想避免使用eval
。
到目前为止,我的搜索还没有发现任何地方,我可以得到函数实际参数列表与代码和值。(已经看到对f_globals
或func_globals
的引用,但它们列出了模块可用的所有内容,我没有办法将这些重新连接到变量参数列表)。
旁注:我知道有可能使用debug_print(**kwargs)
的变体,然后有debug_print(a=a, b=b; c=c; sum=b+2)
这样的语句,但是在编写调试语句时避免重复会更好。
相关问题列表
过去有过与类似问题相关的问题,但是大多数问题处理固定参数,或者只是显示名称,如果可用,我想同时显示名称和值。或者提供解析代码上下文以匹配给定参数的指南。但这里有一些相关的问题:
- 打印Python函数中输入的参数名
- 获取python变量的名称
- 打印变量名
- python获取函数参数的变量名
我不确定是否有任何语法可以比你已经得到的更好,但是:
def pprint(arg):
of = None
if not isinstance(arg, (str, bytes)):
try:
of = type(arg[0]).__name__
except (IndexError, TypeError, KeyError):
of = None
if of is None:
if hasattr(arg, '__name__'):
return '{}({})'.format(type(arg).__name__, arg.__name__)
else:
return '{}({})'.format(type(arg).__name__, repr(arg))
else:
return '{}<{}>{}'.format(type(arg).__name__, of, repr(arg))
def debug_print(*args):
try: # find code_context
# First try to use currentframe() (maybe not available in all implementations)
frame = inspect.currentframe()
if frame:
# Found a frame, so get the info, and strip space from the code_context
code_context = inspect.getframeinfo(frame.f_back).code_context[0].strip()
else:
# No frame, so use stack one level above us, and strip space around
# the 4th element, code_context
code_context = inspect.stack()[1][4][0].strip()
finally:
# Deterministic free references to the frame, to be on the safe side
del frame
print('Code context : {}'.format(code_context))
print('Value of args: {}n'.format('; '.join(pprint(arg) for arg in args)))
给:
Code context : debug_print(a, b, c, b + 2)
Value of args: float(0.2); float(1.2); float(1.2); float(3.2)
Code context : debug_print([4.1, 4.2], [[4.00, 4.01], ["4.1.0", '4.1.1']])
Value of args: list<float>[4.1, 4.2]; list<list>[[4.0, 4.01], ['4.1.0', '4.1.1']]
Code context : debug_print((5.1, 5.2), {6.1: 6.2})
Value of args: tuple<float>(5.1, 5.2); dict({6.1: 6.2})
Code context : debug_print(my_func, my_alias_func, my_alias_func())
Value of args: function(my_func); function(my_func); int(7)
Code context : debug_print(my_list[:2], my_list[3:])
Value of args: list<int>[1, 2]; list<int>[4, 5]
Code context : 'multi-line call', c)
Value of args: float(0.2); float(1.2); str('multi-line call'); float(1.2)
尽管如此,我更喜欢repr
内置的pprint
功能:
-
pprint([1, 'a'])
给出list<int>(1, 'a')
,这显然是错误的,我们不能做得更好,你真的想要list<int or string>
吗?
repr
给出可读且正确的[1, 'a']
。
-
pprint(1.3)
给出<float>(1.3)
,就像我看不到1.3
是浮点数一样?repr
给出1.3
,这已经足够清楚了。
- …