Python 查找标识符';s字符串等价物(如源代码所示)?

Python 查找标识符';s字符串等价物(如源代码所示)?,python,python-3.x,Python,Python 3.x,注意:这个问题的措辞看似简单,但可能需要额外的智力努力才能回答。尝试采用中的方法不是有效的答案(您可能需要先阅读)。从定义上讲,通过对象的方法是不明确的,因为任何对象都可能被几个名称引用,甚至一个都没有。推荐的方法要求返回到解析步骤,在该步骤中,对象还不存在 背景:我正在探索如何在Python中创建结构,以消除一些冗余,例如在进行单元测试时: y = 5 print("%s: %s" % ('y', y)) 最好写下: y = 5 print(info(y)) => "Value

注意:这个问题的措辞看似简单,但可能需要额外的智力努力才能回答。尝试采用中的方法不是有效的答案(您可能需要先阅读)。从定义上讲,通过对象的方法是不明确的,因为任何对象都可能被几个名称引用,甚至一个都没有。推荐的方法要求返回到解析步骤,在该步骤中,对象还不存在

背景:我正在探索如何在Python中创建结构,以消除一些冗余,例如在进行单元测试时:

y = 5
print("%s: %s" % ('y', y))
最好写下:

y = 5    
print(info(y)) => "Value of 'y' is 5"
注意:这可以通过另一种方式解决,方法是传递一个字符串,然后将其转换为id,例如使用
globals()['y']
。但是这里我们想从id到字符串,因为在有些情况下,这样做更简单,例如,当一个测试例程被传递一个要检查的变量列表时

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

从语义上来说,如果我写

x = [1, 2, 3, 4] # whatever object
从源代码中可以明显看出,x是字符串“x”

换句话说,是否可以(在标准Python中)编写一个symbol函数(只是为了创造一个名称),该函数给定x,在调用函数的确切位置将其视为符号,并返回字符串“x”

x = [1, 2, 3, 4] # whatever object
y = x
symbol(x) = 'x'
symbol(y) = 'y'
答案是明确的:调用函数时,在源代码中将x和y用作符号,因此符号的结果必须是与符号等价的字符串(分别为“x”和“y”)

我意识到这可能是一项很好的二级内省工作(在源代码(AST?)中找到调用函数的位置,然后对其进行推理)。然而,它可以用Python完成吗

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

然后
info
函数可以写成:

def info(y):
    return("%s: %s" % (symbol(y), y))
注意1:为了通用性,解决方案应该在标准Python中工作,但其他实现的答案也是可以接受的

注2:如果您觉得“symbol”不是此函数或概念的正确名称,欢迎您指出这一点


注3:这是一个精确的问题:如果代码中使用了符号Y,那么编写一个符号函数,该函数给出符号(Y)=“Y”,而不管符号指向的对象(类、对象等)。

不确定我的问题是否正确,但下面是一个在中搜索符号的示例:

输出

E:\Work\Dev\StackOverflow\q47091183>“E:\WinOBT\1.0.0.0\OPSWpython\2.7.10\uuu 00\x86\python.exe”a.py
(‘sys’,)
('x',)
('dummy',)
(‘符号’,)
(‘main’,)

这可以通过读取调用
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
注意事项:

  • 不适用于交互式会话或无法读取源代码的任何其他场景
  • 可能会被绳子绊倒:

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

非常感谢,这就开始了。我想解决的问题是,如果x和y都引用同一个字符串,那么函数只能通过查看源代码来确定我真正想要的字符串(因为我在那里说过我想要x=>'x')。我想它不应该那么简单。那么
symbol(y)会是什么呢
从您的代码返回?另外,您如何告诉函数您真正想要哪个对象?我理解。答案可以在源代码中找到:
symbol(y)=>'y'
。对象的内容不相关。非常感谢,这是一个快速且令人印象深刻的过程!我想可能有一种方法可以改进调用代码的解析,以避免第二次警告?@fralau我认为只有一些黑客的方法可以绕过第二次警告。看来,没有比第二次警告更准确地找到调用代码的方法了“它就在这行的某个地方”。我能想到的唯一解决办法是维护一个计数器,
symbol
被调用的频率-第一次调用时,返回“symbol(1)”。第二次调用时,返回“symbol(2)”“并重置计数器。很好!
sys.\u getframe
inspect
是我下一步要调查的事情。@Rawing:谢谢你的帮助:我似乎一直在花不必要的时间解释我的问题,而你却马上明白了!这是一个重复的问题。你问题的答案在另一个线程中:“对象本身不知道您使用的是什么名称”。我投票重新打开这个问题,因为它不询问函数,而且它对预期输出有一个明确的定义(与我见过的其他“此值的名称是什么”问题不同)。这个问题本质上是”如何阅读用于调用函数的源代码”,这显然是一个与“如何获取对象名称”不同的问题".@Rawing即使这是一个不同的问题,我也觉得它是。为了恢复这个问题,请给出一个你打算如何使用它的例子。我无法给出一个定义,这个定义不受几个推理缺陷的影响,这使得答案毫无用处。@bfontaine:我重新编写了我的问题,使它清楚地表明它是n关于对象的名称。
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'>)
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