在学习爬虫的时候认识到到迭代我就顺便记录下面

什么是迭代

for遍历就是迭代

for循环能遍历的就是可迭代,不能遍历的就是不可迭代

for循环是怎么判断他是可迭代的,一个可迭代对象都有一个 __iter__() 方法,就是里面有__iter__() 方法,就是可迭代

迭代的基本演示

比如下面这个代码就是可迭代

1
2
3
a = [1, 2, 3, 4]
for i in a:
print(i)

结果

1
2
3
4
1
2
3
4

下面是不可迭代

1
2
for i in 123:
print(i)

结果

1
2
3
4
Traceback (most recent call last):
File "/home/zss/a.py", line 1, in <module>
for i in 123:
TypeError: 'int' object is not iterable

判断是否是可迭代可以用collections.abc模块里面的Iterable

1
2
3
4
5
6
7
from  collections.abc import  Iterable


a=[1,2,3]

#isinstance函数来判断一个对象是否是一个已知的类型
print(isinstance(a,Iterable))

结果

1
True

什么是可迭代对象__iter__() 方法

我们可以看一下能迭代的里面都是有什么方法

  • 查看列表里方法

    查看列表全部方法里面有__iter__() 方法

    1
    2
    3
    >>> a=[1,2,3]
    >>> dir(a)
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
  • 查看元组里方法

    他里面也有__iter__() 方法

    1
    2
    3
    >>> a=(1,2,3)
    >>> dir(a)
    ['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
  • 查看字典里方法

    他里面也有__iter__() 方法

    1
    2
    3
    >>> a={'a':'a','b':'b'}
    >>> dir(a)
    ['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']

使用这个方法

代码,可以看见他是一个listiterator(列表迭代器)对象

1
2
3
>>> a=['a','b']
>>> a.__iter__()
<listiterator object at 0x7f90176f7150>

__iter__() 方法里面有下面这么多的方法,

1
['__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__']

其中__length_hint__()__next__()__setstate__()

方法名 作用
__length_hint__() 元素数量
__next__() 方法也允许您执行操作,并且必须返回序列中的下一个项目
__setstate__(开始位置) 位置信息来重建文件对象,就是指定开始循环的位置

__length_hint__()方法

for循环是怎么知道数组他有几个,用的就是__iter__() 方法里面__length_hint__()方法

代码

1
2
3
>>> a=[1,2,3]
>>> a.__iter__().__length_hint__()
3

__next__()方法

方法也允许您执行操作,并且必须返回序列中的下一个项目

他会一个一个的去执行下一个

代码

1
2
3
4
5
6
a=a=[1,2,3,4].__iter__()

print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())

结果

1
2
3
4
1
2
3
4

image-20210701175905468

__setstate__()方法

位置信息来重建文件对象,就是指定开始循环的位置

代码我指定的是2

1
2
3
4
5
6
7
8
a=a=[1,2,3,4,5,6,7].__iter__()

print(a.__setstate__(2))

print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())

结果他是从第三个开始的

1
2
3
4
3
4
5
6

手写迭代器

__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 next() 方法并通过 StopIteration 异常标识迭代的完成

__next__() 方法(Python 2 里是 next())会返回下一个迭代器对象

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 创一个类
class Iterative_generation:
def __init__(self):
self.a = 0

# 定义一个__iter__类
def __iter__(self):

return self

# 定义一个__next__类
def __next__(self):
b=self.a
# 每调用这个类就加1
self.a+=1
return b

myclass=Iterative_generation()

# 调用myclass的__iter__方法
print(myclass.__iter__())

# 第一次调用myclass的__iter__方法
print(myclass.__next__())

# 第二次调用myclass的__iter__方法
print(myclass.__next__())

# 第三次调用myclass的__iter__方法
print(myclass.__next__())

结果

1
2
3
4
<__main__.Iterative_generation object at 0x7f863bfc69a0>
0
1
2

手写迭代器可以for

StopIteration

StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代

我们可以用任意可以迭代的测试一下

1
2
3
4
5
6
7
# iter() 函数用来生成迭代器
it = iter([1,2,3])

print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())

下面的iter() 函数用来生成迭代器

结果,可以看见他报了一个StopIteration错,应为他就只能迭代三次。上面我执行了四次就报了一个StopIteration

1
2
3
4
5
6
7
8
9
Traceback (most recent call last):
File "/home/zss/杂东西/a2.py", line 6, in <module>
print(it.__next__())
StopIteration
1
2
3

进程已结束,退出代码为 1

手写迭代器可以for

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 创一个类
class Iterative_generation:
def __init__(self):
self.a = 0

# 定义一个__iter__类
def __iter__(self):

return self

# 定义一个__next__类
def __next__(self):
b=self.a
# 每调用这个类就加1
self.a+=1

# self.a>10就会执行下面的语句
if self.a>10:

# StopIteration 异常用于标识迭代的完成
raise StopIteration

return b
# 创建对象
myclass = Iterative_generation()

# iter() 函数用来生成迭代器
myiter = iter(myclass)
for i in myiter:
print(i)

iter() 函数用来生成迭代器

raise关键字用于引发异常,您可以定义要引发的错误类型以及要向用户打印的文本

StopIteration异常用于标识迭代的完成,防止出现无限循环的情况,在 next() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。

结果

1
2
3
4
5
6
7
8
9
10
0
1
2
3
4
5
6
7
8
9