在python中,是否仍然可以获取传递给函数的参数的名称?

在python中,是否仍然可以获取传递给函数的参数的名称?,python,Python,我想知道传递给函数的局部变量名是什么。我不确定这是否可能。让我们来考虑这个例子: 功能定义: def show(x): print(x) 用法: a = 10 show(a) 这张打印10张。但我喜欢打印“a=10”。这在python中可能吗?不,您无法知道用于向函数传递值的局部变量的名称 无论如何,这是一项不可能完成的任务。以下示例中的变量名是什么 arguments = ('a', 1, 10) somefunction(*(arguments[:2] + [10])) 这里我们传

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

功能定义:

def show(x):
  print(x)
用法:

a = 10
show(a)

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

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

无论如何,这是一项不可能完成的任务。以下示例中的变量名是什么

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

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

与此不同。但是,您可以实现类似的目标:

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

show(a=20)
我喜欢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定义show(x)std::cout新解决方案

如果您正在进行交互式会话,这里有一个非常简单的解决方案,通常会奏效:

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
如果您在OSX上使用随附的Python版本,默认情况下没有安装
readline
,但可以通过
pip
安装。如果您在Windows上,
readline
对您来说不存在。。。您可能可以从
pip
使用
pyreadline
,但我从未尝试过,因此我无法确定它是否是可接受的替代品

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

show(show(show(10)))
show(
10
)
如果您希望这类内容显示脚本中的变量名称,可以研究使用inspect并获取调用框架的源代码。但是我想不出为什么你会想在脚本中使用
show()
,或者为什么你会像我上面所做的那样,为了处理故意使用它的人而使函数复杂化,我现在不打算浪费时间去弄清楚它

使用
检查原始溶液

这是我最初的解决方案,它更复杂,有一组更明显的警告,但更便于移植,因为它只使用
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))
下面是另一个有趣的例子:

>>> 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]
>b=10
>>>节目(b)
= 10
>>>节目(11)
= 11
>>>显示([a])
= [10]
这里有一个例子,它打印出一个真实的陈述,但绝对不是你想要的:

>>> show(10)
<a, or b> = 10
>节目(10)
= 10

以下是一个只有在Python 3.6中使用f字符串时才可能实现的答案:

x = 10
print(f'{x=}')  # Outputs x=10

你有什么特别的用途吗?我喜欢它输出“23.4567=23.4567”或一些随机或固定的名称。原因是我有两种工作要提交给集群。Matlab作业(echo“Matlab-ra=1,b=2函数”| qsub)或shell作业(echo“program 12”| qsub)。在matlab的例子中,我需要知道变量名。当然,我可以添加另一个参数,但我只是想确定是否有更干净的方法来实现它。@MohammadMoghimi显式并没有什么“不干净的”:@JonClements我最后就是这么做的!:)我的回答是“不”-还有一些警告-我有一种非常可怕的感觉,你可以用syshooks做些什么-但是我一直坚持“不”-和“你想做什么有什么关系?”@JonClements:你也可以试着玩
sys.\u getframe(1)
和代码框架的反编译。。颤抖不是为了胆小的人,除非OP有他妈的好的理由这样做,否则我不会去探索。我相信没有剖析/其他深奥的目的-没有:)@dash tom bang Umm,应该是
剖析/其他/深奥的
(或者只是没有
其他
)@JonClements啊,抱歉!当我怀疑有人在暗示分析(或单元测试)不是每个人都应该做的事情时,我的愤怒占据了我的上风!是的,我一定很喜欢effbot所说的:)[尽管如此,我相信在德克的一本书中,德克的任务之一是尝试找出一只猫的名字,并做到了:)!]我从阅读effbot的代码中学到了更多关于Python的知识,而不是从我所做的任何其他事情中学到的。他击败了我的C++。为了具体回答OP,调用将是<代码>显示(A= A,AtArg= AtdiaGg,ETC=ETC)< /C>,根据需要扩展。+ 1用于创造力。但考虑到它必须位于全局名称空间内,它似乎有点有限,而答案本身似乎有点冗长。我希望有人能通过查找帧堆栈来做些什么。也许我会自己做。或者我会决定这不是wo
x = 10
print(f'{x=}')  # Outputs x=10