urllib2源碼閱讀

翻看兩個庫的源碼,對urllib2代碼高內聚、低耦合的特色,體會的仍是不深。先寫下來,慢慢分析、慢慢領悟吧。
特地弄了個思惟導圖,對釐清代碼的大概結構仍是挺有幫助的。我按照函數和類去進行

同urllib同樣,urllib2中也能夠調用urlopen方法,貼下這個函數的源碼:python

1  _opener = None
2  def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
3             cafile=None, capath=None, cadefault=False, context=None):
4     global _opener
5     if cafile or capath or cadefault:
6         if context is not None:
7             raise ValueError(
8                 "You can't pass both context and any of cafile, capath, and cadefault"
9             )
10        if not _have_ssl:
11            raise ValueError('SSL support not available')
12        context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH,
13                                             cafile=cafile,
14                                             capath=capath)
15        https_handler = HTTPSHandler(context=context)
16        opener = build_opener(https_handler)
17    elif context:
18        https_handler = HTTPSHandler(context=context)
19        opener = build_opener(https_handler)
20    elif _opener is None:
21        _opener = opener = build_opener()
22    else:
23        opener = _opener
24    return opener.open(url, data, timeout)

能夠看出,urlopen其實是對build_opener函數返回的對象進行調用,build_opener能夠傳遞HTTPSHandler實例
build_opener使用一個handlers的對象列表建立出一個opener對象,這個opener是OpenerDirector的實例,支持一些默認的handler,包括http、ftp、https(調用時)。app

def build_opener(*handlers):
    import types
    def isclass(obj):
        return isinstance(obj, (types.ClassType, type))
    # 實例化OpenerDirector
    opener = OpenerDirector()
    # 默認的handler
    default_classes = [ProxyHandler, UnknownHandler, HTTPHandler,
                       HTTPDefaultErrorHandler, HTTPRedirectHandler,
                       FTPHandler, FileHandler, HTTPErrorProcessor]
    if hasattr(httplib, 'HTTPS'):
        # 添加了HTTPSHandler
        default_classes.append(HTTPSHandler)
    skip = set()
    # handlers參數中有屬於default_classes中子類或實例的,加入到skip中
    for klass in default_classes:
        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())

    for h in handlers:
        if isclass(h):
            h = h()
        opener.add_handler(h)
    return opener

當使用res = urllib2.urlopen('http://python.org')時,過下期間的過程哈(我怕忘):
urlopen函數會在其中調用build_operner函數,build_opener函數中會實例化OpenerDirector爲opener,並把默認的類添加到opener上(add_handler),返回operner。urlopen調用opener.open方法,去執行響應的請求。
先寫到這裏吧,以後在繼續socket

相關文章
相關標籤/搜索