查找标识符的等效字符串(如源代码所示)?

时间:2017-11-03 08:16:25

标签: python python-3.x

警告: 这个问题在措辞上看似简单,但可能需要额外的智力来回答它。尝试采用How can I get the name of an object in Python?中的方法并不是一个有效的答案(您可能需要先阅读它)。根据定义,通过对象的这种方法是不明确的,因为任何对象都可以被几个名称引用,甚至没有。建议的方法需要回到解析步骤,其中对象尚未存在。

背景:我正在探索如何在Python中创建允许我们取消一些冗余的构造,例如:在进行单元测试时:

y = 5
print("%s: %s" % ('y', y))

最好写一下:

y = 5    
print(info(y)) => "Value of 'y' is 5"

注意:这可以通过传递一个字符串然后将其转换为id来反过来解决,例如, print(info('y')使用globals()['y']之类的内容。但是在这里我们想要从转到字符串,因为在某些情况下,这样做更简单,例如当测试例程传递一个要检查的变量列表时。

问题:如果在源代码中给出一个名为x的标识符,是否可以编写一个symbol函数来返回与x对应的字​​符串?< / p>

语义上,如果我写

x = [1, 2, 3, 4] # whatever object

从源代码中可以明显看出x是字符串'x'。

换句话说,是否有可能(在标准Python中)编写一个符号函数(仅用于输入名称),给定x,将其视为符号的确切位置调用函数,并返回字符串'x'?

x = [1, 2, 3, 4] # whatever object
y = x
symbol(x) = 'x'
symbol(y) = 'y'

答案是明确的:调用函数时,x和y在源代码中用作符号,因此符号的结果必须是字符串等效于符号(分别为'x'和'y')。

我意识到这可能是一个很好的二度内省工作(在源代码(AST?)中找到函数被调用的地方然后用它来推理)。然而,它可以用今天存在的Python来完成吗?

因此,如果提议的符号函数有效,则应该能够编写(通常用于单元测试):

   x = 5
   y = x
   print("The value of %s is %s", symbol(x), x) => 5
   print("The value of %s is %s", symbol(y), y) => 5

然后info函数可以写成:

def info(y):
    return("%s: %s" % (symbol(y), y))

注1:为了一般性,解决方案应该在标准Python中工作,但其他实现的答案也是可以接受的。

注2:如果您认为“符号”不是此功能或概念的正确名称,欢迎您指出。

注3:这是一个确切的问题:假设在代码中使用符号Y,则写一个符号函数,它给出符号(Y)='Y',而不管其中的对象是什么符号指向(类,对象等)。

2 个答案:

答案 0 :(得分:2)

这可以通过阅读调用symbol函数的源代码来完成:

import inspect
import re

def symbol(arg):
    frame = inspect.currentframe().f_back
    frameinfo = inspect.getouterframes(frame)[0]
    calling_code = frameinfo[4][frameinfo[5]].strip()
    del frame

    # this adds support for multiple calls in the same line
    matches = re.findall(r'\bsymbol\((\w+)\)', calling_code)
    match = matches[symbol.call_count]
    symbol.call_count += 1
    if symbol.call_count == len(matches):
        symbol.call_count = 0
    return match

symbol.call_count = 0
x = 3
print(symbol(x)) # output: x

注意事项:

  • 在交互式会话或无法读取源代码的任何其他场景中不起作用
  • 可以通过字符串绊倒:

    fake = "symbol(fake)"; print(symbol(5))
    # output: fake
    

答案 1 :(得分:0)

我不确定问题是否正确,但这是一个在[Python]: globals()中搜索符号的示例:

import sys

x = [1, 2, 33]


def dummy():
    pass


def symbol(obj):
    globals_dict = globals()
    for name in globals_dict:
        if obj is globals_dict[name]:
            return name


def main():
    for obj in [sys, x, dummy, symbol, main]:
        obj_name = symbol(obj)
        print(obj_name, type(obj_name))


if __name__ == "__main__":
    main()

<强>输出

E:\Work\Dev\StackOverflow\q47091183>"E:\WinOBT\1.0.0.0\OPSWpython\2.7.10__00\x86\python.exe" a.py
('sys', <type 'str'>)
('x', <type 'str'>)
('dummy', <type 'str'>)
('symbol', <type 'str'>)
('main', <type 'str'>)