前言
最近有許多朋友私信問我,Python的可調用對象到底有什麼用處,爲什麼要費事的重載括號而不是直接綁定類的普通方法。下面就來爲大家分享__call__可調用對象的一些感悟。
精簡代碼,方便接口調用的“約定俗成”
class route(object):
def __init__(self, res)
self.resource = res
@classmethod
def factory(cls):
print 'factory'
return cls()
@webob.dec.wsgify
def __call__(self,req):
print 'route __call__'
return self.resource()
class resource(object):
@webob.dec.wsgify
def __call__(self,req):
print 'resource __call__'
class API(route):
def __init__(self):
res = resource()
super(API, self).__init__(res)
wsgi.server(eventlet.listen(('', 80)), API.factory())
上面的代碼是一個典型的WSGI服務的節選,如果不用__call__,那麼我們各組件之間可能要約定或規範一個接口,比如下面,大家都叫notcall()。。。
class route(object):
def __init__(self, res)
self.resource = res
@classmethod
def factory(cls):
print 'factory'
return cls()
@webob.dec.wsgify
def notcall(self,req):
print 'route notcall'
return self.resource.notcall()
class resource(object):
@webob.dec.wsgify
def notcall(self,req):
print 'resource notcall'
class API(route):
def __init__(self):
res = resource()
super(API, self).__init__(res)
wsgi.server(eventlet.listen(('', 80)), API.factory().notcall())
這樣用起來就非常麻煩,模塊之間合作要約定好接口的名字,編寫記憶許多接口文檔,增加代碼量且容易出錯。
只是想要函數,卻能完成不只是函數的工作
類似上面的代碼,許多模塊的接口的參數都是需要一個函數調用,比如這個wsgi.server(port, app),第二個參數就是一個實際的wsgi服務的函數調用。然後OOP大行其道的今天,貌似地球上乃至宇宙中的萬物都可被抽象成對象,然而在實際的coding中,我們真的需要將所有的東西都抽象成對象嗎?
這也是我喜歡Python的一個原因,雖然Python中萬物都是對象,但是卻提供這種對象可調用的方式,而它可以完成一些函數不能完成的工作。比如靜態變量,這在Python中是不允許的,但是通過__call__可以這樣做
class Factorial:
def __init__(self):
self.cache = {}
def __call__(self, n):
if n not in self.cache:
if n == 0:
self.cache[n] = 1
else:
self.cache[n] = n * self.__call__(n-1)
return self.cache[n]
fact = Factorial()
for i in xrange(10):
print("{}! = {}".format(i, fact(i)))
# output
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
對象綁定
在涉及新類對象綁定的時候,可以在元類放置對象綁定時的操作代碼
class test(type):
pass
class test1(test):
def __call__(self):
print "I am in call"
class test2(object):
__metaclass__=test1
t=test2()
#I am in call
test2是test1的實例。因爲test1是元類。在實例綁定元類的時候,__call__會調用
大家可以交流討論下,看看還有哪些設計模式可以應用於此,我會補充的