【发布时间】:2021-10-24 01:48:07
【问题描述】:
我正在尝试编写一个快速装饰器来管理各种函数的日志记录返回。我不是非常精通装饰器,所以您可以提供的任何帮助都会非常有帮助!
from functools import update_wrapper
from typing import Any, Optional
from logging import getLogger
from time import perf_counter
from datetime import datetime
class logger:
def __init__(self, func:callable, response:str = "debug"):
self.logger = getLogger()
self.func = func
self.response = response
update_wrapper(self, func)
def __call__(self, *args, **kwargs):
return getattr(self, self.response)
def debug(self, *args, **kwargs):
self.logger.debug(f"Running {__name__} with id: {id(self)} at {datetime.now()}")
start = perf_counter()
value = self.func(*args, **kwargs)
end = perf_counter()
self.logger.debug(f"""Completed {__name__} with id: {id(self)} at {datetime.now()}.
Total Time to run: {end - start:.6f}s""")
return value
def info(self, *args, **kwargs):
self.logger.info(f"Running {__name__} at {datetime.now()}.")
return self.func(*args, **kwargs)
@logger(response="debug")
def stuff(x):
return x*x
stuff(2)
我收到的错误是:
TypeError: __init__() missing 1 required positional argument: 'func',
显然,它不喜欢所需的可调用对象和响应要求。但是,我在所有其他基于类的装饰器设置中看到 func 需要作为 __init__ 的一部分调用,而且我还看到您可以传递装饰器添加信息。我在这里做错了什么?
编辑:
getattr(self, self.response) 的目的是使__call__ 返回的函数是与debug 或info 日志记录一起使用的函数。这允许我使用装饰器 @logging 进行日志记录和调试,但会根据装饰器中指定的响应值(即 @logging(response="info"))产生两种不同的结果。
解决方案:
class logger:
def __init__(self, response:str = "debug"):
self.logger = getLogger()
self.response = response
def __call__(self, func:callable):
update_wrapper(self, func)
self.func = func
return getattr(self, self.response)
def debug(self, *args, **kwargs):
self.logger.debug(f"Running {self.func.__name__} (type:{type(self.func)}) with id: {id(self)} at {datetime.now()}")
start = perf_counter()
value = self.func(*args, **kwargs)
end = perf_counter()
self.logger.debug(f"""Completed {self.func.__name__} with id: {id(self)} at {datetime.now()}.
Total Time to run: {end - start:.6f}s""")
return value
def info(self, *args, **kwargs):
self.logger.info(f"Running {self.func.__name__} at {datetime.now()}.")
return self.func(*args, **kwargs)
【问题讨论】:
-
func 应该是 call.... 的参数,并且 call 的参数应该以某种方式重新调整。可以尝试制作所需语法的示例吗?
-
查看发生了什么撤消 @at stuff 函数并在其声明后运行
logger(stuff)(7)。错误消失。然后你必须正确地重新实现装饰器 -
@cards,我想这是让我感到困惑的部分。
logger(stuff)(7)显然有效。包装部分 @ 创建它的logger(stuff)方面吗?然后,当您拨打stuff(7)时,您实际上是在拨打logger(stuff)(7)。 -
您必须跟踪类中方法的“调用”顺序:先是
__init__,然后是__call__。像@my_decorator 这样的装饰器方面作为要调用的函数的下一个参数。如果装饰器接受参数 @my:decorator2( some_args) 那么下一个应该再次是一个函数。注意顺序以及是否需要参数 -
最后的调用将执行装饰!所以它应该只包含func作为参数(最终**kwargs...你可以测试它)
标签: python class decorator python-decorators python-3.8