可迭代对象

什么是可迭代对象

简单理解:可以被for遍历的对象

代码层面:如果一个对象实现了iter方法,那么这个对象就是可迭代对象

1
2
3
4
5
6
str_iterable = "hello world!"

for x in str_iterable:
print(x)


h
e
l
l
o

w
o
r
l
d
!
1
2
print(str_iterable.__iter__())
print(iter(str_iterable)) # iter是内建方法,等同于执行了可迭代对象的__iter__方法
<str_iterator object at 0x7fdfc5c2ac20>
<str_iterator object at 0x7fdfc5c2ad40>

可迭代对象之间的共同点

可以借助一个方法来看不同可迭代对象之间,有什么共同的方法或者属性

1
2
3
4
5
6
7
8
9
10
# 查看可迭代对象之间的共同属性
def common_attrs_of_iterable(*iterables):
res = set()
for iterable in iterables:
if not res:
res = set(dir(iterable))
else:
res &= set(dir(iterable))
res -= set(dir(object))
return res
1
2
3
4
import sys
iterables = ("asada", ["1","2",3], {"1": 2}, set(), open(sys.argv[0]))
common_attrs = common_attrs_of_iterable(*iterables)
print(common_attrs)
{'__iter__'}

运行上述代码可以看到,可迭代对象都实现了__iter__方法。

1
2
for iterable in iterables:
print(iter(iterable))
<str_iterator object at 0x7fdfc5c2bdc0>
<list_iterator object at 0x7fdfc5c2bdc0>
<dict_keyiterator object at 0x7fdfc4290e50>
<set_iterator object at 0x7fdfc42743c0>
<_io.TextIOWrapper name='/opt/conda/lib/python3.10/site-packages/ipykernel_launcher.py' mode='r' encoding='UTF-8'>

可以发现,iter方法作用于可迭代对象,返回了一个迭代器对象。

迭代器

在Python 文档中明确指出了,迭代器必须同时实现__next____iter__方法,这称之为「迭代器协议」。根据这个协议,迭代器必须是可迭代的,换言之,「迭代器」是一种「可迭代对象」。缺少了__iter__方法的迭代器是不完整的,不符合迭代器协议的要求。所有迭代器的__iter__方法都只要干篇一律的return self 即可。

迭代器的共同属性

1
2
3
iterators = [iter(iterable) for iterable in iterables]
r = common_attrs_of_iterable(*iterators)
print(r)
{'__next__', '__iter__'}

如何迭代

如何手动迭代?

  1. 构建迭代器iter(iterable)
  2. 迭代next(iterator)取值
  3. 捕获StopIteration异常结束迭代
1
2
3
actions = ["唱跳", "Rap", "篮球"]
action_iterator = iter(actions)
print(action_iterator)
<list_iterator object at 0x7fdfc5c2b520>
1
next(action_iterator)
'唱跳'
1
next(action_iterator)
'Rap'
1
next(action_iterator)
'篮球'
1
next(action_iterator)
---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

Cell In[24], line 1
----> 1 next(action_iterator)


StopIteration: 

自定义迭代器

手动next迭代

1
2
3
4
5
6
7
8
9
10
11
class CustomIterator:
def __init__(self, actions):
self.actions = actions
self.index = 0

def __next__(self):
while self.index < len(self.actions):
action = self.actions[self.index]
self.index += 1
return action
raise StopIteration
1
2
3
custom_iterator = CustomIterator(actions)
while True:
print(next(custom_iterator))
唱跳
Rap
篮球



---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

Cell In[32], line 3
      1 custom_iterator = CustomIterator(actions)
      2 while True:
----> 3     print(next(custom_iterator))


Cell In[31], line 11, in CustomIterator.__next__(self)
      9     self.index += 1
     10     return action
---> 11 raise StopIteration


StopIteration: 
1
2
3
4
# 使用for in遍历
custom_iterator = CustomIterator(actions)
for x in custom_iterator:
print(x)
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

Cell In[33], line 3
      1 # 使用for in遍历
      2 custom_iterator = CustomIterator(actions)
----> 3 for x in custom_iterator:
      4     print(x)


TypeError: 'CustomIterator' object is not iterable

使用for in自动遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 添加__iter__方法,从而可以for in迭代
class CustomIterator:
def __init__(self, actions):
self.actions = actions
self.index = 0

def __next__(self):
while self.index < len(self.actions):
action = self.actions[self.index]
self.index += 1
return action
raise StopIteration

def __iter__(self):
return self
1
2
3
custom_iterator = CustomIterator(actions)
for x in custom_iterator:
print(x)
唱跳
Rap
篮球

无限产生数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from random import random

class Random:

def __iter__(self):
return self

def __next__(self):
return random()
i = 0
for x in Random():
print(x)
i += 1
if i == 15:
break
0.821488499889332
0.7726247502230905
0.8130058108108277
0.9370384548715419
0.5028830329931709
0.10089818387325744
0.20126577437316662
0.41492810575332495
0.9845745266851457
0.912745925842808
0.21538545269372233
0.1509464699891857
0.9663588740624246
0.9287065525926113
0.5975031338963481