大家最为熟悉的一段代码:
res = urllib2.urlopen('http://python.org')
这端代码的作用就是打开http://python.org这个网站,返回一个response对象。
下面咱们来深入到这个urlopen函数中,来看下代码:
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的。
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对象的。
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
----EOF-----
微信公众号:Python程序员杂谈
微信公众号:Python程序员杂谈