在自定义类中实现__next__

时间:2015-02-22 17:40:15

标签: python class

我有一个看起来像这样的课程

Class myClass:

    def __init__(self, key, value):
        self.key = key
        self.value = value

其中key是一个字符串,而value始终是myClass的元素列表,可能为空。

我想定义我自己的iter方法,为value.key中的每个value返回values。我试过了

def __iter__(self):
    return self 

def __next__(self):
    try:
        self.value.next().key
    except:
        raise StopIteration

但它永远循环着。我究竟做错了什么? 另外,如果我想要兼容Python 2/3,我应该添加方法

def next(self):
    return self.__next__()

2 个答案:

答案 0 :(得分:3)

您没有理由实施__next__。您可以使用__iter__返回一个可以执行您想要的生成器。

class Pair(object):

    def __init__(self, key, value):
        self.key = key
        self.value = value

    def __iter__(self):
        return (v.key for v in self.value)

    # alternative iter function, that allows more complicated logic
    def __iter__(self):
        for v in self.value:
             yield v.key

p = Pair("parent", [Pair("child0", "value0"), Pair("child1", "value1")])

assert list(p) == ["child0", "child1"]

这种做法与python2和python3兼容,因为返回的生成器在python2中具有所需的next函数,在python3中具有__next__

答案 1 :(得分:2)

您需要在列表self.value上提取并保留迭代器 - 您不能只在列表上调用next,在这样的列表上需要一个迭代器

因此,您需要一个辅助迭代器类:

class myClassIter(object):

    def __init__(self, theiter):
        self.theiter = theiter

    def __next__(self):
        return next(self.theiter).key

    next = __next__

我也使Py 2/3与object基础兼容并具有适当的别名。

在这里,我假设列表中的每个项目都有key属性(因此唯一的预期异常是StopIteration,您可以传播它)。如果不是这种情况,并且您希望在没有attribite的情况下遇到项目时停止迭代,则需要try / except,但保持紧张! - 良好异常处理的关键设计方面。即,如果这些确实是你的规格:

    def __next__(self):
        try: return next(self.theiter).key
        except AttributeError: raise StopIteration

不要抓住所有例外 - 只有您特别期望的例外情况!

现在,在myClass中,您需要:

def __iter__(self):
    return myClassIter(iter(self.value))

这意味着myClass可迭代的,而非迭代器,因此您可以在myClass上正确拥有多个循环实例:

mc = myClass(somekey, funkylist)
for ka in mc:
    for kb in mc:
        whatever(ka, kb)

如果mc本身就是一个迭代器,那么内部循环会耗尽它,因此嵌套循环的语义会完全不同。

如果你确实想要这样完全不同的语义(即你想要 mc本身就是一个迭代器,而不仅仅是一个迭代器)那么你必须省去辅助类(但仍然需要将self.value上的迭代器存储为myClass的实例属性 - 这将是一个奇怪的,令人不舒服的安排,但 (几乎不可能)它可能确实是你的应用程序需要的安排......