在自定义 class 中实施 __next__

Implementing __next__ in a custom class

我有一个 class 看起来像这样

Class myClass:

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

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

我想为 values 中的每个 value 定义我自己的迭代器方法 returns value.key。我试过了

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__()

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

所以,你需要一个辅助迭代器class:

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,您可以传播它)。如果不是这种情况,并且您想在没有属性的情况下遇到项目时停止迭代,则需要 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 是一个 iterable,而不是 iterator,所以你可以有多个在 myClass 实例上循环:

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

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

如果你确实想要这种完全不同的语义(即你想要 mc本身就是一个迭代器,而不仅仅是一个可迭代的)那么你必须放弃auxiliary class(但仍需要将迭代器存储在 self.value 上作为 myClass 的实例属性)——这将是一种奇怪、不舒服的安排,但它 (勉强)可能这确实是您的应用程序需要的安排...

您没有理由实施 __next__。您可以使用 __iter__ 到 return 生成器,它将执行您想要的操作。

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 兼容,因为 returned 生成器将在 python2 中具有所需的 next 函数, __next__ 在 python3.