【python】可迭代对象与迭代器

2024-02-05 15:09:51 浏览数 (2)

前言

无论你是刚入门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

0 人点赞