如何获取传递给函数的变量的原始变量名称

Aco*_*orn 45 python variables function

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

foobar = "foo"

def func(var):
    print var.origname
Run Code Online (Sandbox Code Playgroud)

以便:

func(foobar)
Run Code Online (Sandbox Code Playgroud)

返回:

>>foobar

编辑:

我所要做的就是做一个像下面这样的函数:

def log(soup):
    f = open(varname+'.html', 'w')
    print >>f, soup.prettify()
    f.close()
Run Code Online (Sandbox Code Playgroud)

..并让函数从传递给它的变量的名称生成文件名.

我想如果不可能我只需要每次都将变量和变量的名称作为字符串传递.

Ivo*_*zel 55

编辑:为了说清楚,我不建议使用这个全部,它会破坏,它是一个烂摊子,它无论如何都无法帮助你,但它可以用于娱乐/教育目的.

您可以使用该inspect模块进行攻击,我不建议这样做,但您可以这样做......

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()
Run Code Online (Sandbox Code Playgroud)

输出:

['e', '1000', 'c']
Run Code Online (Sandbox Code Playgroud)

  • @Devin:在实际应用程序中使用这样的代码应该得到-1.写它是为了表明通过巧妙地滥用反射可以实现一些不寻常的东西是令人印象深刻的,当然值得+1. (25认同)
  • +1:很长一段时间以来我见过的最讨厌的代码之一. (20认同)
  • 在很长一段时间内作为最苛刻的代码值得+1?我在那里翻过牌子. (2认同)
  • 正如我所说,我不建议使用它,也不会使用这样的 hack。使用检查是 IMO 总是一个迹象,表明事情正在变得可怕,可怕的错误。我只是想证明这是可能的……但众所周知,你不应该仅仅因为有可能就去做某事。 (2认同)

Max*_*keh 17

你不能.它在传递给函数之前进行了评估.您所能做的就是将其作为字符串传递.

  • 这个答案显然是错误的,下面来自 @Aeon 的答案是正确的。 (5认同)
  • 你可以访问`locals()`和`globals()`词典并查找与值匹配的变量,但这真的很不优雅.最好简单地手动传递它:`log('myvar',myvar)`. (3认同)

out*_*tis 10

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

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'
Run Code Online (Sandbox Code Playgroud)

当然,它可以被愚弄:

def baz():
    lcl = 'hi'
    x='hi'
    return foo(lcl)

baz()
# 'x'
Run Code Online (Sandbox Code Playgroud)

道德:不要这样做.


pro*_*007 10

要添加到Michael Mrozek的答案中,您可以通过以下方式提取确切参数与完整代码:

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
Run Code Online (Sandbox Code Playgroud)


Mic*_*zek 6

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

def func(var):
    stack = traceback.extract_stack()
    filename, lineno, function_name, code = stack[-2]
Run Code Online (Sandbox Code Playgroud)

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


Aeo*_*eon 5

@Ivo Wetzel 在函数调用的情况下的答案是在一行中进行的,例如

e = 1 + 7
c = 3
foo(e, 100, b=c)
Run Code Online (Sandbox Code Playgroud)

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

e = 1 + 7
c = 3
foo(e,
    1000,
    b = c)
Run Code Online (Sandbox Code Playgroud)

下面的代码有效:

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)
Run Code Online (Sandbox Code Playgroud)

你会得到:

[u'e', u'1000', u'b = c']
Run Code Online (Sandbox Code Playgroud)

但是,这可能会中断。