看下面一个案例:
class my_decorate(object):
def __init__(self, f):
"""
如果装饰器不带参数,函数需要作为参数传递给这个类的构造器
"""
print("进入到 __init__")
self.f = f
def __call__(self, *args):
print("进入 __call__")
self.f(*args)
print("结束 __call__")
@my_decorate
def myFunction(arg1, arg2):
print('myFunction arguments:', arg1, arg2)
print("开始调用myfunction")
myFunction("say", "hello")
myFunction("hello", "again")
输出:
进入到 __init__
开始调用myfunction
进入 __call__
myFunction arguments: say hello
结束 __call__
进入 __call__
myFunction arguments: hello again
结束 __call__
注意,这里__init__只被调用了一次,进一步印证了上一节的说法,用类作为装饰器会先得到类实例,然后再去执行类实例。这里执行过程等价于:
myDecorate = my_decorate(myFunction)
myDecorate('say', 'hello')
myDecorate('hello', 'again')
试试打印出myFunction的类型print(type(myFunction)),返回的其实是my_decorate类型,被装饰器修饰的函数最终类型实际上是装饰器本身。
装饰器带参数后结构发生了较大的变化,这时__init__方法中的参数是装饰器的参数而不是函数,使用函数作为参数是在__call__方法中,而且__call__方法需要返回可调用对象。
class my_decorate(object):
def __init__(self, arg1, arg2, arg3):
print("进入 __init__()")
self.arg1 = arg1
self.arg2 = arg2
self.arg3 = arg3
def __call__(self, f):
print("进入 __call__()")
def wrapped_f(*args):
print("进入 wrapped_f()")
print("装饰器参数:", self.arg1, self.arg2, self.arg3)
f(*args)
print('执行完函数myfunction')
return wrapped_f
@my_decorate("hello", "world", 1)
def myFunction(*args):
if len(args) > 0:
print('this is myFunction args: %s' % str(args))
else:
print('this is myFunctions')
myFunction('hello', 'myfunction')
myFunction()
输出:
进入 __init__()
进入 __call__()
进入 wrapped_f()
装饰器参数: hello world 1
this is myFunction args: ('hello', 'myfunction')
执行完函数myfunction
进入 wrapped_f()
装饰器参数: hello world 1
this is myFunctions
执行完函数myfunction
因为装饰器有了参数,所以这个时候不能在__init__中接收函数作为参数。类比于装饰器无参的时候,当传递函数作为参数时返回的应该是一个可调用对象(在装饰器无参案例中,函数是传递到__init__方法中,等到的是myDecorate实例,myDecorate实例有实现__call__方法,所以是可调用的),而这个时候,函数参数是传递给了__call__方法,所以在__call__方法中返回了wrapped_f这个函数,函数肯定是可调用的。这个过程等价于:
myDecorate = my_decorate("hello", "world", 1)
wrapped_f = myDecorate(f)
wrapped_f('hello', 'myfunction')
wrapped_f()
本人是做大数据开发的,在微信上开了个个人号,会经常在上面分享一些学习心得,原创文章都会首发到公众号上,感兴趣的盆友可以关注下哦!
备注:微信公众号搜索‘大数据入坑指南’