1.魔法方法__call__是什么
不妨先看下面一个例子:
def foo1():
print('hello python')
print(dir(foo1))
dir()内置函数不多说,结果如下:
['__call__', '__class__', '__closure__', '__code__', '__defaults__',.....省略]
注意这里第一个就是本文的主题,说明了该对像foo1是一个可调用对象,也就是报错时可能常见的callable object。 再举个例子如下:
class foo(object):
def __init__(self):
self.name = 'python'
def foo1(self):
print('hello%s'%self.name)
print(dir(foo))
结果如下:
['__class__', '__delattr__', '__dict__', '__doc__',省略]
发现没有__call__()方法,说明当前的foo对象不是可以调用的,强制调用会出现如下错误
instance = foo()
instance()
>>Traceback (most recent call last):
instance()
TypeError: 'foo' object is not callable
这也是函数和类的一个区别,为了使得类/实例能够像函数一样使用,成为可调用对象,call()魔法方法出现了。 将类中定义一个__call__()方法如下:
class foo(object):
def __init__(self):
self.name = 'python'
def __call__(self, *args, **kwargs):
print('hello%s'%self.name)
instance = foo()
instance()
a = instance
print dir(a)
输出结果如下:
hellopython
['__call__', '__class__', '__delattr__', '__dict__',太长省略]
说明了该魔法方法能够使得一个实例变得可调用,像函数一样。
2.有什么用
看到这里,很多人觉得没什么实际用途啊,对于一个类,我单纯的实例化,然后通过实例对象调用类中的方法不就可以吗,定义个__call__然后使他可调用有什么用? 其实,对于简单的程序或者项目有些画蛇添足,但是,该方法最重要的用途就是将类/实例对象变成函数,变成可调用对象,函数相对于类/实例对象的方便之处就在于不需要实例化,随时只要传参就能使用。而__call__方法就是将类的实例对象变成函数。 看下面的例子:
class Pipe(object):
def __init__(self, fn):
self.fn = fn
def __ror__(self, other):
return self.fn(other)
def __call__(self, *args, **kwargs):
op = Pipe(lambda x: self.fn(x, *args, **kwargs))
return op
可以这样使用
@Pipe
def sort(data, cmp=None, key=None, reverse=False):
return sorted(data, cmp=cmp, key=None, reverse=reverse)
[{'score': 1}, {'score': 3}, {'score': 2}] | sort(key=lambda x: x['score'])
在这里类 Pipe 被当作一个装饰器使用,众所周知,装饰器本身是一个函数,这里一个类作为了装饰器,那么就需要将其变为函数的可调用形式,那么__call__方法就起作用了。 所以 sort 函数的原始定义被传递给 Pipe中的__init__魔法方法,构造出一个 Pipe 实例,该实例在__call__方法作用下变为了一个函数,所以这个类能够作为函数来被装饰sort 函数,这里python管道符请移步自行学习。 除此之外,在一些 ORM 框架或者项目中,__call__方法很重要,经常查看源码的同学应该经常能够看到该方法。举个例子,在需要实例化且全局单例的情况下,通过直接导入该实例对象,就可以在其他程序中减少携带的参数,并且无需再实例化操作,变得和函数一样方便使用。
|