前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >urllib2源码解读三(探索OpenerDirector的add_handler)

urllib2源码解读三(探索OpenerDirector的add_handler)

作者头像
the5fire
发布2019-02-28 16:35:11
6680
发布2019-02-28 16:35:11
举报

OpenerDirector是怎么把这些handler分类的

上篇文章说到,在build_opener中只是调用了OpenerDirector的add_handler方法,并不是直接操作的属性来完成handler的添加的。那么来看看OpenerDirector.add_handler具体做了些什么工作。

这个函数的作用其实很简单,就是传进来的Handler进行分类。既然是分类那就要有分类的依据了,那么分类的依据是什么呢?

看一下这四个属性就知道了:

代码语言:javascript
复制
        self.handle_open = {}
        self.handle_error = {}
        self.process_response = {}
        self.process_request = {}

它要把你传递来的Handler分别放到这四个字典中,显然对应的Handler就应该会包含open或者error或者resonse或者request的属性或者方法,说到这里来看下代码就了解了:

代码语言:javascript
复制
def add_handler(self, handler):
        '''
            根据协议添加handler到不同的字典中,
            所有的handler都会存放到handlers这个list中。
        '''
        if not hasattr(handler, "add_parent"):
            raise TypeError("expected BaseHandler instance, got %r" %
                            type(handler))

        added = False
        for meth in dir(handler):
            #过滤掉命名恰好和下面判断规则一致的函数。
            # 但这几个其实并不是需要的函数。
            if meth in ["redirect_request", "do_open", "proxy_open"]:
                # oops, coincidental match
                continue

            i = meth.find("_")
            protocol = meth[:i]
            condition = meth[i+1:]

            if condition.startswith("error"):
                j = condition.find("_") + i + 1
                kind = meth[j+1:]
                try:
                    kind = int(kind)
                except ValueError:
                    pass
                lookup = self.handle_error.get(protocol, {})
                self.handle_error[protocol] = lookup
            elif condition == "open":
                kind = protocol
                lookup = self.handle_open
            elif condition == "response":
                kind = protocol
                lookup = self.process_response
            elif condition == "request":
                kind = protocol
                lookup = self.process_request
            else:
                continue
            handlers = lookup.setdefault(kind, [])
            if handlers:
                bisect.insort(handlers, handler)
            else:
                handlers.append(handler)
            added = True
        if added:
            #bisect.insort(self.handlers, handler)
            handler.add_parent(self)

从这个函数我们可以看到关于分类的具体处理过程,其实就是通过遍历这个handler对象的所有方法,然后根据其中是否存在某指定方法来进行分类的。比如HttpHanlder中有http_open这个方法,那么就会被放到handle_open中。至于代码中其他的操作都是对一些基本属性和对那些会产生冲突的方法的过滤。

最后存入字典的key也需要注意一下,这个key就是对应的协议,而此事的值并不是单独的handler对象,而是一个列表,这说明,如果有两个Handler(比如AHandler和BHandler)中含有同样的http_open方法,如果是这样的话,在后面要处理对应的http open请求的话就需要通过这两个handler依次处理。

最后还有一个被我注释掉的一句代码,这个其实urllib2作者也有写注释,handlers这个列表只是为了保持兼容。

每个handler类都继承同一个BaseHandler,拥有add_parent方法,这个方面的作用是为了在handler中同OpenerDirector进行通信。

这个函数的功能也就这些了,不过从这里我看到了另外的东西,就是:约定。

所有的这些都是基于一个约定,约定handler中的关键函数一定要是网络协议加上对应的方法,约定每个handler必须有一个add_parent方法,以及其他的一些约定。

了解这些约定的目的一个是方便理解urllib2在处理url的过程,另外一个就是方便自己以后编写一些扩展handler。

不知道说得是不是够清晰,我自己觉得还不是很清晰,或许在写到最后一篇的时候才会真正清晰。

这一篇和上一篇把urlopen中的构建opener对象的过程都学习了一下,下一篇就来学习这两篇构建opener是怎么处理你给定的url的。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2012-12-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档