对于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还是被调用了。