前言
无论你是刚入门python的新兵,还是久经沙场的python老兵。相信在看完这篇本人呕心沥血完成的博客(误人子弟),大家会有新的认识和发现。
一、判断可迭代对象与迭代器的方法
1、方法一:isinstance() 既可以判断可迭代对象又可判断迭代器
如果是返回True
不是返回False
代码语言:javascript复制from collections.abc import Iterator, Iterable
a = [1, 2, 3]
print(isinstance(a, Iterable)) # True
print(isinstance(a, Iterator)) # False
2、方法二:iter() 仅可判断是否为可迭代对象
是可迭代对象 不抛出异常
不是可迭代对象 抛出异常
代码语言:javascript复制a = [1, 2, 3]
b = 1
print(iter(a)) # <list_iterator object at 0x0000026252115D48> 返回跌迭代器
print(iter(b)) # 抛出异常 TypeError: 'int' object is not iterable
二、魔法方法__iter__,__next__
先看代码分别自定义两个类
代码语言:javascript复制class A():
def __iter__(self):
pass
a = A()
print(isinstance(a, Iterable)) # True
print(isinstance(a, Iterator)) # False
代码语言:javascript复制class B():
def __iter__(self):
pass
def __next__(self):
pass
b = B()
print(isinstance(b, Iterable)) # True
print(isinstance(b, Iterator)) # True
先说结论:只要对象定义了__iter__
方法,那这个对象就是可迭代对象
只要对象定义了__iter__
与__next__
方法,那这个对象就是迭代器
可迭代对象:__iter__
迭代器:__iter__
与__next__
所以有:迭代器一定是可迭代对象,可迭代对象不一定是迭代器
三、鸭子类型(ducking typing)
看完上面肯定会有大大的疑惑,为什么自定义__iter__
方法就是可迭代对象,类A与类B又没有继承,且方法__iter__
里面什么都没写。
这不得不说说鸭子类型,这与python程序设计有关。
如果一只鸟看起来想鸭子,叫起来像鸭子,那么它就是鸭子(it must be a duck)
鸭子类型在程序设计中是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。
使用鸭子测试来评估对象是否可以被解析为特定的类型。
在这里就不展开详细讲解,感兴趣可以自行翻阅相关书籍
简单总结:
我自定义__iter__
方法,那我这个对象(鸟)就像可迭代对象(鸭子),那我就认为他就是可迭代对象(鸭子)。
四、for循环原理
可迭代对象一般来说是可迭代的,可以用for循环来迭代。
代码语言:javascript复制a = [1, 2, 3]
for num in a:
print(num)
# 1
# 2
# 3
代码语言:javascript复制a = [1, 2, 3]
it = iter(a)
print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3
print(next(it)) # 抛出异常 StopIteration
for循环实际执行步骤 a是可迭代对象
1、it = iter(a) 2、每次执行 next(it) 迭代 3、捕获StopIteration异常,停止迭代
由1知 首先执行it = iter(a)我们博客前面讲过,iter()可判断是否为可迭代对象,如果a不是可迭代对象那么for循环会报错,所以能够进行for循环的都是可迭代对象。如range(5),“abc”,
[1,2,3],{1,2,3},{1:1,2:2}等等都是可迭代对象。
iter()函数实际上把可迭代对象a变成迭代器。因为只有迭代器才有next()方法。
__iter__对应的iter()
__next__对应next()
python中魔法方法都会对应一个内置函数或者运算符
可迭代对象不一定都可以for循环。如前文我们自定义的class A(),因为iter(a)此时返回it是None,而不是迭代器,此时执行next(it) 就会出错。
五、自定义迭代器
代码语言:javascript复制class N():
def __init__(self):
self.num = [1, 2, 3]
self.index = -1
def __iter__(self):
return self
def __next__(self):
self.index = 1
if self.index >= len(self.num):
raise StopIteration
return self.num[self.index]
n = N()
for i in n:
print(i)
# 1
# 2
# 3
n1 = N()
it = n1.__iter__()
print(it.__next__()) # 1
print(it.__next__()) # 2
print(it.__next__()) # 3
print(it.__next__()) # 抛出异常 StopIteration