1

Python迭代器 - EisenJi

 1 year ago
source link: https://www.cnblogs.com/eisenji/p/16462245.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

最近在看Python基础教程(第三版),是之前python课的课本,但是之前没读过,虽然python一直用得挺多,但重新读读收获还挺大。这里做个笔记。
先是迭代器是什么并简单实现一个迭代器,然后是实现了一些range()。后面本来想写生成器和八皇后问题,但是发现了一些很不错的博客,比我能写出来的好多了,把链接收藏在后面了。


​ 迭代器是像循环一样重复很多次,但不会像列表那样一次性全部生成,而是需要用的时候再生成,就节省了内存资源。有时可能只想一个个地获取值,而不是用列表一次性获取,列表可能占用太多内存,并且有时没办法使用列表,列表的长度会到无穷大。


1、根据基本定义实现一个迭代器类

简单的说,迭代器类中:

  • 定义__iter__和__next__两个方法
  • __iter__返回它自己,__next__返回下一个,没有可返回的就抛出StopIteration异常。
  • 迭代器对象Iterator就是字面意思,可以被迭代,比如可以调用next方法(一个迭代器对象it,next(it)就是it.__next__() ),比如可以放进for循环(for x in it)

根据上面描述可以简单写一个迭代器出来

class TestIterator:
    value = 0

    def __next__(self):  
        self.value += 1
        if self.value > 10:  # 到这个条件了没有可返回的了就抛出一个StopIteration异常
            raise StopIteration
        return self.value  # 每次返回下一个
    
    def __iter__(self):  # 这里返回它自己
        return self


if __name__ == '__main__':
    ti = TestIterator()
    print(list(ti))

运行的结果是:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


2、稍微具体一点的__iter__和__next__

嗯于是就能知道了,关于__iter__和__next__:

实现了方法__iter__的对象是可迭代的,而实现了方法__next__的对象是迭代器。

方法__iter__返回一个迭代器,它是包含方法__next__的对象。

文档中也写得很清楚了,调用__next__时,迭代器应返回其下一个值。如果迭代器没有可供返回的值,则引发StopIteration异常。

2321451-20220709232105671-1344066603.png

iter返回一个迭代器对象,即object.__iter__()。如果指定了sentinel(哨兵),这个迭代器将不断调用直到返回的是sentinel。

2321451-20220709232118249-1382537281.png

3、for循环的原理,斐波那契数列的例子

然后再来一个斐波那契数列的例子,迭代器对象可以被放进for循环。

class Fibs:
    def __init__(self) -> None:
        self.a = 0
        self.b = 1

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        return self.a
    
    def __iter__(self):
        return self


if __name__ == '__main__':
    fibs = Fibs()
    for f in fibs:  # 首先会执行__iter__方法获取返回值,就它自己,然后执行一次它的__next__方法,不断循环。
        if f > 1000:
            print(f)
            break

返回这个数列中第一个大于1000的数,是1597。


4、关于range()

(base) eisen@pop-os:~$ python3.8
Python 3.8.10 (default, Mar 15 2022, 12:22:08) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> v1 = range(20)
>>> dir(v1)
['__bool__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index', 'start', 'step', 'stop']

这里先看到v1里面只有__iter__,v1为可迭代对象Iterable,让v2 = v1.__iter__()

>>> v2 = v1.__iter__()
>>> dir(v2)
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']

可以看到v2既有__iter__又有__next__为迭代器对象。range就是执行v1的__iter__获取到里面的迭代器对象v2,再执行v2的__next__方法...

>>> v2.__next__()
0
>>> v2.__next__()
1
>>> v2.__next__()
2
>>> v2.__next__()
3
>>> v2.__next__()
4
>>> v2.__next__()
5

到这里就能理解书上这段话了。

2321451-20220709233312699-564066937.png

于是实现一下range就很简单了,在实现的MyRange里面,__iter__方法就生成一个IterRange类的迭代器对象。

class IterRange():
    def __init__(self, num):
        self.num = num
        self.counter = -1

    def __iter__(self):
        return self

    def __next__(self):
        self.counter += 1
        if self.counter == self.num:
            raise StopIteration()
        return self.counter


class MyRange():
    def __init__(self, num):
        self.num = num

    def __iter__(self):
        return IterRange(self.num)


v1 = MyRange(20)
for i in v1:
    print(i)

输出就是把0到19打印出来。


本来还想写后面的生成器和八皇后问题,但是发现了一些很不错的博客,我就没必要自己写了。这里收藏一下。

Python中生成器的原理,这一篇讲了生成器的使用方法,和详细的原理(里面有源码)

深入理解Python中的生成器,这一篇写了生成器的语法,以及它支持的方法close/send等。

python生成器和迭代器有这篇就够了,这篇写得很详细,后面还有补充itertools库的学习。

还记得八皇后的解法吗,这篇讲了个故事。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK