python 中的装饰器:class 和基于函数的装饰器中 args 解释的差异

Decorators in python: Difference in the args interpretation in class and function based decorators

我正在尝试在 python 中创建通用函数生命周期处理程序。 工作简介:

我在清理时遇到的问题如下: 基于函数的装饰器:

def handler(exception=Exception,cleanup=None):
def func_wrapper(func):
    def wrapper(*args,**kwargs):
        response=None
        try:
            print(args)
            response=func(*args,**kwargs)
        except exception as ex:
            print(f'Exception occurred:{str(ex)}\nCleaning up resources')
            #Passing the object for cleanup, it fails for class based decorators as it does not passes self as argument
            cleanup(args[0])
        return response
    return wrapper
return func_wrapper

需要清理的数据存放在class实例中,按照提供的方法进行清理。 例如:

输出:

Exception occurred:division by zero
Cleaning up resources
Cleaning:John Doe

我更倾向于基于 Class 的装饰器。

class LifeCycleHandler:
    def __init__(self,*,func=None,exception=Exception,cleanup=None):
        self.__exception=exception
        self.__cleanup=cleanup
        self.__func=func

    def __call__(self,*args,**kwargs):
        response=None
        try:
            print(args)
            response=self.__func(*args,**kwargs)
        except self.__exception as ex:
            print(f'Exception occurred:{str(ex)}\n cleaning up resources')
            #Passing the object for cleanup
            self.__cleanup(args[0])
        return response
def lifecycle_handler(exception=Exception,cleanup=None):
    def wrapper(func): 
        response=LifeCycleHandler(func=func,exception=exception,cleanup=cleanup)
        return response
    return wrapper

使用具有类似功能的基于 class 的装饰器时,我遇到了以下错误:

()
Exception occurred:test_data() missing 1 required positional argument: 'self'
 cleaning up resources
Traceback (most recent call last):
  File "test.py", line 27, in __call__
    response=self.__func(*args,**kwargs)
TypeError: test_data() missing 1 required positional argument: 'self'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 54, in <module>
    test.test_data()
  File "test.py", line 31, in __call__
    self.__cleanup(args[0])
IndexError: tuple index out of range

有人可以指导我关于可调用 classes 的参数解释吗?

如果我的评论正确,您可以将 __get__ 添加到 LifeCycleHandler

def __get__(self, obj, type=None):
    return functools.partial(self.__call__, obj)

这将使test_data成为非数据描述符。我假设您已经知道 descriptor。如果没有,绝对值得检查一下。

回到你的问题,从追溯来看,你假设 python 将帮助你将作为 Test 的实例的调用者实例作为第二个参数传递给 __call__。这不是真的。然而,在 __get__.

中确实如此

您的核心逻辑(try/except 块)需求是:

  • Test 的实例,因为您需要访问 main_data
  • LifeCycleHandler 中的实例,因为您需要访问您的 self.__func.
  • 参数在 __get__ 中是不可接受的,但您可以在 __call__ 中使用它们。

比如你有下面的测试代码:

t = Test(123)
t.test_data()

t.test_data 将调用 __get__。在其参数中,selfLifeCycleHandler 的实例,而 objtTest 的实例)。 __get__ 返回了一个可调用函数 (__call__),其中第一个参数部分由 obj.

提供