如何在Python中获取函数的实际参数名称?

时间:2014-12-18 11:37:00

标签: python introspection python-internals

例如:

def func(a):
    # how to get the name "x"

x = 1
func(x)

如果我使用inspect模块,我可以获得堆栈帧对象:

import inspect
def func(a):
    print inspect.stack()

出:

[
(<frame object at 0x7fb973c7a988>, 'ts.py', 9, 'func', ['  stack = inspect.stack()\n'], 0)

(<frame object at 0x7fb973d74c20>, 'ts.py', 18, '<module>', ['func(x)\n'], 0)
]

或使用inspect.currentframe()我可以获取当前帧。

但是我只能通过检查函数对象获得名称"a"

使用inspect.stack我可以获得调用堆栈:"['func(x)\n']"

如何通过解析"x"来调用func来获取实际参数的名称("['func(x)\n']")?

如果我致电func(x),我会得到"x"

如果我致电func(y),我会得到"y"

编辑:

一个例子:

def func(a):

    # Add 1 to acttual parameter
    ...

x = 1
func(x)
print x # x expected to 2

y = 2
func(y)
print y # y expected to 3

4 个答案:

答案 0 :(得分:3)

查看您的评论解释,您尝试这样做的原因是:

  

因为我想在C ++中推动参考参数

你做不到。在python中,所有内容都按值传递,但该值是对您传递的对象的引用。现在,如果该对象是可变的(如列表),您可以修改它,但如果它是不可变的,则创建并设置一个新对象。在您的代码示例中,xint,它是不可变的,因此如果您想更改x的值,只需从您调用的函数返回其新值: / p>

def func(a):
    b = 5 * a
    # ... some math
    return b


x = 1
x = func(x)

那么如果你想返回多个值呢?使用tuple

def func(a, b):
    a, b = 5 * b, 6 * a
    # ...
    return b, a

a, b = 2, 3
a, b = func(a, b)

答案 1 :(得分:1)

这在某种程度上是可行的 - 但在任何类型的真实代码中都是无用的。 你可以将它用于后院魔术:

只需像你正在那样检索调用stack_frame, 然后线性循环通过调用帧中可用的变量 引用您作为参数获得的同一对象的一个​​。变量在 f_localsf_globals字典,它们是框架对象的属性。

当然,传递的参数可能不是以变量名开头的: 它可能是调用者中的常量,也可能是在字典或列表中。

无论哪种方式,正如@Nasser所说的那样:它不是Python的工作方式。对象存在于内存中,每个范围中的变量名只指向这些对象。否则这些名称本身毫无意义。

import inspect
from itertools import chain

def magic(x):
    # note that in Python2, 'currentframe' could get a parameter
    # to indicate which frame you want on the stack. Not so in Python3
    fr = inspect.currentframe().f_back
    for var_name, value in chain(fr.f_locals.items(),  fr.f_globals.items()):
        if value is x:
            print ("The variable name in the caller context is {}".format(var_name))


def caler():
   y = "My constant"
   magic(y)

答案 2 :(得分:0)

使用列表作为参考

def func(a):
   a[0] = a[0] + 1

x = [1]
func(x)
print x[0] # x expected to 2

y = [2]
func(y)
print y[0] # y expected to 3

答案 3 :(得分:-1)

这是我的最终解决方案。使用ast解析函数语句并获取args。:

import inspect
import re
import ast

def func(a,b,c):
  stack = inspect.stack()
  stack_pre = stack[1]
  function_call_string = ';'.join( stack_pre[4] ).strip('\n')
  ret = re.search(r'(%s[ ]*\(.*\))' % func.func_name, function_call_string)
  striped_function_call_string = ret.group()
  parser = ast.parse(striped_function_call_string)

  frame = inspect.currentframe()
  for arg in parser.body[0].value.args:
    iter_frame = frame.f_back
    while iter_frame:
      if arg.id in iter_frame.f_locals:
        iter_frame.f_locals[arg.id] += 1
        break
      iter_frame = iter_frame.f_back

x=1;y=2;z=3;func(x,y,z)
print x,y,z

输出: 2 3 4