我想知道将局部变量名称传递给函数时是什么。我不确定这是否可能。让我们考虑这个例子:
函数定义:
def show(x):
print(x)
用法:
a = 10
show(a)
这会打印 10。但我喜欢打印“a = 10”。这在python中可能吗?
我想知道将局部变量名称传递给函数时是什么。我不确定这是否可能。让我们考虑这个例子:
函数定义:
def show(x):
print(x)
用法:
a = 10
show(a)
这会打印 10。但我喜欢打印“a = 10”。这在python中可能吗?
不完全是这样。但是,您可以实现类似的目标:
def show(**kwargs):
print(', '.join('%s=%s' % kv for kv in kwargs.items()))
show(a=20)
不,您无法知道用于将值传递给您的函数的局部变量的名称。
在任何情况下,这都是一项不可能完成的任务。以下示例中的变量名称是什么?
arguments = ('a', 1, 10)
somefunction(*(arguments[:2] + [10]))
这里我们传入 3 个参数,其中两个取自我们之前定义的元组,一个字面量值,这三个参数都使用变量参数列表语法传入。
我喜欢在 Python 编程常见问题解答中找到的这个问题的答案,引用 Fredrik Lundh 的话:
就像你得到你在门廊上发现的那只猫的名字一样:猫(物体)本身不能告诉你它的名字,它并不关心——所以找出它叫什么的唯一方法就是问你所有的邻居(命名空间),如果它是他们的猫(对象)......
....如果您发现它有很多名字,或者根本没有名字,请不要感到惊讶!
我预感以下解决方案将获得一些批评
def show(*x):
for el in x:
fl = None
for gname,gobj in globals().iteritems():
if el==gobj:
print '%s == %r' % (gname,el)
fl = True
if not fl:
print 'There is no identifier assigned to %r in the global namespace' % el
un = 1
y = 'a'
a = 12
b = c = 45
arguments = ('a', 1, 10)
lolo = [45,'a',a,'heat']
print '============================================'
show(12)
show(a)
print '============================================'
show(45)
print
show(b)
print '============================================'
show(arguments)
print
show(('a', 1, 10))
print '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'
show(*arguments)
print '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'
show(*(arguments[1:3] + (b,)))
结果
============================================
a == 12
a == 12
============================================
c == 45
b == 45
c == 45
b == 45
============================================
arguments == ('a', 1, 10)
arguments == ('a', 1, 10)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
y == 'a'
un == 1
There is no identifier assigned to 10 in the global namespace
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
un == 1
There is no identifier assigned to 10 in the global namespace
c == 45
b == 45
这似乎在 Python 中是不可能的,但在 C++ 中实际上是可能的。
#define show(x) std::cout << #x << " = " << x << std::endl
新解决方案使用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
对你来说不存在......你可能可以使用pyreadline
frompip
但我从未尝试过,所以我不能说它是否是可接受的替代品。
我将让上面的代码更防弹,作为读者的练习。要考虑的事情是如何让它处理这样的事情:
show(show(show(10)))
show(
10
)
如果您希望这种东西显示脚本中的变量名称,您可以查看使用检查并获取调用框架的源代码。但是考虑到我想不出为什么你会想show()
在脚本中使用,或者为什么你会像我上面那样处理故意搞砸它的人而使函数复杂化,我现在不会浪费我的时间来计算出来。
原始解决方案使用inspect
这是我的原始解决方案,它更复杂并且有更明显的警告集,但更便携,因为它只使用inspect
, not 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
是 a 的内置标识符str
,说明如何正确退出。
这里有一些情况可能比您想要的要少,但是......可以接受吗?
>>> b = 10
>>> show(b)
<a, or b> = 10
>>> show(11)
<unnamed> = 11
>>> show([a])
<unnamed> = [10]
这是一个打印出真实陈述的案例,但绝对不是您想要的:
>>> show(10)
<a, or b> = 10
这是一个只有在使用 f-strings 的 Python 3.6 才成为可能的答案:
x = 10
print(f'{x=}') # Outputs x=10