python dict2种遍历方式及区别

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



原文地址:https://www.cnblogs.com/hust/p/2597095.html