[英]Function decorator that logs the value of specified function arguments in an accessible python object
我正在嘗試創建一個函數裝飾器,該函數裝飾器將指定值的函數參數記錄在可訪問的python對象中。 我已經可以使用代碼了,但是我缺少一段代碼來完成此工作。
首先,我有對象日志,可以在其中正確保存內容:
class Borg:
_shared_state = {}
def __init__(self):
self.__dict__ = self._shared_state
class Log(Borg):
def __init__(self):
Borg.__init__(self)
if not hasattr(self, 'tape'):
self.tape = []
def add(self, this):
self.tape.append(this)
def __str__(self):
return '\n'.join([str(line) for line in self.tape])
然后,我有一個通用的調用對象和裝飾器實現(缺少代碼):
import inspect
import functools
class Call:
def __init__(self, name, **saved_arguments):
self.name = name
self.saved_arguments = saved_arguments
def __str__(self):
return f'Call(name={self.name}, saved_arguments={self.saved_arguments})'
def record(func, save_args_names=None):
if save_args_names is None:
save_args_names = {}
name = func.__name__
args = inspect.getfullargspec(func).args
if save_args_names and not set(save_args_names).issubset(set(args)):
raise ValueError(f'Arguments not present in function: {set(save_args_names) - set(args)}')
log = Log()
@functools.wraps(func)
def wrapper(*func_args, **func_kwargs):
# **here** I am missing something to replace 0 with the correct values!
saved_arguments = {a: 0 for a in save_args_names}
log.add(Call(name, **saved_arguments))
return_value = func(*func_args, **func_kwargs)
return return_value
return wrapper
為了對此進行測試,我設置了以下功能:
def inner(x, add=0):
return sum(x) + add
def outer(number, add=0):
x = range(number)
return inner(x, add)
基本用例(不保存參數)可以工作:
inner = record(inner)
print(outer(1), outer(2), outer(3))
print(Log())
它正確輸出:
0 1 3
Call(name=inner, saved_arguments={})
Call(name=inner, saved_arguments={})
Call(name=inner, saved_arguments={})
我所缺少的是使用此用例的方法:
inner = record(inner, save_args_names=['x'])
print(outer(1), outer(2), outer(3))
print(Log())
輸出:
0 1 3
Call(name=inner, saved_arguments={'x': range(0, 1)})
Call(name=inner, saved_arguments={'x': range(0, 2)})
Call(name=inner, saved_arguments={'x': range(0, 3)})
這也適用於關鍵字參數,例如:
inner = record(inner, save_args_names=['x', 'add'])
print(outer(1, 2), outer(2, 3), outer(3, 4))
print(Log())
應該輸出:
2 4 7
Call(name=inner, saved_arguments={'x': range(0, 1), 'add': 2})
Call(name=inner, saved_arguments={'x': range(0, 2), 'add': 3})
Call(name=inner, saved_arguments={'x': range(0, 3), 'add': 4})
我覺得我已經接近了,而inspect
庫應該可以幫助我解決這個問題,但是一點幫助將不勝感激!
您要查找的功能是Signature.bind
。 定義wrapper
函數,如下所示:
@functools.wraps(func)
def wrapper(*func_args, **func_kwargs):
signature = inspect.signature(func)
bound_args = signature.bind(*func_args, **func_kwargs)
saved_arguments = {a: bound_args.arguments[a] for a in save_args_names}
log.add(Call(name, **saved_arguments))
return_value = func(*func_args, **func_kwargs)
return return_value
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.