简体   繁体   English

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

[英]Print name and value of Python function arguments

I want to make a debug_print() which would output the callers variable and value, and later on I would extend this to only partially print lists and dicts and so on. 我想创建一个debug_print()来输出调用者的变量和值,稍后我会将它扩展为仅部分打印列表和dicts等等。 This post focuses only on the first part of printing callers variables and values. 本文仅关注打印调用者变量和值的第一部分。

This post has the following parts: 这篇文章有以下几个部分:

  • Current version of debug_print 当前版本的debug_print
  • Constructed test cases 构建测试用例
  • Output of test cases 输出测试用例
  • My wanted output, and problem areas 我想要的输出和问题区域
  • List of somewhat related questions 有些相关问题的清单

Sorry, for a somewhat lengthy post, but I just want to show I've done some research, and really would like some help to get some assistance on how to solve my issues (as listed in second to last section). 对不起,对于一个有点冗长的帖子,但我只是想表明我做了一些研究,并且真的希望得到一些帮助来获得一些帮助来解决我的问题(如第二部分所列)。

Current version of 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))

Constructed test cases 构建测试用例

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

Output of test cases 输出测试用例

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)

Wanted output, and problem areas 想要输出和问题领域

I would love for something like the following to be output: 我希望输出以下内容:

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]

I do however see from related issues that this is maybe setting the bar a little high. 然而,我确实从相关问题中看到,这可能会使条形设置得有点高。 But the closer I get, the better it would be. 但我越接近,它就越好。

Ideally I could loop through some dict which the original argument code as key, but I would also be most satisfied with a way to extract the true argument code from the code_context and then combine these with the actual args. 理想情况下,我可以遍历一些原始参数代码作为键的dict,但我也最满意的方法是从code_context中提取真正的参数代码,然后将它们与实际的args相结合。

However I can not simply split the code context on , as that might also be a part of lists, dict's or tuples. 但是我不能简单地拆分代码上下文,因为它也可能是列表,字典或元组的一部分。 If some python parser could be used to split the code context, this might be an alternate route to explore. 如果可以使用某些python解析器来拆分代码上下文,那么这可能是一种可供探索的替代路径。 But I would like to avoid using eval . 但我想避免使用eval

So far my search has not revealed any place where I can get the functions actually argument list with both code and values. 到目前为止,我的搜索没有透露任何我可以获得函数实际参数列表的地方,包括代码和值。 (Have seen references to f_globals or func_globals but they list everything available to the module, and I found no way to reconnect these to a variable arguemnt list). (已经看过对f_globalsfunc_globals引用,但它们列出了模块可用的所有内容,我发现没有办法将它们重新连接到变量arguemnt列表)。

On a sidenote: I know it is possible to use variations over debug_print(**kwargs) and then having statements like debug_print(a=a, b=b; c=c; sum=b+2) , but it would be even better to avoid that duplication when writing the debug statements. 在旁注:我知道可以使用变量而不是debug_print(**kwargs) ,然后使用像debug_print(a=a, b=b; c=c; sum=b+2)这样的语句,但它会是均匀的编写调试语句时最好避免重复。

List of somewhat related issues 有些相关问题的清单

There has been questions in the past related to similar issues, but whilst most of them deal with fixed arguments, or just displaying names, I would like to show both name and value, if available. 过去一直存在与类似问题相关的问题,但是虽然大多数问题涉及固定参数,或者只是显示名称,但我想显示名称和值,如果可用的话。 Or alternatively a guide to parsing the code context to match the arguments given. 或者是解析代码上下文以匹配给定参数的指南。 But here goes some of the related questions: 但是这里有一些相关的问题:

I'm not sure that any syntax can be better than what you already got, but: 我不确定任何语法可能比你已经获得的更好,但是:

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

Gives: 得到:

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)

Still, I prefer the repr builtin over my pprint function: 不过,我更喜欢内置于我的pprint函数的repr

  • pprint([1, 'a'])

Gives list<int>(1, 'a') which is obviously wrong, and we can't do better, do you really want list<int or string> ? list<int>(1, 'a')这显然是错误的,我们不能做得更好,你真的想要list<int or string>吗?

repr gives [1, 'a'] which is readable and correct. repr给出[1, 'a']这是可读和正确的。

  • pprint(1.3)

Gives <float>(1.3) , like I can't see that 1.3 is a float ? 给出<float>(1.3) ,就像我看不到1.3是浮点数一样? repr gives 1.3 , which is clearly enough. repr给出1.3 ,这显然已经足够了。

  • ... ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM