因此,我搞砸了并创建了这种伪造的State-Machine应用排序模式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?
答案 0 :(得分:0)
您的实际问题似乎在此评论中:
您可以按原样使用它,而无需在类的方法上更改回溯索引(-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