Python迭代器。在__init__或__iter__中初始化状态变量?

时间:2013-02-15 17:22:16

标签: python iterator

我对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

那么推荐的方法是哪一个?

感谢。 :)

3 个答案:

答案 0 :(得分:7)

初始化应在__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

答案 1 :(得分:1)

初始化类的实例时使用

__init__。它用于设置类实例的属性。

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

@mgilson - __iter__通常返回一个Iterator,它与列表不同(type()是物理上不同的),因为Iterators产生(破坏性消耗)值。

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

 >>> foo = xrange(5)
 >>> bar = a.__iter__()
 >>> bar.next()
 0
 >>> bar.next()
 1
 >>> list(bar)
 [2, 3, 4]

答案 2 :(得分:0)

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

所以,重申:

  • 对于标准迭代器,将初始化放在__init__

  • 了解自定义/重复行为,将初始化设置为__iter__