python装饰器系列(六)

可调用对象

在python中可以用callable函数查看一个对象是不是可调用

1 def fn():
2     print('ha ha ha')
1 callable(fn)
2 True

输出为True,函数当然是一个可调用对象,如果是一个类呢?

1 class Fun:
2     def __init__(self,name):
3         self.name = name
4 
5 f = Fun('zhaochj')
1 callable(f)
2 False

如上,一个类被实例化后,这个实例对象是一个不可调用对象

有什么方法能让一个实例对象变成可调用对象呢?做如下修改:

1 class Fun_1:
2     def __init__(self,name):
3         self.name = name
4         
5     def __call__(self):
6         print('my name is {0}'.format(self.name))
1 f1 = Fun_1('zhaochj')
2 
3 callable(f1)
4 True

f1这个实例现在已是一个可调用对象了。所以只要一个类中实现了__call__方法,那么类实例就是一个可调用对象

1 f1()
2 my name is zhaochj

事实证明,调用此实例对象也就是执行了__call__方法。既然是可调用对象,就可以向调用函数一样传递参数来调用,只要在__call__方法中定义可接收参数即可。

类通过实现__call__方法可以让实例变成一个可调用对象,如果我们向这个可调用对象传递一个函数作为其参数,那__call__函数就可以写成一个装饰器

 1 import functools
 2 class InjectUser:
 3     def __init__(self,default_user):
 4         self.user = default_user
 5         
 6     def __call__(self,fn):
 7         @functools.wraps(fn)
 8         def wrap(*args,**kwargs):
 9             if 'user' not in kwargs.keys():
10                 kwargs['user'] = self.user
11             return fn(*args,**kwargs)
12         return wrap
1 @InjectUser('zhaochj')
2 def do_somthings(*args,**kwargs):
3     print(kwargs.get('user'))
1 do_somthings()
2 zhaochj

对上述的代码进行分析:

1 def __call__(self,fn):
2         @functools.wraps(fn)
3         def wrap(*args,**kwargs):
4             if 'user' not in kwargs.keys():
5                 kwargs['user'] = self.user
6             return fn(*args,**kwargs)
7         return wrap

上边的代码是定义一个装饰器

1 @InjectUser('zhaochj')
2 def do_somthings(*args,**kwargs):
3     print(kwargs.get('user'))

这里的魔法等价执行了InjectUser('zhaochj')(do_somthings),实质是返回装饰器的wrap函数。执行do_somthings()时,实质是执行了wrap(),并返回fn(*args,**kwargs),到这里才真正执行函数中的print语句

1 def do_somthings(*args,**kwargs):
2     print(kwargs.get('user'))

猜你喜欢

转载自www.cnblogs.com/tianshug/p/10922051.html
今日推荐