专栏首页Python程序员杂谈urllib2源码解读三(探索OpenerDirector的add_handler)

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

OpenerDirector是怎么把这些handler分类的

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

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

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

        self.handle_open = {}
        self.handle_error = {}
        self.process_response = {}
        self.process_request = {}

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

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的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • python项目练习一:即时标记

    这是《python基础教程》后面的实践,照着写写,一方面是来熟悉python的代码方式,另一方面是练习使用python中的基本的以及非基本的语法,做到熟能生巧。

    the5fire
  • functools之update_wrapper的使用

    xadmin通过实现自己的BaseAdminView(继承自Django的View)来完成xadmin后台界面的处理。在解决一个csrf的问题时,翻了下xadm...

    the5fire
  • SSH连*nux常用命令二

    通过SSH连接*nux服务器,需要记住很多命令,今天用到了一些,记下来,以免忘记。

    the5fire
  • Spring Webflux —— 源码阅读之 handler 包

    查找给定请求的handler,如果找不到特定的请求,则返回一个空的Mono。这个方法被getHandler(org.springframework.web.se...

    芋道源码
  • 源码阅读再来一发:解读RGW中request的处理流程

    请求处理流程图 ? 以civetweb为例 1. rgw_main.cc为整个radosgw服务的入口,main()函数中根据在ceph.conf的rgw...

    用户1260683
  • 抛开flash,自己开发实现C++ RTMP直播流播放器

    众所周知,RTMP是以flash为客户端播放器的直播协议,主要应用在B/S形式的场景中。本人研究并用C++开发实现了RTMP直播流协议的播放器,结合之前做的R...

    hbstream
  • ESP8266 SDK开发: 外设篇-SPI

    杨奉武
  • MySQL多实例配置(二)

        MySQL数据库的集中化运维,可以通过在一台MySQL数据库服务器上,部署多个MySQL实例。该功能是通过mysqld_multi来实现。mysqld_...

    Leshami
  • 基于RTMP数据传输协议的实时流媒体技术研究

    本文来自论文《基于 RTMP 协议的流媒体技术的原理与应用》,文中研究了基于 Flash 平台的流媒体系统中使用的 RTMP 协议的原理和应用,并对网络上实时流...

    貟王軍
  • 惰性单例分析与学习

    本文基于你已经知道单例模式的要点,本文内容借鉴于《javascript设计模式与开发实践》这本书,做出了整理和一些思考。

    RobinsonZhang

扫码关注云+社区

领取腾讯云代金券