Python调试技术之变量名称获取 郝伟 2021/03/29 [TOC]

1. 问题

这样的代码相信大家都很常用:

a, b = 10, 20
print('a=', a)
print('b=', a)

其作用是在输出时显示变量a的名称,我们可否简化成:

a, b = 10, 20
show(a)
show(b)

然后显示同样的内容呢?

2. 示例及输出效果

以下代码定义了一个变量并进行调用输出:

s1 = pandas.DataFrame([1, 2, 3], list('abc'))
show(s1.index)

输出:

s1.index = Index(['a', 'b', 'c'], dtype='object')

可见,show函数能够获得输入变量的名称,并自动输出,达到了我们预期的目标。

3. 全代码

代码中实际上共提供了三种方法,只有最后一种最完善。 解释都放在代码中了,不再细表。

import matplotlib.pyplot as plt
import pandas as pd
import re
import traceback
import inspect

pattren = re.compile(r'[\W+\w+]*?get_variable_name\((\w+)\)')
__get_variable_name__ = []
def get_variable_name(x):
    global __get_variable_name__
    if not __get_variable_name__:
        __get_variable_name__ = pattren.findall(traceback.extract_stack(limit=2)[0][3])
    return __get_variable_name__.pop(0)


def retrieve_variable_name(var):
        """
        获得变量var的名称,这个名称是最开始定义时的名称。
        获取原理是利用变量存储栈。
        如果获取失败则返回长度为0的字符串。
        :参数 var: 待获得名称的变量。
        :返回类型: 字符串
        """
        for fi in reversed(inspect.stack()):
            names = [var_name for var_name, var_val in fi.frame.f_locals.items() if var_val is var]
            if len(names) > 0:
                return names[0]
        return ''


def test0():
    print('hello')
    plt.plot([1,2, 3], [4,5,6])
    plt.plot(range(100), 
    [i * i for i in range(100)])
    plt.plot(1,2)
    plt.show()

# 反射有四个方法:hasattr、getattr、setattr、delattr,比较常用的是前两种,一般会结合起来用。
def show(obj1, prop_name):
    # print('name:', get_variable_name(obj1))
    # print('name:', retrieve_variable_name(obj1))
    title=retrieve_variable_name(obj1)+'.'+prop_name+':'
    if hasattr(obj1, prop_name):
        v = getattr(obj1, prop_name)
        print(title, v)
    else:
        print(title)

s1 = pd.DataFrame([1, 2, 3], list('abc'))
print(s1.index)
print(getattr(s1, 'index'))
show(s1, 'index')

# print('s1:', get_variable_name(s1))

print('sig:', inspect.signature(retrieve_variable_name))

print('1:', retrieve_variable_name(s1.index))
#print('2:', retrieve_variable_name(s1.index))


# ★★★★ 真正可用的代码 ★★★★
# 参考: http://blog.csdn.net/chunyexiyu
def retrieve_name_ex(var):
    '''
    实现的原理是利用inspect获得函数的源代码,从而取得变量的字符串。
    '''
    stacks = inspect.stack()
    try:
        code = stacks[2].code_context[0]   # 获得调用行的代码
        callFunc = stacks[1].function      # 获得调用的函数名
        # 获得函数中起始索引位置,以取得变量名称的字符串
        startIndex = code.index("(", code.index(callFunc) + len(callFunc)) + 1
        endIndex = code.index(")", startIndex)
        name=code[startIndex:endIndex].strip() # 获得变量名称
        return name
    except:
        return ""

def show(var):
    print(retrieve_name_ex(var), '=', var)

outputVar(s1.index)

4. 结论

通过本文,我们可以掌握获得一个变量的完整名称的几种方法。在此基础之上,我们可以利用 inspect 库,实现对代码进行过程中的全面监视,从而可以实现更多更强大的能力。

5. 参考资料

Python获取变量名称,https://blog.csdn.net/chunyexiyu/article/details/84879295 Python 中的反射操作,https://zhuanlan.zhihu.com/p/99150129

results matching ""

    No results matching ""