Ответ 1
Вы не можете. Он оценивался перед передачей функции. Все, что вы можете сделать, это передать его как строку.
Можно ли получить исходное имя переменной переменной, переданной функции? Например.
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()
.. и функция сгенерирует имя файла из имени переданной ему переменной.
Я полагаю, что если это невозможно, мне просто нужно будет каждый раз передавать переменную и имя переменной в виде строки.
Вы не можете. Он оценивался перед передачей функции. Все, что вы можете сделать, это передать его как строку.
РЕДАКТИРОВАТЬ: Чтобы это было ясно, я не рекомендую использовать этот 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']
Похоже, что Иво избил меня до 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'
Мораль: не делайте этого.
Чтобы добавить к Майклу Мрозеку ответ, вы можете получить точные параметры по сравнению с полным кодом:
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
Если вы знаете, как будет выглядеть вызывающий код, вы можете попробовать использовать traceback
:.
def func(var):
stack = traceback.extract_stack()
filename, lineno, function_name, code = stack[-2]
code
будет содержать строку кода, которая использовалась для вызова func
(в вашем примере это будет строка func(foobar)
). Вы можете разобрать это, чтобы вытащить аргумент
Если вы хотите, чтобы между парой ключ-значение было лучше использовать словарь?
... или если вы пытаетесь создать некоторую автоматическую документацию из своего кода, возможно, что-то вроде Doxygen (http://www.doxygen.nl/) могло бы помочь вам?
@Ответы 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']
Но все же это может сломаться.
Поскольку у вас может быть несколько переменных с одним и тем же содержимым, вместо передачи переменной (содержимого) может быть безопаснее (и будет проще) передать ее имя в строке и получить содержимое переменной из словаря локальных объектов в стеке вызывающих. Рамка.
def displayvar(name):
import sys
return name+" = "+repr(sys._getframe(1).f_locals[name])
Для процветания здесь приведен некоторый код, который у меня был для этой задачи, в общем, я думаю, что в 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