python 中的装饰器:class 和基于函数的装饰器中 args 解释的差异
Decorators in python: Difference in the args interpretation in class and function based decorators
我正在尝试在 python 中创建通用函数生命周期处理程序。
工作简介:
- 记录签名和 return 值。
- 在重试或不重试的情况下处理异常。
- 在异常情况下提供清理。
我在清理时遇到的问题如下:
基于函数的装饰器:
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实例中,按照提供的方法进行清理。
例如:
使用第三方存储一些信息API。
如果出现异常,传递的清理操作将调用
删除 API.
class Test:
def __init__(self,data):
self.main_data=data
@handler(exception=Exception,cleanup=lambda x:print(f"Cleaning data:{x.main_data}"))
def test_data(self):
print(f'Data is :{self.main_data}')
i=1/0
输出:
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__
。在其参数中,self
是 LifeCycleHandler
的实例,而 obj
是 t
(Test
的实例)。 __get__
返回了一个可调用函数 (__call__
),其中第一个参数部分由 obj
.
提供
我正在尝试在 python 中创建通用函数生命周期处理程序。 工作简介:
- 记录签名和 return 值。
- 在重试或不重试的情况下处理异常。
- 在异常情况下提供清理。
我在清理时遇到的问题如下: 基于函数的装饰器:
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实例中,按照提供的方法进行清理。 例如:
使用第三方存储一些信息API。
如果出现异常,传递的清理操作将调用 删除 API.
class Test: def __init__(self,data): self.main_data=data @handler(exception=Exception,cleanup=lambda x:print(f"Cleaning data:{x.main_data}")) def test_data(self): print(f'Data is :{self.main_data}') i=1/0
输出:
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__
。在其参数中,self
是 LifeCycleHandler
的实例,而 obj
是 t
(Test
的实例)。 __get__
返回了一个可调用函数 (__call__
),其中第一个参数部分由 obj
.