使用readline的新解决方案
如果您处于交互式会话中,这里有一个非常简单的解决方案,通常会起作用:
def show(x):
from readline import get_current_history_length, get_history_item
print(get_history_item(get_current_history_length()).strip()[5:-1] + ' = ' + str(x))
它所做的只是读取交互式会话缓冲区中的最后一行输入,删除任何前导或尾随空格,然后为您提供除前五个字符(希望是 show()和最后一个字符(希望是 ))之外的所有内容,从而使您得到传入的任何内容。
例子:
>>> a = 10
>>> show(a)
a = 10
>>> b = 10
>>> show(b)
b = 10
>>> show(10)
10 = 10
>>> show([10]*10)
[10]*10 = [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
>>> show('Hello' + 'World'.rjust(10))
'Hello' + 'World'.rjust(10) = Hello World
如果您在 OS X 上使用随附的 Python 版本,则默认情况下您没有安装 readline,但您可以通过 pip 安装它。如果您在 Windows 上,readline 不适合您...您可能可以使用来自pip 的pyreadline 但我从未尝试过,所以我不能说它是否是可接受的替代品与否。
我把让上面的代码更防弹的问题留给读者作为练习。要考虑的事情是如何让它处理这样的事情:
show(show(show(10)))
show(
10
)
如果您希望这种东西显示脚本中的变量名称,您可以查看使用检查并获取调用框架的源代码。但是考虑到我想不出你为什么会想在脚本中使用show(),或者为什么你会像我上面所做的那样让函数复杂化只是为了处理故意搞砸的人,我不会浪费我的时间现在想起来了。
使用inspect的原始解决方案
这是我最初的解决方案,它更复杂,有更明显的警告,但更便携,因为它只使用inspect,而不是readline,因此可以在所有平台上运行,无论您是否在交互式会话或脚本:
def show(x):
from inspect import currentframe
# Using inspect, figure out what the calling environment looked like by merging
# what was available from builtin, globals, and locals.
# Do it in this order to emulate shadowing variables
# (locals shadow globals shadow builtins).
callingFrame = currentframe().f_back
callingEnv = callingFrame.f_builtins.copy()
callingEnv.update(callingFrame.f_globals)
callingEnv.update(callingFrame.f_locals)
# Get the variables in the calling environment equal to what was passed in.
possibleRoots = [item[0] for item in callingEnv.items() if item[1] == x]
# If there are none, whatever you were given was more than just an identifier.
if not possibleRoots:
root = '<unnamed>'
else:
# If there is exactly one identifier equal to it,
# that's probably the one you want.
# This assumption could be wrong - you may have been given
# something more than just an identifier.
if len(possibleRoots) == 1:
root = str(possibleRoots[0])
else:
# More than one possibility? List them all.
# Again, though, it could actually be unnamed.
root = '<'
for possibleRoot in possibleRoots[:-1]:
root += str(possibleRoot) + ', '
root += 'or ' + str(possibleRoots[-1]) + '>'
print(root + ' = ' + str(x))
这是一个完美运行的案例(问题中的那个):
>>> a = 10
>>> show(a)
a = 10
这是另一个有趣的案例:
>>> show(quit)
quit = Use quit() or Ctrl-Z plus Return to exit
现在您知道该功能是如何在 Python 解释器中实现的 - quit 是 str 的内置标识符,表示如何正确退出。
在某些情况下,它可能比您想要的要少,但是...可以接受吗?
>>> b = 10
>>> show(b)
<a, or b> = 10
>>> show(11)
<unnamed> = 11
>>> show([a])
<unnamed> = [10]
这是一个例子,它打印出一个真实的陈述,但绝对不是你要找的:
>>> show(10)
<a, or b> = 10