翻看兩個庫的源碼,對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