2017-07-27 57 views
0

我有一个装饰器,我在类方法上使用。不过,我想使用相同的装饰,而是作为包装。使用装饰器作为包装

例如,这一点我如何使用装饰:

myDecorators.py

def authenticate(method): 
    def authenticate_and_call(service_instance, *args, **kwargs): 
     print("Authentification success") 
     #access to service_instance is needed in the decorator 
     print(service_instance.config) 
     return method(service_instance, *args, **kwargs) 

    return authenticate_and_call 

myClass.py

from myDecorators import authenticate 

class MyService: 
    def __init__(self, config): 
     self.config = config 

    @authenticate #I dont want to use a decorator here 
    def execute(self): 
     print(self.config) 
     print("MyService is executed with authentication") 

我想什么做的是什么如:

service_callers.py

from myClass import MyService 
from myDecorators import authenticate 

#use the decorator as a wrapper 
def execute_service_with_authentification(): 
    service = MyService({"foo":"bar"}) 
    authenticate(service.execute)(service) 

execute_service_with_authentification() 

这将返回以下错误:

File "c:\temp\test\myDecorators.py", line 4, in authenticate_and_call 
    return method(service_instance, *args, **kwargs) 
TypeError: execute() takes exactly 1 argument (2 given) 

回答

2

首先从MyService.execute definiton删除@authenticate装饰。然后,当您需要使用authenticate装饰者时,请将您的电话打包为:authenticate(service.execute)()

确保你改变你的装饰以及 - 你不及格的第一个参数是自:

def authenticate(method): 
    def authenticate_and_call(*args, **kwargs): 
     print("Attempting authentication on object: {}".format(method.__self__)) 
     return method(*args, **kwargs) 
    return authenticate_and_call 
+0

@BelowtheRadar - 从包装中移除'service_instance',只是通过相同ARGS/kwargs你给包装函数。 – zwer

+1

@BelowtheRadar - 我已经添加了上面更改的装饰器。由于我们将它传递给一个实例方法,因此它不需要第一个参数。上面的内容适用于你的结构,并且也适用于你想传递的任何参数(注意'裸体'电话,因为它在我原来的答案中,我最初并没有看着装饰者) – zwer

+1

@BelowtheRadar - 你不喜欢不需要访问它,你传递的方法已经绑定到'service'实例。但是,如果你在实际调用方法之前需要对它做些什么,你可以从它的绑定方法中'提取':'method .__ self__'。检查上面的更新。 – zwer