我能改进它的打字吗?你还会做什么其他的改善或仿生改变吗?
F = TypeVar('F', bound=Callable[..., Any])
# This is mostly so that I practice using a class as a decorator.
class CountCalls:
"""Logs to DEBUG how many times a function gets called, saves the result in a newly created attribute `num_calls`."""
def __init__(self, func: F) -> None:
functools.update_wrapper(self, func)
self.func = func
self.num_calls: int = 0
self._logger = logging.getLogger(__name__ + '.' + self.func.__name__)
self.last_return_value = None
def __call__(self, *args: Any, **kwargs: Any) -> Any:
self.num_calls += 1
self._logger.debug(' called %s times', self.num_calls)
self.last_return_value = self.func(*args, **kwargs)
return self.last_return_value
下面是装修师的作品:
>>> @CountCalls
... def asdf(var: str):
... print(var)
... return len(var)
...
>>> asdf('Laur')
Laur
4
DEBUG:__main__.asdf: called 1 times
>>> asdf('python 3')
DEBUG:__main__.asdf: called 2 times
python 3
8
>>> asdf(3)
DEBUG:__main__.asdf: called 3 times
3
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "C:/Projects/Python/he/src/he/decorators.py", line 156, in __call__
self.last_return_value = self.func(*args, **kwargs)
File "<input>", line 4, in asdf
TypeError: object of type 'int' has no len()
>>> asdf.num_calls
3
发布于 2019-03-10 08:57:35
您可以尝试改进类型的一件事是键入方法本身(虽然我不确定工具对它的支持程度)。另外,引导/尾随空格应该由记录器来决定,而不是使用它的代码。
F = TypeVar('F', bound=Callable[..., Any])
# This is mostly so that I practice using a class as a decorator.
class CountCalls:
"""Logs to DEBUG how many times a function gets called, saves the result in a newly created attribute `num_calls`."""
def __init__(self, func: F) -> None:
functools.update_wrapper(self, func)
self.func = func
self.num_calls: int = 0
self._logger = logging.getLogger(__name__ + '.' + self.func.__name__)
self.last_return_value = None
__call__: F
def __call__(self, *args: Any, **kwargs: Any) -> Any:
self.num_calls += 1
self._logger.debug(f'called %s times', self.num_calls)
self.last_return_value = self.func(*args, **kwargs)
return self.last_return_value
至于代码本身,您可以创建一个基于回调的API。
F = TypeVar('F', bound=Callable[..., Any])
# This is mostly so that I practice using a class as a decorator.
class CountCalls:
"""Logs to DEBUG how many times a function gets called, saves the result in a newly created attribute `num_calls`."""
def __init__(self, func: F, callback: Optional[Callable[[int, Tuple[Any], Dict[str, Any]], Any]] = None) -> None:
if callback is None:
logger = logging.getLogger(__name__ + '.' + self.func.__name__)
def callback(num_calls: int, args: Tuple[Any], kwargs: Dict[str, Any]):
self._logger.debug(f'called %s times', self.num_calls)
functools.update_wrapper(self, func)
self.func = func
self.callback = callback
self.num_calls: int = 0
self.last_return_value = None
__call__: F
def __call__(self, *args: Any, **kwargs: Any) -> Any:
self.num_calls += 1
self.callback(self.num_calls, args, kwargs)
self.last_return_value = self.func(*args, **kwargs)
return self.last_return_value
或者使用回调中跟踪的呼叫数量(为了提高灵活性):
F = TypeVar('F', bound=Callable[..., Any])
# This is mostly so that I practice using a class as a decorator.
class CountCalls:
"""Logs to DEBUG how many times a function gets called, saves the result in a newly created attribute `num_calls`."""
def __init__(self, func: F, callback: Optional[Callable[[int, Tuple[Any], Dict[str, Any]], Any]] = None) -> None:
if callback is None:
logger = logging.getLogger(__name__ + '.' + self.func.__name__)
num_calls: int = 0
def callback(args: Tuple[Any], kwargs: Dict[str, Any]):
nonlocal num_calls # Not sure if this is necessary or not
num_calls += 1
self._logger.debug(f'called %s times', self.num_calls)
functools.update_wrapper(self, func)
self.func = func
self.callback = callback
self.last_return_value = None
__call__: F
def __call__(self, *args: Any, **kwargs: Any) -> Any:
self.callback(self.num_calls, args, kwargs)
self.last_return_value = self.func(*args, **kwargs)
return self.last_return_value
更早的时候,为了在使用关键字时传递关键字参数,需要使用@functools.partial(CountCalls, callback=callback)
。现在,可以使用@CountCalls(callback=callback)
代替。
F = TypeVar('F', bound=Callable[..., Any])
# This is mostly so that I practice using a class as a decorator.
class CountCalls:
"""Logs to DEBUG how many times a function gets called, saves the result in a newly created attribute `num_calls`."""
def __init__(self, func: F = None, callback: Optional[Callable[[int, Tuple[Any], Dict[str, Any]], Any]] = None) -> None:
if callback is None:
logger = logging.getLogger(__name__ + '.' + self.func.__name__)
num_calls: int = 0
def callback(args: Tuple[Any], kwargs: Dict[str, Any]):
nonlocal num_calls # Not sure if this is necessary or not
num_calls += 1
self._logger.debug(f'called %s times', self.num_calls)
if func is None:
return functools.partial(CountCalls, callback=callback)
functools.update_wrapper(self, func)
self.func = func
self.callback = callback
self.last_return_value = None
__call__: F
def __call__(self, *args: Any, **kwargs: Any) -> Any:
self.callback(self.num_calls, args, kwargs)
self.last_return_value = self.func(*args, **kwargs)
return self.last_return_value
(注意:这些代码都没有经过测试。)
https://codereview.stackexchange.com/questions/215135
复制相似问题