Python迭代器协议在迭代器返回值中?

2024-09-29 19:36:48 发布

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

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

这是我们在考试中遇到的一个例子,我因为使用self而不是FileName迭代器而丢了分数

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)

Tags: nameinselfindexreturndeffilenameiterable
1条回答
网友
1楼 · 发布于 2024-09-29 19:36:48

要在容器类中实现迭代器协议,需要向其添加__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

如果将迭代器类与iterable对象分开,则必须返回一个新的迭代器对象,而不是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

相关问题 更多 >

    热门问题