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) |
号
返回:
编辑:
我只想做一个功能,比如:
1 2 3 4 | def log(soup): f = open(varname+'.html', 'w') print >>f, soup.prettify() f.close() |
…并让函数根据传递给它的变量名生成文件名。
我想如果不可能的话,我每次只需要把变量和变量名作为字符串传递。
编辑:要说清楚,我不建议使用这个,它将打破,这是一个混乱,它无论如何都不会帮助你,但它可以用于娱乐/教育目的。
你可以利用
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' |
。
道德:不要这样做。
如果知道调用代码的外观,您可以尝试另一种方法是使用
1 2 3 | def func(var): stack = traceback.extract_stack() filename, lineno, function_name, code = stack[-2] |
如果你想要一个键值对关系,也许使用字典会更好?
…或者,如果您试图从代码中创建一些自动文档,也许像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]) |
。