关于python:如何获取传递给函数的变量的原始变量名

How to get the original variable name of variable passed to a function

是否可以获取传递给函数的变量的原始变量名?例如。

1
2
3
4
foobar ="foo"

def func(var):
    print var.origname

以便:

1
func(foobar)

返回:

>>foobar

编辑:

我只想做一个功能,比如:

1
2
3
4
def log(soup):
    f = open(varname+'.html', 'w')
    print >>f, soup.prettify()
    f.close()

…并让函数根据传递给它的变量名生成文件名。

我想如果不可能的话,我每次只需要把变量和变量名作为字符串传递。


编辑:要说清楚,我不建议使用这个,它将打破,这是一个混乱,它无论如何都不会帮助你,但它可以用于娱乐/教育目的。

你可以利用inspect模块进行黑客攻击,我不建议这样做,但你可以这样做…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import inspect

def foo(a, f, b):
    frame = inspect.currentframe()
    frame = inspect.getouterframes(frame)[1]
    string = inspect.getframeinfo(frame[0]).code_context[0].strip()
    args = string[string.find('(') + 1:-1].split(',')

    names = []
    for i in args:
        if i.find('=') != -1:
            names.append(i.split('=')[1].strip())

        else:
            names.append(i)

    print names

def main():
    e = 1
    c = 2
    foo(e, 1000, b = c)

main()

输出:

1
['e', '1000', 'c']


不能。它是在传递给函数之前进行计算的。你所能做的就是把它当作字符串传递。


要添加到michael mrozek的答案中,您可以通过以下方式提取准确的参数和完整的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import re
import traceback

def func(var):
    stack = traceback.extract_stack()
    filename, lineno, function_name, code = stack[-2]
    vars_name = re.compile(r'\((.*?)\).*$').search(code).groups()[0]
    print vars_name
    return

foobar ="foo"

func(foobar)

# PRINTS: foobar


看起来Ivo打败了我,但这里有另一个实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import inspect

def varName(var):
    lcls = inspect.stack()[2][0].f_locals
    for name in lcls:
        if id(var) == id(lcls[name]):
            return name
    return None

def foo(x=None):
    lcl='not me'
    return varName(x)

def bar():
    lcl = 'hi'
    return foo(lcl)

bar()
# 'lcl'

当然,它可以被愚弄:

1
2
3
4
5
6
7
def baz():
    lcl = 'hi'
    x='hi'
    return foo(lcl)

baz()
# 'x'

道德:不要这样做。


如果知道调用代码的外观,您可以尝试另一种方法是使用traceback

1
2
3
def func(var):
    stack = traceback.extract_stack()
    filename, lineno, function_name, code = stack[-2]

code将包含用于调用func的代码行(在您的示例中,它将是字符串func(foobar))。你可以解析它来提取参数


如果你想要一个键值对关系,也许使用字典会更好?

…或者,如果您试图从代码中创建一些自动文档,也许像doxygen(http://www.doxygen.nl/)之类的东西可以为您完成这项工作?


@IvoWetzel的答案在函数调用的情况下是在一行中进行的,比如

1
2
3
e = 1 + 7
c = 3
foo(e, 100, b=c)

如果函数调用不在一行中,例如:

1
2
3
4
5
e = 1 + 7
c = 3
foo(e,
    1000,
    b = c)

以下代码工程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import inspect, ast

def foo(a, f, b):
    frame = inspect.currentframe()
    frame = inspect.getouterframes(frame)[1]
    string = inspect.findsource(frame[0])[0]

    nodes = ast.parse(''.join(string))

    i_expr = -1
    for (i, node) in enumerate(nodes.body):
        if hasattr(node, 'value') and isinstance(node.value, ast.Call)
            and hasattr(node.value.func, 'id') and node.value.func.id == 'foo'  # Here goes name of the function:
            i_expr = i
            break

    i_expr_next = min(i_expr + 1, len(nodes.body)-1)  
    lineno_start = nodes.body[i_expr].lineno
    lineno_end = nodes.body[i_expr_next].lineno if i_expr_next != i_expr else len(string)

    str_func_call = ''.join([i.strip() for i in string[lineno_start - 1: lineno_end]])
    params = str_func_call[str_func_call.find('(') + 1:-1].split(',')

    print(params)

你会得到:

1
[u'e', u'1000', u'b = c']

但是,这可能会被打破。


因为您可以有多个具有相同内容的变量,而不是传递变量(内容),所以在字符串中传递它的名称并从调用者堆栈帧中的局部变量字典中获取变量内容可能更安全(并且更简单)。:

1
2
3
def displayvar(name):
    import sys
    return name+" ="+repr(sys._getframe(1).f_locals[name])