实例化对象内自产自销
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().usersOut[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").reposOut[4]:
/users/michael/repos第三步的最后相当于执行对象实例
Chain("/users/michael"),那么第四步,就在这个实例基础上尝试调用repos属性,显然repos属性没有被定义,于是再次调用__getattr__()方法。然后就重复第二步的逻辑,最终完成拼接/users/michael/repos。
浙公网安备 33010602011771号