在显示调用函数的参数和值的实用程序函数中,我需要知道从另一个模块导入的可能别名函数的原始名称。这可能是针对导入别名的简单情况吗?
这是一个简化的用例,我首先介绍utilities.py
模块中的一些代码:
import inspect
DEBUG_FLAG = True
def _log_args(*args):
"""Uses reflection to returning passing argument code with values."""
prev_frame = inspect.currentframe().f_back
func_name = prev_frame.f_code.co_name
code_context = inspect.getframeinfo(prev_frame.f_back).code_context[0].strip()
# Do some magic, which does work _unless_ func_name is aliased :-)
print('code context: {}'.format(code_context))
print('func_name : {}'.format(func_name))
return ', '.join(str(arg) for arg in args)
def format_args(*args):
"""Returns string with name of arguments with values."""
return _log_args(args)
def debug_print(*args):
"""Prints name of arguments with values."""
if DEBUG_FLAG:
print _log_args(args)
以下是一些代码首先按原始名称访问这些函数,然后使用别名:
from utilities import debug_print, format_args, debug_print as debug, format_args as fargs
def main():
a, b = "text", (12, 13)
print "== Unaliased =="
test_text = format_args(a, b)
print test_text # Returns
debug_print(a, b)
print "\n== Aliased =="
test_text = fargs(a, b)
print test_text
debug(a, b)
if __name__ == '__main__':
main()
这个输出是:
== Unaliased ==
code context: test_text = format_args(a, b)
func_name : format_args
('text', (12, 13))
code context: debug_print(a, b)
func_name : debug_print
('text', (12, 13))
== Aliased ==
code context: test_text = fargs(a, b)
func_name : format_args
('text', (12, 13))
code context: debug(a, b)
func_name : debug_print
('text', (12, 13))
可以看出我找到了正确的代码上下文,并且找到了调用函数的名称,但是第一个报告了别名,后者报告了实际名称。所以我的问题是是否可以撤销操作,以便我知道format_args
已被别名化为fargs
,而debug_print
已被别名化为debug
}?
一些相关的问题,不解决了这种别名的反转:
答案 0 :(得分:0)
事实证明,找出为debug_print
或format_args
定义的别名是相当困难的,但幸运的是我确实有代码上下文,可以执行相反的操作来查找我的哪一部分代码上下文实际上是我的功能之一。
导致此解决方案的以下思路部分受到Martijn Pieters与抽象语法树相关的评论的启发,部分受SuperBiasedMan给出的与做help(fargs)
相关的提示的启发。 }}:
help(fargs)
实际列出了format_args
函数help??
,我发现它使用了pydoc.help
name = getattr(thing, '__name__', None)
getattr(fargs, '__name__', None)
,并且它正常工作getattr('fargs', ...)
,但失败了globals()['fargs']
确实返回了函数对象code_context
中提取令牌,并编写了一些代码来执行各种查找所有这些都产生了以下工作代码:
def _log_args(*args):
"""Uses reflection to returning passing argument code with values."""
prev_frame = inspect.currentframe().f_back
func_name = prev_frame.f_code.co_name
code_context = inspect.getframeinfo(prev_frame.f_back).code_context[0].strip()
# Do some magic, which does work _unless_ func_name is aliased :-)
print('code context : {}'.format(code_context))
print('func_name : {}'.format(func_name))
# Get globals from the calling frame
globals_copy = prev_frame.f_back.f_globals
tokens = re.compile('[_a-zA-Z][a-zA-Z_0-9]*').findall(code_context)
for token in tokens:
print( ' Checking token : {}'.format(token))
# Check if token is found as an object in globals()
code_object = globals_copy.get(token, None)
if not code_object:
continue
# Check if code_object is one of my userdefined functions
if inspect.isfunction(code_object):
code_func_name = getattr(code_object, '__name__', None)
else:
continue
# Check if expanded token is actually an alias (or equal) to func_name
if code_func_name == func_name:
func_name = token
break
else:
# For-loop went through all tokens, and didn't find anything
func_name = None
if func_name:
print('Calling function : {}'.format(func_name))
else:
print('Didn\'t find a calling function?!')
return ', '.join(str(arg) for arg in args)
我知道这取决于代码上下文中存在的调用函数,如果您将代码分解为多行,则会破坏此方法。另一个警告是,如果有人通过列表或词典调用该函数。但是,这主要是出于调试目的,并且可以记录它们不应该做那样的事情。
输出现在是:
== Unaliased ==
code context : test_text = format_args(a, b)
func_name : format_args
Calling function : format_args
('text', (12, 13))
code context : debug_print(a, b)
func_name : debug_print
Calling function : debug_print
('text', (12, 13))
== Aliased ==
code context : test_text = fargs(a, b)
func_name : format_args
Calling function : fargs
('text', (12, 13))
code context : debug(a, b)
func_name : debug_print
Calling function : debug
('text', (12, 13)
此输出现在可以继续我寻求制作一个不错的debug_print()
。如果您发现此设计有任何改进或缺陷,请发表评论(或回答)。