问题描述
我想在 Python 中调用函数时获得控制权(以执行一些先发制人的任务)而不修改源程序,例如,在调用 test() 时
def test(i : int,s: str) -> int:
pass
我想要一个函数 myobserver 被调用,并且有一些方法来检查(甚至可能修改?!)参数?把它想象成一个迷你调试器,例如,将日志添加到不能/不应该被修改的现有程序中?
def myobserver(handle)
name = get_name(handle)
for n,arg in enumerate(get_arg_iterator(handle)):
print("Argument {n} of function {name}: {arg}")
ETA:我不是在寻找传统的 decorator
,因为添加装饰器需要更改源代码。 (从这个意义上说,装饰器比添加打印更好,但仍然相似,因为它们需要更改源。)
解决方法
您正在寻找 python 装饰器:
from functools import wraps
def debugger(func):
@wraps(func)
def with_logging(*args,**kwargs):
print('"'+func.__name__+'({},{})"'.format(*args,**kwargs)+" was invoked")
# -------------------
# Your logic here
# -------------------
return func(*args,**kwargs)
return with_logging
@debugger
def test(i : int,s: str) -> int:
print('We are in test',i,s)
test(10,'hello')
编辑
由于上面提到的装饰器方法干扰了源代码(必须应用 @
装饰器),我提出以下建议:
# This is source code to observe,should not be _touched_!
class SourceCode:
def __init__(self,label):
self.label = label
def test1(self,s):
print('For object labeled {},we are in {} with param {},{}'.format(self.label,'test1',s))
def test2(self,k):
print('For object labeled {},we are in {} with param {}'.format(self.label,'test2',k))
我的建议是在编写钩子时执行一些手动操作,我不确定这是否可行(只是我突然想到,因此添加):
from functools import wraps
# the following is pretty much syntactic and generic
def hook(exist_func,debugger):
@wraps(exist_func)
def run(*args,**kwargs):
return debugger(exist_func,*args,**kwargs)
return run
# here goes your debugger
def myobserver(orig_func,**kwargs):
# -----------------------
# Your logic goes here
# -----------------------
print('Inside my debugger')
return orig_func(*args,**kwargs)
# ---------------------------------
obj = SourceCode('Test')
# making the wrapper ready to receive
no_iterference_hook1 = hook(obj.test1,myobserver)
no_iterference_hook2 = hook(obj.test2,myobserver)
# call your debugger on the function of your choice
no_iterference_hook1(10,'hello')
no_iterference_hook2('Another')