9

我对 Python 还很陌生,只是在看一些定义迭代器对象的例子。

我看的例子是:

class fibit:  # iterate through fibonacci sequence from 0,1...n<=max
    def __init__(self, max):       
        self.max = max

   def __iter__(self):
        self.a = 0
        self.b = 1
        return self

   def next(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

但是,如果我将 self.a 和 self.b 的初始化从iter移到init似乎(以我的简单理解)以完全相同的方式工作。

class fibit:  # iterate through fibonacci sequence from 0,1...n<=max
    def __init__(self, max):
        self.a = 0
        self.b = 1        
        self.max = max

   def __iter__(self):
        return self

   def next(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

那么哪一种是推荐的方法呢?

谢谢。:)

4

3 回答 3

10

初始化应该在__init__. 这就是它在那里的原因。

Python 中的迭代器对象通常是“使用一次”——一旦你迭代了一个迭代器,就不能期望你能够再次迭代它。

因此,如果您尝试再次迭代对象,则重新初始化这些值是没有意义的。为了说明这一点,我稍微扩展了您的代码:

class fibit_iter:  # iterate through fibonacci sequence from 0,1...n<=max
    def __init__(self, max):
        self.max = max

    def __iter__(self):
        self.a = 0
        self.b = 1
        return self

    def next(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

class fibit_init:  # iterate through fibonacci sequence from 0,1...n<=max
    def __init__(self, max):
        self.a = 0
        self.b = 1
        self.max = max

    def __iter__(self):
        return self

    def next(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

iter_iter = fibit_iter(10)
iter_init = fibit_init(10)

print "iter_iter"

for item in iter_iter:
    print item
    break

for item in iter_iter:
    print item
    break

print "iter_init"

for item in iter_init:
    print item
    break

for item in iter_init:
    print item
    break

本质上,我从您的 init 版本创建一个对象,并从您的 iter 版本创建一个对象。然后我尝试对它们进行两次部分迭代。注意你如何得到不同的结果:

iter_iter
0
0
iter_init
0
1
于 2013-02-15T17:25:32.950 回答
2

__init__在初始化类的实例时使用。它用于设置类实例的属性。

__iter__用于定义可迭代的类的行为(返回一个交互器)。

@mgilson -__iter__通常返回一个与列表不同的迭代器(type() 在物理上不同),因为迭代器产生(破坏性地消耗)值。

尝试调用__iter__()xrange 实例的方法并尝试多次循环这些值。

 >>> foo = xrange(5)
 >>> bar = a.__iter__()
 >>> bar.next()
 0
 >>> bar.next()
 1
 >>> list(bar)
 [2, 3, 4]
于 2013-02-15T17:30:42.420 回答
1

这实际上取决于您希望迭代器做什么。如果你有充分的理由多次迭代你的迭代器,每次都得到相同的结果,然后把初始化放在__iter__; 然而,这应该是例外而不是常态;raise StopIteration表现良好的迭代器应该在用尽时继续,而不是重新启动序列。事实上:在 aStopIteration被引发后返回更多值的迭代器被认为是损坏的(尽管这更像是一个警告,要小心你如何使用它)。

所以,重申一下:

  • 对于标准迭代器,将您的初始化放入__init__

  • 对于自定义/重复行为,将您的初始化放入__iter__

于 2016-03-24T22:06:30.353 回答