對於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還是被調用了。