对next()和\uu iter\uu()的确切工作方式感到困惑

2024-10-02 00:32:04 发布

您现在位置:Python中文网/ 问答频道 /正文

在尝试实现迭代器时,我对next()感到困惑。我做了一个简单的测试脚本,其中迭代器的工作方式与我预期的一样:

class Object:
    def __init__(self, name):
        self.name = name
    def prin(self):
        print self.name

class Some:
    def __init__(self):
        self.data = list()
    def __iter__(self):
        return self.SomeIter(self, len(self.data))
    def fill(self, obj):
        self.data.append(obj)
    def printMe(self):
        for entry in self:
            print entry.name

    class SomeIter:
        def __init__(self, some, end):
            self.index = 0
            self.end = end
            self.name = some.data[self.index].name
            self.data = some.data
        def next(self):
            if self.index == self.end:
                raise StopIteration
            else:
                self.name = self.data[self.index].name
                self.index += 1
            return self

########################################################################


someX = Some()

obj1 = Object("A")
obj2 = Object("B")

someX.fill(obj1)
someX.fill(obj2)
someX.fill(obj2)

for obj in someX:
    print obj.name

我得到“A B B”作为输出。那很好。但是我还有一个树类的迭代器。next()-方法的工作原理基本相同。我首先更新实例,然后返回它。但是对于树迭代器,第一个元素被跳过。这对我来说是有意义的,因为我只在更新实例之后才返回self。但是为什么在上面的实现中我会得到不同的行为呢?在这种情况下,实例被更新,然后才被返回呢?在

^{pr2}$

编辑1:

我比较了两个迭代器的输出结果,它们不同,SomeIter将第一个元素输出两次:

next:  A
A
next:  A
B
next:  B
B
next:  B

另一个迭代器不:

next:  a
s
next:  s
i
next:  i
r
next:  r
t
next:  t
t
next:  t
s
next:  s
e
next:  e
t
next:  t

否则“next:a”将出现2次

编辑2:

这对我来说真的没有任何可怕的意义。。。在

看看这些调用和输出:

someXIter = iter(someX)
print someXIter.next().name
print someXIter.next().name
print someXIter.next().name

输出:

next:  A
A
next:  A
B
next:  B
B

使用此代码:

class SomeIter:
        def __init__(self, some, end):
            self.index = 0
            self.end = end
            self.name = some.data[self.index].name
            self.data = some.data
        def next(self):
            print "next: ", self.name
            if self.index == self.end:
                raise StopIteration
            else:
                self.name = self.data[self.index].name
                self.index += 1
            return self

为什么这对我来说毫无意义?因为第一次调用next()时,它输出“next:A”,然后更新实例,并打印函数调用的返回值,也就是“A”。哇?为什么不是“B”,因为返回值应该是更新后的实例。在


Tags: 实例nameselfdataindexinitdefsome
1条回答
网友
1楼 · 发布于 2024-10-02 00:32:04

Python 2.7

要成为迭代器,必须实现迭代器协议:

  • 定义obj.__iter__和{}
  • obj.__iter__必须返回self
  • 一旦StopIteration被引发,对obj.next()next(obj))的后续调用必须引发StopIteration

如果一个类只定义__iter____iter__必须返回一个实现迭代器协议的对象。如果类中的项包含在内建类型中,就像一个列表,__iter___可以简单地返回iter(list)。在

我想整个概念中隐含的意思是迭代器必须跟踪它在迭代中的位置。在

如果希望对象是具有不同迭代序列的迭代器,可以定义不同的方法来跟踪迭代并前进到下一个项目,然后在obj.next()中使用这些方法。在

小例子:

class Thing(object):
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return self.name
    def __repr__(self):
        return 'Thing({})'.format(self.name)

class Some(object):
    def __init__(self):
        self.data = None
        # need something to keep track of the iteration sequence
        self.__index = None
        # type of iteration do you want to do
        self.direction = self.forward
    def __iter__(self):
        # reset the iteration
        self.__index = None
        return self
    def next(self):
        try:
            return self.direction()
        except IndexError:
            raise StopIteration
    def forward(self):
        if self.__index is None:
            self.__index = -1
        self.__index += 1
        return self.data[self.__index]
    def reverse(self):
        if self.__index is None:
            self.__index = 0
        self.__index -= 1
        return self.data[self.__index]

使用

^{pr2}$

所以也许只要保持next简单,并将树遍历逻辑放在不同的方法中。这可能会使测试这种逻辑变得更容易。您可以随时添加不同的行为:

    def odd_then_even(self):
        if self.__index is None:
            self.__index = -1
            self.__odd = True
        self.__index += 2
        try:
            return self.data[self.__index]
        except IndexError:
            if not self.__odd:
                raise IndexError
            self.__odd = False
            self.__index = 0
            return self.data[self.__index]

>>> some.direction = some.odd_then_even
>>> for thing in some:
    print thing,


B D A C
>>>

我很难理解您的内部类解决方案是如何工作的,但有一点看起来有点不对劲,就是迭代器对象的next方法返回self,而且似乎{}应该返回序列/集合中的下一个项。当您迭代一组事物时,迭代应该为单个事物提供服务,而不是迭代器对象的修改实例。在

相关问题 更多 >

    热门问题