我正在尝试添加一个装饰器,该装饰器将可调用属性添加到函数中,这些函数返回的对象与该函数的返回值略有不同,但将在某个时候执行该函数。
我遇到的问题是,当函数对象传递到装饰器中时,它是未绑定的,并且不包含隐式self
参数。当我调用创建的属性函数(即string()
)时,我无权访问self
,也无法将其传递给原始函数。
def deco(func):
"""
Add an attribute to the function takes the same arguments as the
function but modifies the output.
"""
def string(*args, **kwargs):
return str(func(*args, **kwargs))
func.string = string
return func
class Test(object):
def __init__(self, value):
self._value = 1
@deco
def plus(self, n):
return self._value + n
当我执行装饰器创建的属性时,这是我得到的错误,因为其中args
不包含self
引用。
>>> t = Test(100)
>>> t.plus(1) # Gets passed self implicitly
101
>>> t.plus.string(1) # Does not get passed self implicitly
...
TypeError: plus() takes exactly 2 arguments (1 given)
有没有一种方法可以创建这样的装饰器,以获取参考self
?还是有一种方法可以绑定添加的属性函数(string()
),以便它也可以使用隐式self
参数来调用?
您可以在此处使用描述符:
class deco(object):
def __init__(self, func):
self.func = func
self.parent_obj = None
def __get__(self, obj, type=None):
self.parent_obj = obj
return self
def __call__(self, *args, **kwargs):
return self.func(self.parent_obj, *args, **kwargs)
def string(self, *args, **kwargs):
return str(self(*args, **kwargs))
class Test(object):
def __init__(self, value):
self._value = value
@deco
def plus(self, n):
return self._value + n
以便:
>>> test = Test(3)
>>> test.plus(1)
4
>>> test.plus.string(1)
'4'
这值得解释。deco
是一个装饰器,但它也是一个描述符。描述符是定义替代行为的对象,当该对象作为其父对象的属性查找时,将调用该行为。有趣的是,界限方法本身是使用描述符协议实现的
满嘴 让我们看看运行示例代码时会发生什么。首先,当定义plus
方法时,我们应用deco
装饰器。现在通常我们将函数视为修饰器,并且该函数的返回值是修饰的结果。在这里,我们使用一个类作为装饰器。其结果是,Test.plus
不是一个函数,而是一个实例的的deco
类型。该实例包含对plus
我们希望包装的函数的引用。
本deco
类有一个__call__
方法,允许它的实例表现得像功能。此实现只是将给定的参数传递给plus
它具有引用的功能。请注意,第一个参数将是对Test
实例的引用。
棘手的部分来自于实现test.plus.string(1)
。为此,我们需要引用test
该plus
实例是属性的实例。为此,我们使用描述符协议。也就是说,我们定义了一个__get__
方法,只要deco
实例被访问为某个父类实例的属性,该方法就会被调用。发生这种情况时,它将父对象存储在其内部。然后,我们可以简单地实现plus.string
为deco
类的方法,并使用对deco
实例中存储的父对象的引用来获取所属的test
实例plus
。
这是很多魔术,所以这里有一个免责声明:尽管这看起来很酷,但是实现这样的东西可能不是一个好主意。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句