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

urllib2源码解读二(简单的urlopen)

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

对上面的几个对象有个基本概念之后,再来深究下代码,从一个最普通的urllib2.urlopen()开始,先来熟悉下第一个重点对象:build_opener这个函数。

大家最为熟悉的一段代码:

代码语言:javascript
复制
res = urllib2.urlopen('http://python.org')

这端代码的作用就是打开http://python.org这个网站,返回一个response对象。

下面咱们来深入到这个urlopen函数中,来看下代码:

代码语言:javascript
复制
def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):

    """

    对外的访问函数

    """

    global _opener

    if _opener is None:
        _opener = build_opener()
    return _opener.open(url, data, timeout)

在程序第一次执行urlopen操作的时候,其实就是构建了一个全局的_opener对象,然后用这个_opener对象来处理url以及data。这样做的好处就是如果你在程序中要多次调用urlopen,就不会频繁构建opener对象了。当然这个opener也不是一次加载就再也不可变了,urllib2提供了install_opener这个方法,你可以在客户端调用build_opener然后用前面的那个install_opener来加载。

这段代码很简单,起作用就是构建一个opener对象,所以咱来看下它是如何构建这个_opener对象的。

不过在此之前需要先了解下我们一直在说的opener是什么?

这个_opener其实就是OpenerDirector的一个实例,OpenerDirector上篇已经大概说了,目前我们需要了解的就是在这个对象中定义了几个字典属性,这些字典就是用来存放对应的handler的。

代码语言:javascript
复制
       self.handlers = []   

        # manage the individual handlers

        self.handle_open = {}

        self.handle_error = {}

        self.process_response = {}

        self.process_request = {}

最主要的三个字典是process_request、handle_open、process_response,分别存放处理request、打开request、处理response的handler。

所谓的handler是什么呢?顾名思义,就是处理器,目前只需要知道有一群handler,分别用来处理不同的对象,然后对应的处理结果。

有了这样的认识我们先来看下build_opener()函数是如何来构建这个OpenerDirector对象的。

代码语言:javascript
复制
def build_opener(*handlers):

    import types

    def isclass(obj):

        return isinstance(obj, (types.ClassType, type))



    opener = OpenerDirector()

    #这里定义了一系列的handler类

    default_classes = [ProxyHandler, UnknownHandler, HTTPHandler,

                       HTTPDefaultErrorHandler, HTTPRedirectHandler,

                       FTPHandler, FileHandler, HTTPErrorProcessor]

    if hasattr(httplib, 'HTTPS'):#判断是否支持https

        default_classes.append(HTTPSHandler)

    skip = set()

    for klass in default_classes:

        #处理用户函数参数handler中是否有相同的类在默认类中。

        for check in handlers:

            if isclass(check):

                if issubclass(check, klass):

                    skip.add(klass)

            elif isinstance(check, klass):

                skip.add(klass)

    for klass in skip:

        default_classes.remove(klass)

    #这一步,将默认的类实例化之后加入opener中

    for klass in default_classes:

        opener.add_handler(klass())

    ​#然后把参数中的handler类实例化,加到OpenerDirector中。

    for h in handlers:

        if isclass(h):

            h = h()

        opener.add_handler(h)

    return opener

这个函数的整个过程其实相对简单,只是把系统默认的handler和用户传入的自定义handler参数进行了对比弃重。最后把所有的handler都实例化通过opener.add_handler方法添加给OpenerDirector。最后返回构建好的OpenerDirector实例。

关于这个build_opener就先说到这里,下篇再来说OpenerDirector的add_handler的具体流程。

另外,最近一直在思考一个问题,如何把这些(我学到的东西,比如urllib2)东西能够更好的,更清晰易懂的让读者明白。自己理解urllib2的源码不难,难的是以何种方式或者说何种组织结构来写能让人更容易懂。不知道各位有没有什么好的建议或者好的书籍推荐。

目前我自己的想法就是尽量让每篇文章涉及的未知知识点少,每篇文章也尽量内容单一,这样读起来会不会容易些? - from the5fire.com

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

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

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

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

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