gpt4 book ai didi

python - 装饰器类和缺少必需的位置参数

转载 作者:太空宇宙 更新时间:2023-11-03 20:37:21 24 4
gpt4 key购买 nike

我在使用包装类时遇到问题,并且无法弄清楚我做错了什么。我该如何让该包装器与带有“self”参数的任何类函数一起使用?

这适用于 Python 3.7.3。问题是我记得包装器以前工作过,但似乎有些东西发生了变化……也许我现在只是做错了一些事情,而以前没有。

class SomeWrapper:

def __init__(self, func):
self.func = func

def __call__(self, *args, **kwargs):
# this fails because self is not passed
# ERROR: __init__() missing 1 required positional argument: 'self'
func_ret = self.func(*args, **kwargs)

# this is also wrong, because that's the wrong "self"
# ERROR: 'SomeWrapper' object has no attribute 'some_func'
# func_ret = self.func(self, *args, **kwargs)

return func_ret


class SomeClass:

SOME_VAL = False

def __init__(self):
self.some_func()
print("Success")

@SomeWrapper
def some_func(self):
self.SOME_VAL = True

def print_val(self):
print(self.SOME_VAL)


SomeClass().print_val()

最佳答案

所以,在 python 3 中,方法声明作为方法工作,当它们只是在类体内定义为函数时,会发生的情况是该语言使用“描述符协议(protocol)”。

简单地说,普通方法只是一个函数,直到从实例中检索它为止:由于该函数具有 __get__ 方法,因此它们被识别为描述符,并且 __get__ 方法负责返回一个“部分函数”,即“绑定(bind)方法”,并且在调用时会插入 self 参数。如果没有 __get__ 方法,则从实例检索 SomeWrapper 的实例时,没有有关该实例的信息。

简而言之,如果要对方法使用基于类的装饰器,则不仅需要编写 __call__,还需要编写 __get__ 方法。这应该足够了:


from copy import copy

class SomeWrapper:

def __init__(self, func):
self.func = func

def __call__(self, *args, **kwargs):

func_ret = self.func(self.instance, *args, **kwargs)

return func_ret

def __get__(self, instance, owner):
# self here is the instance of "somewrapper"
# and "instance" is the instance of the class where
# the decorated method is.
if instance is None:
return self
bound_callable = copy(self)
bound_callable.instance = instance
return self

除了复制装饰器实例之外,这也可以工作:

from functools import partial

class SomeWrapper:
...

def __call__(self, instance, *args, **kw):
...
func_ret = self.func(instance, *args, **kw)
...
return func_ret

def __get__(self, instance, owner):
...
return partial(self, instance)

“部分”和 self 的副本都是可调用的,它们“知道”它们来自哪些实例“__got__”。

简单地在装饰器实例中设置 self.instance 属性并返回 self 也可以,但仅限于一次使用该方法的单个实例。在具有一定并行性的程序中,或者即使代码会检索一个方法来延迟调用它(例如将其用于回调),它也会以一种壮观且难以调试的方式失败,因为该方法将接收 其“self”参数中的另一个实例。

关于python - 装饰器类和缺少必需的位置参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57086840/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com