实例化对象内自产自销

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

步步拆解,理解上面的代码块

  1. 第一步

    In [1]:
    Chain()  # 初始化实例并打印
    Out[1]:
    

    创建实例Chain(),由于没有传入 path参数,默认参数 path="",所以直接打印实例结果也为 空。

  2. 第二步
    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。

  3. 第三步
    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")

  4. 第四步
    In [4]:

    Chain().users("michael").repos
    

    Out[4]:/users/michael/repos

    第三步的最后相当于执行对象实例Chain("/users/michael"),那么第四步,就在这个实例基础上尝试调用repos属性,显然repos属性没有被定义,于是再次调用__getattr__()方法。然后就重复第二步的逻辑,最终完成拼接/users/michael/repos

posted @ 2023-01-12 20:23  HugoWang010220  阅读(20)  评论(0)    收藏  举报