class Chain(object):
def __init__(self, path=''):
self._path = path
def __call__(self,user_name=''):
return Chain('%s/%s' % (self._path, user_name))
def __getattr__(self, path):
return Chain('%s/%s' % (self._path, path))
def __str__(self):
return self._path
__repr__ = __str__ #两个函数返回的数据一样,形式不同,__repr__返回的是给用户看的,__str__返回的是调试信息,给开发者的
#/users/michael/repos
a = Chain()
b = a.users
c = b('michael')
d = c.repos
d
Chain().users('michael').repos
步步拆解,理解上面的代码块
-
第一步
In [1]: Chain() # 初始化实例并打印 Out[1]:
创建实例
Chain()
,由于没有传入path
参数,默认参数path=""
,所以直接打印实例结果也为 空。 -
第二步
In [2]:Chain().users
Out[2]:
/users
尝试调用实例Chain()的
users属性
,由于users属性没有定义,于是调用__getattr__()
方法。根据Chain类的定义,进入
__getattr__()
内部后执行Chain()
.
传入参数"self.__path/path"
(这里的self.__path
为第一步默认值""
.
path为第二步尝试调用的"users"
,即拼接成"/users"
,也就是执行:Chain("/users")
这相当于在类的内部实例化自己然后传入参数"/users"。
也就是说,在执行
Chain().users
时,由于实例没有定义users这个属性,于是调用__getattr__()
方法,最终执行的是Chain("/users")
,结果就打印出/users。 -
第三步
In [3]:Chain().users("michael")
Out[3]:
/users/michael
由于定义了
__call__()
方法,使得可以将对象实例当作方法一样调用。第二步中,执行
Chain().users
相当于实例化了一个对象:Chain("/users")
。于是第三步就相当于,把这个对象实例当做方法直接调用:
Chain("/users")(),并传入参数"michael"
,此时执行的就是 call()方法。同理,根据Chain类的定义,进入
__call__()
内部后,执行Chain(),传入参数"self.__path/path"
这里的
self.__path为第二步的结果"/users"
,path为第三步传入的"michael"
,即拼接成"/users/michael"
,也就是执行:Chain("/users/michael")
。 -
第四步
In [4]:Chain().users("michael").repos
Out[4]:
/users/michael/repos
第三步的最后相当于执行对象实例
Chain("/users/michael")
,那么第四步,就在这个实例基础上尝试调用repos属性,显然repos属性没有被定义,于是再次调用__getattr__()方法
。然后就重复第二步的逻辑,最终完成拼接/users/michael/repos
。