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

97

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

foobar = "foo"

def func(var):
    print var.origname

所以:

func(foobar)

返回:

>>foobar

编辑:

我只是想创建一个像这样的函数:

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

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

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


2
不行。也许如果您在更高的层面上描述您想要实现什么,我们可以给您一些指针或替代方案? - Magnus Hoff
1
我主要想知道你为什么想要它?据我所知,这是不可能的,以前从来没有听说过有人想要这样做。 - dutt
@wjandrea 清除重复的 IMO。 - Karl Knechtel
13个回答

2
如果你想获取调用者的参数,就像@Matt Oates answer答案中所述,而不使用源文件(即从Jupyter Notebook中),那么这个代码(结合自@Aeon answer的答案)将解决问题(至少在一些简单情况下)。
def get_caller_params():
    # get the frame object for this function call
    thisframe = inspect.currentframe()

    # get the parent calling frames details
    frames = inspect.getouterframes(thisframe)

    # frame 0 is the frame of this function
    # frame 1 is the frame of the caller function (the one we want to inspect)
    # frame 2 is the frame of the code that calls the caller
    caller_function_name = frames[1][3]
    code_that_calls_caller = inspect.findsource(frames[2][0])[0]

    # parse code to get nodes of abstract syntact tree of the call
    nodes = ast.parse(''.join(code_that_calls_caller))

    # find the node that calls the function
    i_expr = -1
    for (i, node) in enumerate(nodes.body):
        if _node_is_our_function_call(node, caller_function_name):
            i_expr = i
            break

    # line with the call start
    idx_start = nodes.body[i_expr].lineno - 1

    # line with the end of the call
    if i_expr < len(nodes.body) - 1:
        # next expression marks the end of the call
        idx_end = nodes.body[i_expr + 1].lineno - 1
    else:
        # end of the source marks the end of the call
        idx_end = len(code_that_calls_caller)

    call_lines = code_that_calls_caller[idx_start:idx_end]
    str_func_call = ''.join([line.strip() for line in call_lines])
    str_call_params = str_func_call[str_func_call.find('(') + 1:-1]
    params = [p.strip() for p in str_call_params.split(',')]

    return params


def _node_is_our_function_call(node, our_function_name):
    node_is_call = hasattr(node, 'value') and isinstance(node.value, ast.Call)
    if not node_is_call:
        return False

    function_name_correct = hasattr(node.value.func, 'id') and node.value.func.id == our_function_name
    return function_name_correct

您可以按照以下方式运行它:
def test(*par_values):
    par_names = get_caller_params()
    for name, val in zip(par_names, par_values):
        print(name, val)


a = 1
b = 2
string = 'text'
test(a, b,
  string
)

要获得所需的输出:

a 1
b 2
string text

能否改进代码,使得当使用常量调用时,par_nameNone,例如 test("x", 1000) 应该打印出 None x 然后是 None 1000 - tsorn

0

由于您可以拥有多个具有相同内容的变量,因此不是传递变量(内容),而是通过字符串传递其名称并从调用者堆栈帧中的本地字典获取变量内容可能更安全(并且更简单)。

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

0
如果变量恰好是可调用的(函数),它将具有一个__name__属性。
例如,一个记录函数执行时间的包装器:
def time_it(func, *args, **kwargs):
    start = perf_counter()
    result = func(*args, **kwargs)
    duration = perf_counter() - start

    print(f'{func.__name__} ran in {duration * 1000}ms')

    return result

这是一个不错的方法,但对于整数不可用:'int'对象没有'name'属性。 - DShost

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接