python - 使用 Traceback 获取函数/类的调用者名称的可堆叠装饰器?
问题描述
所以,我搞砸了并创建了这个伪状态机应用程序排序模式https://github.com/rebelclause/python_legs/blob/master/init_subclass_example.py大大扩展了这个回溯方法:https://stackoverflow .com/a/1690751/7955763
import traceback # for callable name
from functools import wraps
def tracename(orig_func):
@wraps(orig_func)
def wrapper(*args, **kwargs):
(filename,line_number,function_name,text)=traceback.extract_stack()[-2]
def_name = text[:text.find('=')].strip()
print(def_name)
return def_name
return wrapper
现在,我意识到这可能不是制作装饰器的正确方法;毕竟,回溯必须立即跟随要获取其调用者名称的函数。无论如何,我试着知道这一点,但现在乐趣结束了。我不确定我将如何使用它(即使在我提供的框架中),但有人可以回答如何改进装饰器和捕获调用者姓名的代码,以便它可以作为装饰器工作在一堆装饰器中?也许如何?
编辑:在避免协程问题的同时添加了这个...
import traceback # for callable name
from functools import wraps
# this should make you laugh, or not
def tracename(orig_func):
@wraps(orig_func)
def wrapper(*args, **kwargs):
(filename,line_number,function_name,text)=traceback.extract_stack()[-2]
def_name = text[:text.find('=')].strip()
# print(def_name)
return def_name
return wrapper
class foo(object):
''' '''
def __init__(self):
pass
@tracename
def _goodbye(self):
print("It's been a good run so far, but this decorator might be toast.")
print(foo()._goodbye()) # prints wrapper returned var def_name
foo()._goodbye() # sits and watches while we patiently wait?
# uncomment the print statement in the decorator, then re-run
# then comment out the decorator and run it
guess_who = foo()._goodbye()
print('Guess where def_name went :', guess_who) # would it freak you out if the comment printed, too?
解决方案
您的实际问题似乎在此评论中:
您可以按原样使用它,而无需更改类方法上的回溯索引 (-2),并且按原样,它将返回调用者,但是由于我尚未深入研究的原因,它不会运行方法的代码。
它不运行该方法的代码的原因很简单:您不调用该方法。
通常,装饰器看起来像这样:
def deco(func):
@wraps(func)
def wrapped(*args, **kwargs):
# possibly modify args, kwargs
# do any other pre-call stuff
result = func(*args, **kwargs)
# possibly modify result
# do any other post-call stuff
return result
return wrapped
您的装饰器缺少对 的调用func
,并且它还返回用于调用函数的字符串,而不是返回值。
如果您希望它像普通装饰器一样工作,只需执行普通装饰器的操作即可:
def tracename(orig_func):
@wraps(orig_func)
def wrapper(*args, **kwargs):
(filename,line_number,function_name,text)=traceback.extract_stack()[-2]
def_name = text[:text.find('=')].strip()
print(def_name)
return orig_func(*args, **kwargs)
return wrapper
还值得注意的是,您的函数实际上并没有“捕获调用者姓名”。它捕获的是调用语句的文本,在第一个被截断=
- 或者,如果没有=
,最后一个字符被剥离:
>>> @tracename
>>> def spam(n):
... return n
>>> spam(n=1) # will truncate the "=1)"
spam(n
>>> spam(1) # will truncate the last character
spam(1
>>> print(spam(1)) # will truncate the last character
print(spam(1)
>>> x = spam(1) # will truncate the "= spam(1)"
x
这些例子,或者我能想到的任何其他例子,都没有包含调用者的名字。来电者姓名是function_name
您得到并忽略的。
虽然真的,除非你需要与 Python 2.6 或其他东西兼容,否则你可能inspect
比traceback
这里使用更好:
>>> def tracecallername(func):
... @wraps(func)
... def wrapped(*args, **kwargs):
... frame = inspect.stack()[1]
... print(frame.function)
... # frame.code_context has the statement if you want that for something
... return func(*args, **kwargs)
... return wrapped
>>> @tracecallername
... def spam(n):
... return n
>>> def eggs():
... print(spam(1))
>>> eggs()
eggs
1
同时,如果“调用者”是指方法接收者——调用该方法的self
实例——有一种更简单的方法可以做到这一点,因为self
在 Python 方法调用中总是显式地作为第一个参数传递:
def tracereceiver(func):
@wraps(func)
def wrapped(self, *args, **kwargs):
print(self)
return func(self, *args, **kwargs)
return wrapped
推荐阅读
- powershell - 将 AD 用户字段列表写入 CSV
- git - 在 master 中恢复提交,如何在没有恢复影响的情况下将 master 拉下来?
- git - 用远程仓库覆盖本地仓库
- python - 将 Sentinel-1 SAR 图像的像素位置转换为地理坐标(纬度、经度)
- bash - 在一个文件中搜索多个单词,并为每个文件打印 1 行 - bash
- php - 尽管在我的控制器中定义了路由,但无法重定向到路由 [Symfony]
- mongodb - 无法从 Docker 中的 Flask GET 和 POST 数据到 MongoDB
- powershell - 静默模式下的 ISDeploymentWizard 状态
- python - Python中不止两个变量的相关系数
- entity-framework-core - 创建基于角色的动态授权