関数に渡された変数の元の変数名を取得することは可能ですか?例えば。
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()
..そして、関数に、渡された変数の名前からファイル名を生成させます。
それが不可能な場合は、毎回変数と変数の名前を文字列として渡す必要があると思います。
できません。関数に渡される前に評価されます。できることは、それを文字列として渡すことだけです。
編集:明確にするために、これを使用することはお勧めしません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']
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
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'
もちろん、だまされる可能性があります。
def baz():
lcl = 'hi'
x='hi'
return foo(lcl)
baz()
# 'x'
道徳:それをしないでください。
呼び出しコードがどのように見えるかがわかっている場合に試すことができるもう1つの方法は、 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の回答は、次のように1行で作成されます。
e = 1 + 7
c = 3
foo(e, 100, b=c)
その関数呼び出しが1行にない場合:
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']
しかし、それでも壊れる可能性があります。
ソースファイルを使用せずに(つまり、Jupyter Notebookから) @ Matt Oates answer answerのように呼び出し元のパラメーターを取得する場合、このコード( @ 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
変数(コンテンツ)を渡す代わりに、同じコンテンツを持つ複数の変数を使用できるため、文字列でその名前を渡し、呼び出し元スタックのローカルディクショナリから変数のコンテンツを取得する方が安全(かつ簡単)です。フレーム。 :
def displayvar(name):
import sys
return name+" = "+repr(sys._getframe(1).f_locals[name])