分离方法

2024-04-26 03:43:56 发布

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

在python3中,通过同时定义__iter__和{}方法,使一个类同时成为iterable和迭代器是一个标准过程。但我有点难以理解。举个例子,它创建了一个只产生偶数的迭代器:

class EvenNumbers:

    def __init__(self, max_):
        self.max_ = max_

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n <= self.max:
            result = 2 * self.n
            self.n += 1
            return result

        raise StopIteration

instance = EvenNumbers(4)

for entry in instance:
    print(entry)

据我所知(如果我错了,请纠正我),当我创建循环时,迭代器是通过调用类似于itr = iter(instance)的东西来创建的,它在内部调用__iter__方法。这将返回一个迭代器对象(该实例是由于定义了__next__),因此我可以只返回self)。要从中获取元素,将调用next(itr),直到引发异常为止。在

我现在的问题是:如果和如何将__iter__和{}分开,以便在其他地方定义后一个函数的内容?什么时候有用呢?我知道我必须更改__iter__以便它返回一个迭代器。在

顺便说一句,这样做的想法来自于这个站点(LINK),它没有说明如何实现这一点。在


Tags: 方法instanceselfreturn定义defresultiterable
2条回答

我想我现在已经掌握了这个概念,即使我不完全理解@FHTMitchell文档中的段落。我遇到了一个关于如何分离这两个方法的示例,并希望将其记录下来。在

我发现的是一个非常basic tutorial,它清楚地区分了iterable和iterator(这是我混淆的原因)。在

基本上,您首先将iterable定义为一个单独的类:

class EvenNumbers:

    def __init__(self, max_):
        self.max = max_

    def __iter__(self):
        self.n = 0
        return EvenNumbersIterator(self)

__iter__方法只需要定义了__next__方法的对象。因此,您可以这样做:

^{pr2}$

这将迭代器部分与iterable类分开。现在,如果我在iterable类中定义__next__,我必须返回对实例本身的引用,因为它基本上一次完成两个作业。在

听起来你好像混淆了迭代器iterables。Iterables有一个返回迭代器的__iter__方法。迭代器有一个__next__方法,该方法返回下一个值或引发一个StopIteration。现在在python中,stated迭代器也是iterable的(但反之亦然),并且iter(iterator) is iterator所以迭代器itr应该只从它的__iter__方法返回自己。在

Iterators are required to have an __iter__() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted

代码:

class MyIter:
   def __iter__(self):
       return self

   def __next__(self):
       # actual iterator logic

如果您想创建一个自定义迭代器类,最简单的方法是从^{}继承,您可以看到上面对__iter__的定义(它也是collections.abc.Iterable的子类)。那你只需要

^{pr2}$

当然,有一种更简单的方法来制作迭代器,那就是使用生成器函数

def fib():
    a = 1
    b = 1
    yield a
    yield b
    while True:
        b, a = a + b, b
        yield b

list(itertools.takewhile(lambda x: x < 100, fib()))
#  > [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

仅供参考,这是抽象迭代器和iterable的(简化)代码

from abc import ABC, abstractmethod

class Iterable(ABC):

    @abstractmethod
    def __iter__(self):
        'Returns an instance of Iterator'
        pass

class Iterator(Iterable, ABC):

    @abstractmethod
    def __next__(self):
        'Return the next item from the iterator. When exhausted, raise StopIteration'
        pass

    # overloads Iterable.__iter__
    def __iter__(self):
        return self

相关问题 更多 >