對於python的dict數據類型常用for結合dict的items方法進行遍歷
for k,v in d.items(): print k,v
還有種遍歷方式
利用dict的popitem方法進行遍歷
while d: k,v=d.popitem() print k,v
這2種方法主要區別是什么呢,采用第一種方式遍歷不會改變原變量,比如d={"a":1,"b":2,"c":3,"d":4}遍歷后d還是這個值,第二種遍歷后d={}
對於可能會發生變化的dict采用第二種方式較為安全,采用for來遍歷會產生不穩定的結果。
具體例子,tornado框架IOloop.py文件里有這么段代碼
def start(self): """Starts the I/O loop. The loop will run until one of the I/O handlers calls stop(), which will make the loop stop after the current event iteration completes. """ self._running = True while True: [ ... ] if not self._running: break [ ... ] try: event_pairs = self._impl.poll(poll_timeout) except Exception, e: if e.args == (4, "Interrupted system call"): logging.warning("Interrupted system call", exc_info=1) continue else: raise # Pop one fd at a time from the set of pending fds and run # its handler. Since that handler may perform actions on # other file descriptors, there may be reentrant calls to # this IOLoop that update self._events self._events.update(event_pairs) while self._events: fd, events = self._events.popitem() try: self._handlers[fd](fd, events) except KeyboardInterrupt: raise except OSError, e: if e[0] == errno.EPIPE: # Happens when the client closes the connection pass else: logging.error("Exception in I/O handler for fd %d", fd, exc_info=True) except: logging.error("Exception in I/O handler for fd %d", fd, exc_info=True)
里邊是這么遍歷一個dict數據的
while self._events: fd, events = self._events.popitem()
為什么不采用下面這種常用遍歷方式呢
for
fd, events
in
self._events.items():
原因很簡單,在主循環期間,這個_events字典變量可能會被處理器所修改。比如remove_handler()處理器。這個方法把fd從_events字典中取出,
所以即使fd被選擇到了,它的處理器也不會被調用,如果使用for迭代循環_events,那么在迭代期間_events就不能被修改,否則會產生不可預計的錯誤,
比如,明明調用了 remove_handler()方法刪除了某個<fd, handler>鍵值對,但是該handler還是被調用了。