打印Python函数参数的名称和值



我想创建一个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_globalsfunc_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,这已经足够清楚了。

相关内容

  • 没有找到相关文章

最新更新