3

我想知道将局部变量名称传递给函数时是什么。我不确定这是否可能。让我们考虑这个例子:

函数定义:

def show(x):
  print(x)

用法:

a = 10
show(a)

这会打印 10。但我喜欢打印“a = 10”。这在python中可能吗?

4

7 回答 7

7

不完全是这样。但是,您可以实现类似的目标:

def show(**kwargs):
  print(', '.join('%s=%s' % kv for kv in kwargs.items()))

show(a=20)
于 2012-12-11T20:03:34.530 回答
5

不,您无法知道用于将值传递给您的函数的局部变量的名称。

在任何情况下,这都是一项不可能完成的任务。以下示例中的变量名称是什么?

arguments = ('a', 1, 10)
somefunction(*(arguments[:2] + [10]))

这里我们传入 3 个参数,其中两个取自我们之前定义的元组,一个字面量值,这三个参数都使用变量参数列表语法传入。

于 2012-12-11T20:02:16.153 回答
3

我喜欢在 Python 编程常见问题解答中找到的这个问题的答案,引用 Fredrik Lundh 的话:

就像你得到你在门廊上发现的那只猫的名字一样:猫(物体)本身不能告诉你它的名字,它并不关心——所以找出它叫什么的唯一方法就是问你所有的邻居(命名空间),如果它是他们的猫(对象)......

....如果您发现它有很多名字,或者根本没有名字,请不要感到惊讶!

于 2012-12-11T20:09:53.303 回答
3

我预感以下解决方案将获得一些批评

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
于 2012-12-12T00:24:44.853 回答
1

这似乎在 Python 中是不可能的,但在 C++ 中实际上是可能的。

#define show(x)   std::cout << #x << " = " << x << std::endl
于 2013-01-31T05:35:04.847 回答
1

新解决方案使用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对你来说不存在......你可能可以使用pyreadlinefrompip但我从未尝试过,所以我不能说它是否是可接受的替代品。

我将让上面的代码更防弹,作为读者的练习。要考虑的事情是如何让它处理这样的事情:

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
于 2015-02-20T17:38:42.353 回答
-1

这是一个只有在使用 f-strings 的 Python 3.6 才成为可能的答案:

x = 10
print(f'{x=}')  # Outputs x=10
于 2021-02-20T03:21:08.710 回答