Подтвердить что ты не робот

Как получить исходное имя переменной, переданное функции

Можно ли получить исходное имя переменной переменной, переданной функции? Например.

foobar = "foo"

def func(var):
    print var.origname

Итак, чтобы:

func(foobar)

Возврат:

>>foobar

EDIT:

Все, что я пытался сделать, это сделать такую ​​функцию, как:

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

.. и функция сгенерирует имя файла из имени переданной ему переменной.

Я полагаю, что если это невозможно, мне просто нужно будет каждый раз передавать переменную и имя переменной в виде строки.

4b9b3361

Ответ 1

Вы не можете. Он оценивался перед передачей функции. Все, что вы можете сделать, это передать его как строку.

Ответ 2

РЕДАКТИРОВАТЬ: Чтобы это было ясно, я не рекомендую использовать этот AT ALL, он сломается, это беспорядок, он вам все равно не поможет, но он подходит для развлечений/образования.

Вы можете взломать модуль 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()

Выход:

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

Ответ 3

Похоже, что Иво избил меня до 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'

Конечно, его можно обмануть:

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

baz()
# 'x'

Мораль: не делайте этого.

Ответ 4

Чтобы добавить к Майклу Мрозеку ответ, вы можете получить точные параметры по сравнению с полным кодом:

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

Ответ 5

Если вы знаете, как будет выглядеть вызывающий код, вы можете попробовать использовать traceback:.

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

code будет содержать строку кода, которая использовалась для вызова func (в вашем примере это будет строка func(foobar)). Вы можете разобрать это, чтобы вытащить аргумент

Ответ 6

Если вы хотите, чтобы между парой ключ-значение было лучше использовать словарь?

... или если вы пытаетесь создать некоторую автоматическую документацию из своего кода, возможно, что-то вроде Doxygen (http://www.doxygen.nl/) могло бы помочь вам?

Ответ 7

@Ответы Ivo Wetzel работают в случае вызова функции в одной строке, например

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

Если вызов функции не находится в одной строке, например:

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

ниже работает код:

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)

Вы получите:

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

Но все же это может сломаться.

Ответ 8

Поскольку у вас может быть несколько переменных с одним и тем же содержимым, вместо передачи переменной (содержимого) может быть безопаснее (и будет проще) передать ее имя в строке и получить содержимое переменной из словаря локальных объектов в стеке вызывающих. Рамка.

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

Ответ 9

Для процветания здесь приведен некоторый код, который у меня был для этой задачи, в общем, я думаю, что в Python отсутствует модуль, который предоставил бы всем хороший и надежный контроль среды вызывающего. Подобно тому, что предоставляет Rlang Eval Framework в R.

import re, inspect, ast

#Convoluted frame stack walk and source scrape to get what the calling statement to a function looked like.
#Specifically return the name of the variable passed as parameter found at position pos in the parameter list.
def _caller_param_name(pos):
    #The parameter name to return
    param = None
    #Get the frame object for this function call
    thisframe = inspect.currentframe()
    try:
        #Get the parent calling frames details
        frames = inspect.getouterframes(thisframe)
        #Function this function was just called from that we wish to find the calling parameter name for
        function = frames[1][3]
        #Get all the details of where the calling statement was
        frame,filename,line_number,function_name,source,source_index = frames[2]
        #Read in the source file in the parent calling frame upto where the call was made
        with open(filename) as source_file:
            head=[source_file.next() for x in xrange(line_number)]
        source_file.close()

        #Build all lines of the calling statement, this deals with when a function is called with parameters listed on each line
        lines = []
        #Compile a regex for matching the start of the function being called
        regex = re.compile(r'\.?\s*%s\s*\(' % (function))
        #Work backwards from the parent calling frame line number until we see the start of the calling statement (usually the same line!!!)
        for line in reversed(head):
            lines.append(line.strip())
            if re.search(regex, line):
                break
        #Put the lines we have groked back into sourcefile order rather than reverse order
        lines.reverse()
        #Join all the lines that were part of the calling statement
        call = "".join(lines)
        #Grab the parameter list from the calling statement for the function we were called from
        match = re.search('\.?\s*%s\s*\((.*)\)' % (function), call)
        paramlist = match.group(1)
        #If the function was called with no parameters raise an exception
        if paramlist == "":
            raise LookupError("Function called with no parameters.")
        #Use the Python abstract syntax tree parser to create a parsed form of the function parameter list 'Name' nodes are variable names
        parameter = ast.parse(paramlist).body[0].value
        #If there were multiple parameters get the positional requested
        if type(parameter).__name__ == 'Tuple':
            #If we asked for a parameter outside of what was passed complain
            if pos >= len(parameter.elts):
                raise LookupError("The function call did not have a parameter at postion %s" % pos)
            parameter = parameter.elts[pos]
        #If there was only a single parameter and another was requested raise an exception
        elif pos != 0:
            raise LookupError("There was only a single calling parameter found. Parameter indices start at 0.")
        #If the parameter was the name of a variable we can use it otherwise pass back None
        if type(parameter).__name__ == 'Name':
            param = parameter.id
    finally:
        #Remove the frame reference to prevent cyclic references screwing the garbage collector
        del thisframe
    #Return the parameter name we found
    return param