Discuss / Python / 链式调用拆解分析(小白式理解)

链式调用拆解分析(小白式理解)

Topic source

__MAY21

#1 Created at ... [Delete] [Delete and Lock User]

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。

紫陌ol

#2 Created at ... [Delete] [Delete and Lock User]

bzny虫

#3 Created at ... [Delete] [Delete and Lock User]

谢谢,之前只是大致明白,尤其是是加上用户名以后更看不懂了,看了解析原来是要用到后面的__call__,明白了

bzny虫

#4 Created at ... [Delete] [Delete and Lock User]

顺便也厘清了一些迷惑,class(arg)是创建实例,arg和class的__init__方法中确定的参数个数相匹配,而class()(arg)是创建一个实例以后再调用这个实例,需要有__call__方法支持。这是完成例子中实现的代码:

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   

    def __call__(self,path):

        return Chain('%s/:%s' % (self._path, path))

在这个例子中__getattr__和__call__的功能都是拼接,区别仅仅是__call__里面多了一个冒号:

小菜

#5 Created at ... [Delete] [Delete and Lock User]

为什么第二步和第三步也要拆开呢

Heiya7

#6 Created at ... [Delete] [Delete and Lock User]

确实讲解的易懂,感谢

看到这个关于如何进入__call__内部的拆分说明,迷糊的脑袋终于懂了,感谢!😁

Medivh

#8 Created at ... [Delete] [Delete and Lock User]

其实你们的做法全部都是错误的,在让你们做一下这个试题的时候,还没讲 __call__ 方法呢

Chain().users('michael').repos

正确的解答方法是:

class Chain(object):    def __init__(self, path=''):        self._path = path    def __getattr__(self, path):        if(path =='users'):            return Chain        return Chain('%s/%s' % (self._path, path))    def __str__(self):        return self._path    __repr__ = __str__

  • 1

Reply