【问题标题】:Python Iterator Protocol __iter__ in iterator return value?Python迭代器协议__iter__在迭代器返回值?
【发布时间】:2021-02-17 00:34:05
【问题描述】:

所以我最近在我的 python 类中了解了迭代器协议,我被告知 __iter__(self) 方法应该总是返回一个新的迭代器而不是 self。在 Fluent Python 书中,它谈到了在迭代器中返回 self,所以我不确定为什么我的导师告诉我不能使用 self 作为返回值。

这是我们在考试中的示例,我因使用 self 而不是 FileNamesIterator 而失分。

class FileNamesIterator:
    """
    Iterator that iterates over all the file names in the
    FileNamesIterable.
    """

    def __init__(self, filename_iterable: FileNamesIterable):
        self.filename_iterable = filename_iterable
        self.curr_index = 0

    def __next__(self) -> str:
        file_list = self.filename_iterable.file_list
        if self.curr_index == len(file_list):
            raise StopIteration()

        next_file_name = file_list[self.curr_index]
        self.curr_index += 1

        if ".png" in next_file_name:
            next_file_name = f"{next_file_name} - Portable Network Graphics " \
                             f"File"
        elif ".gif" in next_file_name:
            next_file_name = f"{next_file_name} - Graphics Interchange " \
                             f"Format File"

        return next_file_name

    def __iter__(self) -> FileNamesIterator:
        return self


class FileNamesIterable:
    def __init__(self, file_list: list):
        self.file_list = file_list

    def __iter__(self) -> FileNamesIterator:
        return FileNamesIterator(self)

【问题讨论】:

    标签: python iterator iterable


    【解决方案1】:

    要在容器类中实现迭代器协议,您需要向其添加__iter__ 方法。这允许使用for 循环迭代类实例,因为它在类实例上调用iter() 以获取迭代器对象(从instance.__iter__(),然后从返回的对象(迭代器)调用__next__ 方法,直到它耗尽(提高StopIteration 而不是返回另一个数据值)。这就是为什么迭代器类的__iter__ 方法应该返回一个带有__next__ 方法的对象。

    如果实现该协议的类本身可以具有__next__ 方法,您可以从__iter__ 返回self

    class MyIterator:
        def __init__(self, data):
            self._data = data
            self._index = 0
    
        def __next__(self):
            if self._index == len(self._data):
                raise StopIteration
            self._index += 1
            return self._data[self._index-1]
    
        def __iter__(self):
            return self
    

    如果将迭代器类与可迭代对象分开,则必须返回一个新的迭代器对象,而不是 self(也不是迭代器类名):

    class Iterator:
        def __init__(self, iterable):
            self._iterable = iterable
    
        # required for the iterator protocol
        def __next__(self):
            if not self._iterable:
                raise StopIteration
            value = self._iterable.pop(0)
            return value
    
        # required for the iterator protocol. It *has* to return self
        def __iter__(self):
            return self
    
    
    class Container(list):
        """
        This container is a list. A list is already an iterable
        but we override the list __iter__ just to see how its code
        should be like
        """
        def __iter__(self):
            """
            Returns an iterator protocol compliant object. Note it is an
            instance, not the Iterator class. Otherwise it raises TypeError
            (no iterator type. Note also that it is a *new* iterator instance.
            """
            return Iterator(self)
    
    
    print("Using a single class:")
    it = MyIterator([1, 2, 3])
    print(it)
    
    for elem in it:
        print(elem)
    
    print()
    
    print("Separating the iterator class from the container class:")
    container = Container((1, 2, 3))
    it = iter(container)
    print(it)
    
    print(next(it))
    print(next(it))
    print(next(it))
    
    print()
    
    for elem in container:
        print(elem)
    

    输出:

    Using a single class:
    <__main__.MyIterator object at 0x7f65a23b6fd0>
    1
    2
    3
    
    Separating the iterator class from the container class:
    <__main__.Iterator object at 0x7f65a23b6ca0>
    1
    2
    3
    

    【讨论】:

      猜你喜欢
      • 2018-06-15
      • 2018-01-05
      • 1970-01-01
      • 2019-08-15
      • 2018-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多