简体   繁体   English

有没有办法在python中获取传递给函数的参数的名称?

[英]Is there anyway to get the names of passed arguments to a function in python?

I like to know what was the local variable names when they are passed to a function.我想知道将局部变量名称传递给函数时的名称是什么。 I'm not sure whether this is possible at all.我不确定这是否可能。 Let's consider this example:让我们考虑这个例子:

function definition:函数定义:

def show(x):
  print(x)

usage:用法:

a = 10
show(a)

this prints 10. But I like to print "a = 10".这会打印 10。但我喜欢打印“a = 10”。 Is this possible in python?这在python中可能吗?

Not exactly like this.不完全是这样。 However, you can achieve something similar:但是,您可以实现类似的目标:

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

show(a=20)

No, you cannot know what the name was of the local variable used to pass a value to your function.不,您无法知道用于将值传递给您的函数的局部变量的名称是什么。

This is an impossible task in any case.这在任何情况下都是不可能完成的任务。 What would be the variable name in the following example?以下示例中的变量名称是什么?

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

Here we pass in 3 arguments, two taken from a tuple we defined earlier, and one literal value, and all three are passed in using the variable argument list syntax.这里我们传入了 3 个参数,其中两个取自我们之前定义的元组,还有一个文字值,所有三个参数都是使用变量参数列表语法传入的。

I like the answer to this question that's found in the Python programming FAQ, quoting Fredrik Lundh:我喜欢在 Python 编程常见问题解答中找到的这个问题答案,引用 Fredrik Lundh 的话:

The same way as you get the name of that cat you found on your porch: the cat (object) itself cannot tell you its name, and it doesn't really care – so the only way to find out what it's called is to ask all your neighbours (namespaces) if it's their cat (object)...就像你得到你在门廊上找到的那只猫的名字一样:猫(物体)本身不能告诉你它的名字,它并不真正关心——所以找出它叫什么的唯一方法是问你所有的邻居(命名空间),如果是他们的猫(对象)...

....and don't be surprised if you'll find that it's known by many names, or no name at all! ....如果您发现它有很多名字,或者根本没有名字,请不要感到惊讶!

I forebode that the following solution will gain several criticisms我预示以下解决方案会受到一些批评

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,)))

result结果

============================================
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

New Solution Using readline使用readline新解决方案

If you're in an interactive session, here's an extremely naive solution that will usually work:如果你在一个交互式会话中,这里有一个非常简单的解决方案,通常会奏效:

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))

All it does is read the last line input in the interactive session buffer, remove any leading or trailing whitespace, then give you everything but the first five characters (hopefully show( ) and the last character (hopefully ) ), thus leaving you with whatever was passed in.它所做的只是读取交互式会话缓冲区中的最后一行输入,删除任何前导或尾随空格,然后为您提供除前五个字符(希望show( )和最后一个字符(希望) )之外的所有内容,从而为您留下任何内容被传入。

Example:例子:

>>> 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

If you're on OS X using the version of Python that comes with it, you don't have readline installed by default, but you can install it via pip .如果您在 OS X 上使用随附的 Python 版本,则默认情况下您没有安装readline ,但您可以通过pip安装它。 If you're on Windows, readline doesn't exist for you... you might be able to use pyreadline from pip but I've never tried it so I can't say if it's an acceptable substitute or not.如果您使用的是 Windows,则不存在readline ……您可能可以使用pip pyreadline ,但我从未尝试过,所以我不能说它是否是可接受的替代品。

I leave making the above code more bullet-proof as an exercise for the reader.我把让上面的代码更防弹的留给读者作为练习。 Things to consider would be how to make it handle things like this:需要考虑的事情是如何让它处理这样的事情:

show(show(show(10)))
show(
10
)

If you want this kind of thing to show variables names from a script, you can look into using inspect and getting the source code of the calling frame.如果您希望这种东西从脚本中显示变量名称,您可以考虑使用检查并获取调用框架的源代码。 But given I can't think of why you would ever want to use show() in a script or why you would complicate the function just to handle people intentionally screwing with it as I did above, I'm not going to waste my time right now figuring it out.但是考虑到我想不出为什么你会想要在脚本中使用show()或者为什么你会像我上面那样为了处理故意搞砸的人而使函数复杂化,我不会浪费我的时间现在想通了。

Original Solution Using inspect使用inspect原始解决方案

Here's my original solution, which is more complicated and has a more glaring set of caveats, but is more portable since it only uses inspect , not readline , so runs on all platforms and whether you're in an interactive session or in a script:这是我的原始解决方案,它更复杂并且有更多明显的警告,但更便携,因为它只使用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))

Here's a case where it works perfectly (the one from the question):这是一个完美运行的情况(问题中的那个):

>>> a = 10
>>> show(a)
a = 10

Here's another fun case:这是另一个有趣的案例:

>>> show(quit)
quit = Use quit() or Ctrl-Z plus Return to exit

Now you know how that functionality was implemented in the Python interpreter - quit is a built-in identifier for a str that says how to properly quit.现在您知道该功能是如何在 Python 解释器中实现的 - quitstr的内置标识符,表示如何正确退出。

Here's a few cases where it's less than you might want, but... acceptable?这里有一些情况比您想要的要少,但是……可以接受吗?

>>> b = 10
>>> show(b)
<a, or b> = 10
>>> show(11)
<unnamed> = 11
>>> show([a])
<unnamed> = [10]

And here's a case where it prints out a true statement, but definitely not what you were looking for:这是一个例子,它打印出一个真实的陈述,但绝对不是你想要的:

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

Here's an answer that only became possible as of Python 3.6 with f-strings:这是一个只有在 Python 3.6 中使用 f-strings 才成为可能的答案:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM