值得一提的是这个用法:效果
>>> Chain().status.user.timeline.list
'/status/user/timeline/list'
上代码:
>>> class Chain(object):
def __init__(self,path=""):
self._path=path
def __getattr__(self,path):
return Chain("%s/%s"%(self._path,path))
def __str__(self):
return self._path
__repr__=__str__
>>> Chain().status.user.timeline.list
/status/user/timeline/list
这里有几个问题:
1.逻辑比较明显。每次调用并不存在的方法时,返回return Chain("%s/%s"%(self._path,path))这种字符串,不管多少次调用最后都会变成chain(“XX/XX/XX”)
2.chain(“XX/XX/XX”)变成字符串需要改写__str__方法,不然传回的是地址。
3.记得__repr__=__str__使开发者也能看到效果
留一个问题:
作业上的:
还有些REST API会把参数放到URL中,比如GitHub的API:
GET /users/:user/repos
调用时,需要把:user
替换为实际用户名。如果我们能写出这样的链式调用:
Chain().users('michael').repos
就可以非常方便地调用API了。有兴趣的童鞋可以试试写出来。
>>> class Chain(object):
def __init__(self,path=""):
self._path=path
def __getattr__(self,path):
if ????:
return Chain(????)
else:
return Chain("%s/%s"%(self._path,path))
def __str__(self):
return self._path
__repr__=__str__
是这么写吗?那??应该写什么呢?
直到我看到了:
__call__
一个对象实例可以有自己的属性和方法,当我们调用实例方法时,我们用instance.method()
来调用。能不能直接在实例本身上调用呢?在Python中,答案是肯定的。
任何类,只需要定义一个__call__()
方法,就可以直接对实例进行调用。请看示例:
class Student(object):
def __init__(self, name):
self.name = name
def __call__(self):
print('My name is %s.' % self.name)
调用方式如下:
>>> s = Student('Michael')
>>> s() # self参数不要传入
My name is Michael.
豁然开朗:
>>> class Chain(object):
def __init__(self,path=""):
self._path=path
def __getattr__(self,path):
if path=="user":
return self
return Chain("%s/%s"%(self._path,path))
def __call__(self,path):
return Chain("%s/%s"%(self._path,path))
def __str__(self):
return self._path
__repr__=__str__
>>> Chain().users('michael').repos
/users/michael/repos
我还真他娘是个天才
步骤基本可能是这样Chain().users先让解释器去找users属性,结果返回的是Chain()即self,然后变成了Chain()(“michael”),于是去调用__call__