打印 Python 函数参数的名称和值 [英] Print name and value of Python function arguments

查看:170
本文介绍了打印 Python 函数参数的名称和值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想制作一个 debug_print() 来输出调用者的变量和值,稍后我会将其扩展为仅部分打印列表和字典等.这篇文章只关注打印调用者变量和值的第一部分.

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. This post focuses only on the first part of printing callers variables and values.

这篇文章有以下几个部分:

This post has the following parts:

  • debug_print 的当前版本
  • 构建测试用例
  • 测试用例输出
  • 我想要的输出和问题区域
  • 有些相关的问题列表

抱歉,这篇文章有点长,但我只是想表明我已经做了一些研究,并且真的很想获得一些帮助,以获取有关如何解决我的问题的一些帮助(如倒数第二部分所列).

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

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)

想要的输出和问题区域

我希望输出如下内容:

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.

理想情况下,我可以遍历一些原始参数代码的字典作为关键,但我也最满意的是从 code_context 中提取真正的参数代码,然后将它们与实际参数结合起来.

然而,我不能简单地分割 , 上的代码上下文,因为它也可能是列表、字典或元组的一部分.如果某些 Python 解析器可用于拆分代码上下文,这可能是另一种探索途径.但我想避免使用 eval.

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. But I would like to avoid using eval.

到目前为止,我的搜索还没有发现任何可以获取函数实际参数列表以及代码和值的地方.(看过对 f_globalsfunc_globals 的引用,但它们列出了模块可用的所有内容,我发现无法将它们重新连接到变量 argumentmnt 列表).

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

旁注:我知道可以对 debug_print(**kwargs) 使用变体,然后使用像 debug_print(a=a,b=b; c=c; sum=b+2),但最好在编写调试语句时避免重复.

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.

过去曾出现过与类似问题相关的问题,但尽管其中大多数都涉及固定参数,或者只是显示名称,但我想同时显示名称和值(如果有).或者,一份解析代码上下文以匹配给定参数的指南.但这里有一些相关的问题:

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

给出:

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 函数:

Still, I prefer the repr builtin over my pprint function:

  • pprint([1, 'a'])

给出list(1, 'a')显然是错误的,我们不能做得更好,你真的要list代码> ?

Gives list<int>(1, 'a') which is obviously wrong, and we can't do better, do you really want list<int or string> ?

repr 给出了可读且正确的 [1, 'a'].

repr gives [1, 'a'] which is readable and correct.

  • pprint(1.3)

给出 (1.3),就像我看不到 1.3 是一个浮点数?repr 给出了 1.3 ,这已经足够了.

Gives <float>(1.3), like I can't see that 1.3 is a float ? repr gives 1.3, which is clearly enough.

  • ...

这篇关于打印 Python 函数参数的名称和值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆