Python的列表、元组、集合、字典都支持使用for循环,Python的for循环也使得遍历一个可迭代对象的每个元素十分容易,那么如何自定义一个类来使它实现Python的for循环呢?

为了更好地说明这个方法,我用单链表来举例:



class



其中,Node类是单链表的节点类,SLList是一个带sentinel的单链表,我这里只简单实现了一些addFirst和addLast方法。

首先我们回顾一下Java是如何实现增强的for循环的(即for each),类似的代码如下:



/* Singly linked list with generics*/



在Java中,我们使SLList类实现了iterable接口返回一个Iterator对象,在for each循环中,我们其实是先调用SLList.iterator()方法得到一个Iterator对象,再调用Iterator对象的next方法直到hasNext方法返回false.

接下来我们回到python上来,Python实现for循环的主要方法有两个,分别是 __iter__ 和 __next__方法,分别对应 iter 和 next两个内置函数,以下是Python for循环的一个慢动作:

在for i in range(3)语句中,首先由内置函数iter生成一个iterable object,再不断地调用这个对象的next的方法并赋值给 i 这个变量,直到这个对象的next方法报出“StopIteration”这个错误的时候停止迭代。



for



好,那么我们该如何让我们自定义的单链表也能像普通的列表,元组一样支持for循环呢?

首先,我们写入__iter__ 方法,这个方法返回一个可迭代的对象,这个对象支持next方法,并在“没有下一个”的时候 raise StopIteration 错误(就像Java的 .iterator()方法返回一个带有.next()和.hasNext()方法的实现了Iterable接口的对象一样)。那么我们该如何定义__iter__方法返回的对象呢?这里我给出两种思路:

第一种思路:把链表本身(self)返回,再写入链表的__next__方法,示例代码如下:



def



在每次迭代的一开始(__iter__方法的第一行),我们让指针pointer指向sentinel,并把self返回,当指针pointer非空时,我们将它作为__next__方法的返回值,当pointer为空时,我们raise StopIteration()

第二种思路:定义一个遍历链表所有节点的生成器,我们就可以使用这个生成器自带的next()方法了,示例代码:



def __travel(self):
        p = self.__sentinel.next
        while p is not None:
            yield p.item
            p = p.next
    def __iter__(self):
        return self.__travel



这里我们给iter方法返回了一个迭代器函数,迭代器本身就支持__next__方法. So, it works !!!