使用基类时将装饰器应用于类函数

问题描述 投票:0回答:1

我正在尝试构建一个装饰器,它允许我在 Python3 的类中记录函数。装饰器如下:

import functools
def log(_func=None, *, logger):
    def decorator_log(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            try:
                logger.info(f"Entering function {func.__qualname__}")
                args_repr = [repr(a) for a in args]
                kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]
                signature = ", ".join(args_repr + kwargs_repr)
                logger.debug(f"function {func.__qualname__} called with args {signature}")
                try:
                    result = func(*args, **kwargs)
                    return result
                except Exception as e:
                    logger.exception(f"Exception raised in {func.__qualname__}. exception: {str(e)}")
                    raise e
                logger.info(f"Leaving function {func.__qualname__}.{func.__name__}")
            except Exception:
                pass
        return wrapper

    if _func is None:
        return decorator_log
    else:
        return decorator_log(_func)

然后用它来装饰类函数,如下所示:

class MainController(BaseController):
    logger = logging.getLogger(__name__)
    def __init__(self, main_model, main_view):
        ...

    @log(logger=logger)
    def initialize_components(self):
        ...

等等

这工作正常,但当我使用基类和子类时会遇到问题。特别是,我想装饰基类和子类中的几乎所有函数,但是当我这样做时,只有当子类重写基类方法时,

func.__qualname__
才会是
subclass.methodname
,并且它将是
baseclass.methodname 
否则。

如何修改此方法,以便即使在子类不重写基类方法的情况下,应用于基类方法的装饰器也会在装饰器调用

subclass.methodname
的地方给我
func.__qualname__
,而不是基类?

我不想在类级别装饰它,因为在某些情况下,标准库类有多个继承级别,我只想装饰我自己定义的函数。

python-3.x inheritance logging python-decorators
1个回答
1
投票

不用

func.__qualname__
,只需使用类名和
__name__
属性:

def wrapper(*args, **kwargs):
    self = args[0]  #  this will only work for methods
    ...
    name = "self.__class__.__name__}.{func.__name__}"
    logger.debug(f"function {name} called with args {signature}")
    ...

当然,如果您希望将装饰器应用于“独立”函数,那么第一个参数(

args[0]
,如果它存在)将不会是对实例的引用:您必须调整上面的代码来检查这一点,相应地计算
name

© www.soinside.com 2019 - 2024. All rights reserved.