我有这样的方法装饰器。
class MyClass:
def __init__(self):
self.start = 0
class Decorator:
def __init__(self, f):
self.f = f
self.msg = msg
def __get__(self, instance, _):
def wrapper(test):
print(self.msg)
print(instance.start)
self.f(instance, test)
return self.f
return wrapper
@Decorator
def p1(self, sent):
print(sent)
c = MyClass()
c.p1('test')
这很好用。但是,如果我想将参数传递给装饰器,则该方法不再作为参数传递,我收到此错误:
TypeError: init ()缺少1个必需的位置参数:'f'
class MyClass:
def __init__(self):
self.start = 0
class Decorator:
def __init__(self, f, msg):
self.f = f
self.msg = msg
def __get__(self, instance, _):
def wrapper(test):
print(self.msg)
print(instance.start)
self.f(instance, test)
return self.f
return wrapper
@Decorator(msg='p1')
def p1(self, sent):
print(sent)
@Decorator(msg='p2')
def p2(self, sent):
print(sent)
如何将参数传递给装饰器类,为什么它会覆盖该方法?
答案 0 :(得分:2)
装饰者称为。
在您的情况下,您会在__call__
方法
class MyClass:
def __init__(self):
self.start = 0
class Decorator:
def __init__(self, msg):
self.msg = msg
def __call__(self, f):
self.f = f
return self
def __get__(self, instance, _):
def wrapper(test):
print(self.msg)
self.f(instance, test)
return self.f
return wrapper
@Decorator(msg='p1')
def p1(self, sent):
print(sent)
@Decorator(msg='p2')
def p2(self, sent):
print(sent)
您的第一个示例有效,因为调用Class
会创建一个实例,而该函数就是参数。
但是在你的第二个例子中,你手动调用Class
来设置msg
参数,所以装饰过程会调用左边的内容,即:实例,然后转到__call__
方法
答案 1 :(得分:2)
描述符协议在这里没有多大用处。您只需将函数本身传递给__call__
并返回包装函数,而不会失去对实例的访问权限:
class MyClass:
def __init__(self):
self.start = 0
class Decorator:
def __init__(self, msg):
self.msg = msg
def __call__(self, f):
def wrapper(instance, *args, **kwargs):
print(self.msg)
# access any other instance attributes
return f(instance, *args, **kwargs)
return wrapper
@Decorator(msg='p1')
def p1(self, sent):
print(sent)
>>> c = MyClass()
>>> c.p1('test')
p1
test
答案 2 :(得分:1)
当您使用参数调用装饰器时,您调用的函数实际上并不是作为装饰器本身工作。相反,它是一个装饰工厂(一个函数或其他可调用的return
将作为装饰器的东西)。通常,您可以通过添加额外级别的嵌套函数来解决此问题。既然你要用一个类来定义你的装饰器,那么直接做这个有点尴尬(尽管你可能会使它工作)。但是,只要你在包装函数中处理self
(现在它将是MyClass的instance
,而且你的装饰器是否真的需要成为一个类似乎没有任何需要而不是Decorator
类的实例:
class MyClass:
def __init__(self):
self.start = 0
def decorator_factory(msg):
def decorator(f):
def wrapper(self, test): # you might want to replace test with *args and **kwargs
print(msg)
print(self.start)
return f(self, test)
return wrapper
return decorator
@decorator_factory(msg='p1')
def p1(self, sent):
print(sent)
@decorator_factory(msg='p2')
def p2(self, sent):
print(sent)
我按照我的方式命名装饰工厂,以明确不同级别的嵌套函数,但是你当然应该使用对你的用例有意义的东西作为顶级名称。您可能还希望将其移出类名称空间,因为它可以调用MyClass
的所有实例(可能有愚蠢的结果,因为它不是一个方法)。 / p>