iter()方法的第二个参数

Ste*_*ong 10 python python-3.x

我试图弄清楚如何制作迭代器,下面是一个工作正常的迭代器.

class DoubleIt:

    def __init__(self):
        self.start = 1

    def __iter__(self):
        self.max = 10
        return self

    def __next__(self):
        if self.start < self.max:
            self.start *= 2
            return self.start
        else:
            raise StopIteration

obj = DoubleIt()
i = iter(obj)
print(next(i))
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试将16传递给iter()中的第二个参数时(我希望迭代器在返回16时停止)

i = iter(DoubleIt(), 16)
print(next(i))
Run Code Online (Sandbox Code Playgroud)

它抛出TypeError:iter(v,w):v必须是可调用的因此,我尝试这样做.

i = iter(DoubleIt, 16)
print(next(i))
Run Code Online (Sandbox Code Playgroud)

它返回< main .DoubleIt对象0x7f4dcd4459e8>.这不是我的预期.我检查了programiz的网站,https://www.programiz.com/python-programming/methods/built-in/iter 其中说可调用对象必须在第一个参数中传递,以便使用第二个参数,但它未提及可以在其中传递用户定义的对象以使用第二个参数.

所以我的问题是,有没有办法这样做?第二个参数可以与"自定义对象"一起使用吗?

Gra*_*her 11

它的文档可能会更加清晰,它只是说明了

iter(object [,sentinel ])

...

在这种情况下创建的迭代器将为每个对其方法的调用调用没有参数的对象__next__() ; 如果返回的值等于sentinel,StopIteration则会引发,否则返回值.

可能没有说清楚的是,迭代器产生的是无法调用的返回值.由于你的callable是一个类(没有参数),它每次迭代都会返回一个新的类实例.

解决此问题的一种方法是使您的类可调用并将其委托给__next__方法:

class DoubleIt:

    def __init__(self):
        self.start = 1

    def __iter__(self):
        return self

    def __next__(self):
        self.start *= 2
        return self.start

    __call__ = __next__

i = iter(DoubleIt(), 16)
print(next(i))
# 2
print(list(i))
# [4, 8]
Run Code Online (Sandbox Code Playgroud)

这具有以下优点:它是一个无限的发生器,只能通过哨兵值停止iter.

另一种方法是使类的最大参数:

class DoubleIt:

    def __init__(self, max=10):
        self.start = 1
        self.max = max

    def __iter__(self):
        return self

    def __next__(self):
        if self.start < self.max:
            self.start *= 2
            return self.start
        else:
            raise StopIteration

i = iter(DoubleIt(max=16))
print(next(i))
# 2
print(list(i))
# [4, 8, 16]
Run Code Online (Sandbox Code Playgroud)

需要注意的一个区别是,iter当它遇到sentinel值时停止(并且不产生项目),而第二种方式使用<而不是<=比较(如代码),因此将产生最大项目.

  • `__call__ = __next__`非常巧妙! (3认同)