可调用对象
在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'))