Python小白学习教程从入门到入坑------第三十一课 迭代器(语法进阶)

目录

一、可迭代对象Iterable

1.1 可迭代对象的条件

1.2 for 循环工作原理

1.3 isinstance()

二、迭代器  Iterator

2.1 __iter__() 和 __next__()

2.2 可迭代对象&迭代器

2.2.1 定义与特性

2.2.2 关系与转换

2.2.3 应用场景

三、迭代器协议(了解即可)

四、自定义迭代器类



在这一节,我将向大家介绍Python中的迭代器和生成器,在介绍之前我们先回顾一下什么是可迭代对象?

一、可迭代对象Iterable

含义: 可以通过for ..in….这类语句遍历读取数据的对象称之为可迭代对象

遍历(迭代):依次从对象中把一个个元素取出来的过程

可迭代对象的数据类型:str、list、tuple、dict、set 等

1.1 可迭代对象的条件

(满足了这两个条件也可以称为可迭代对象):

1、对象实现了__iter__()方法

2、__iter__() 方法返回了迭代器对象

1.2 for 循环工作原理

1、先通过__iter__() 获取可迭代对象的迭代器

2、对获取到的迭代器不断调用__next__() 方法来获取下一个值并将其赋值给临时变量 i

1.3 isinstance()

判断一个对象是否是可迭代对象或者是一个己知的数据类型

导入模块:

from collections.abc import Iterable   # 导入模块

isinstance(o,t)     o:对象,t:类型,可以是直接或者间接类名、基本类型或者元组

eg:

from collections.abc import Iterable   # 导入模块

# 示例对象
my_list = [1, 2, 3]
my_str = "hello"
my_int = 42

# 判断是否是可迭代对象
print(isinstance(my_list, Iterable))  # 输出: True
print(isinstance(my_str, Iterable))  # 输出: True
print(isinstance(my_int, Iterable))  # 输出: False

在这个例子中,my_list 是一个列表,my_str 是一个字符串,它们都是可迭代对象,因此 isinstance() 返回 True。而 my_int 是一个整数,不是可迭代对象,所以 isinstance() 返回 False。

此外,还可以使用 isinstance() 来判断一个对象是否是某个具体的数据类型,比如列表、元组、字典等:

# 判断是否是列表
print(isinstance(my_list, list))  # 输出: True

# 判断是否是元组
my_tuple = (1, 2, 3)
print(isinstance(my_tuple, tuple))  # 输出: True

# 判断是否是字典
my_dict = {'a': 1, 'b': 2}
print(isinstance(my_dict, dict))  # 输出: True

二、迭代器  Iterator

含义:迭代器是一个可以记住遍历位置的对象,迭代器对象从集合的第一个元素开始访
问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

2.1 __iter__() 和 __next__()

迭代器有两个基本的方法:__iter__() 和 __next__()

__iter__() 方法:返回迭代器对象本身

__next__() 方法:返回容器的下一个元素,并将其移动到下一个位置,如果容器中没有更多的元素,则返回一个StopIteration异常

步骤:

1、iter() 调用对象的__iter__(),并把__iter__() 方法的返回结果作为自己的返回值

2、next() 调用对象的__next__(),一个个取出元素

3、所以元素都取完了,__next__()将引发StopIteration异常

接下来通过一个例子来更好的了解这两个方法:

# 第一种方法:
li = [1,2,3,4]
# 1.创建迭代器对象
li2 = iter(li)
print(li2)

# 2.获取下一条数据
print(next(li2))   # 1
print(next(li2))   # 2
print(next(li2))   # 3
print(next(li2))   # 4

# 3.取完元素后,再使用next()会引发StopIteration异常
print(next(li2))   # StopIteration异常

# 第二种方法:
li = [1,2,3,4]
# 1.创建迭代器对象
li2 = li.__iter__()
print("li2:",li2)

# 2.获取下一条数据
print(li2.__next__())   # 1
print(li2.__next__())   # 2
print(li2.__next__())   # 3
print(li2.__next__())   # 4

# 3.取完元素后,再使用next()会引发StopIteration异常
print(li2.__next__())   # StopIteration异常

2.2 可迭代对象&迭代器

凡是可以作用于for循环的都属于可迭代对象
凡是可以作用于next()的都是迭代器

2.2.1 定义与特性

可迭代对象(Iterable)

定义:可迭代对象是指实现了iter()方法的对象,该方法返回一个迭代器对象,允许对象被遍历

特性:

1、可以使用for循环进行遍历

2、常见的可迭代对象包括列表(list)、元组(tuple)、集合(set)、字典(dict)、字符串(str)等

3、在迭代过程中,不会记忆之前的访问状态,每次都从头开始遍历

迭代器(Iterator)

定义:迭代器是指实现了iter()和next()方法的对象。其中,iter()方法返回迭代器对象本身(这通常是一个已经实现了迭代协议的对象,因此调用此方法通常只是简单地返回对象自身),而next()方法用于返回迭代器的下一个元素

特性:

1、可以通过next()函数获取下一个元素,直到遍历完所有元素时抛出StopIteration异常

2、迭代器只能单向遍历,不能反向遍历

3、在迭代过程中,会记忆之前的访问状态,每次调用next()方法时,会从上一次停止的位置开始遍历

4、迭代器实现了惰性计算,即只在需要时才生成下一个值,这使得它在处理大数据集时非常高效

2.2.2 关系与转换

关系:如果一个对象是迭代器,那么它一定是可迭代的。但反过来,如果一个对象是可迭代的,它不一定是迭代器。

转换:可以使用 iter() 函数将可迭代对象转换为迭代器。例如,iter([])会将一个空列表转换为一个迭代器对象。

我们如何判断一个对象时可迭代对象还是迭代器对象呢?

根据1.3可得需要用到 isinstance 来判别

eg:

from collections.abc import Iterable,Iterator  # 第一步导入模块
name = "junjun"   # 定义对象
print(isinstance(name,Iterable))  # 判断对象是否为可迭代对象,True,说明为可迭代对象
print(isinstance(name,Iterator))  # 判断对象是否为迭代器对象,False,说明不是迭代器对象

可得到一个结论:可迭代对象并不一定是迭代器对象 

但是可以通过iter()将可迭代对象转换为迭代器

eg:

from collections.abc import Iterable,Iterator  # 第一步导入模块
name = "junjun"   # 定义对象
print(isinstance(name,Iterable))  # 判断对象是否为可迭代对象,True,说明为可迭代对象
print(isinstance(name,Iterator))  # 判断对象是否为迭代器对象,False,说明不是迭代器对象
name2 = iter(name)  # 将name转换成迭代器对象
print(isinstance(name2,Iterable))  # 判断对象是否为可迭代对象,True,说明为可迭代对象
print(isinstance(name2,Iterator))  # 判断对象是否为迭代器对象,True,说明是迭代器对象

可以得到另一个结论:迭代器对象一定是可迭代对象 

总结:
1、可迭代对象可以通过iter()转换成迭代器对象
2、如果一个对象拥有__iter__(),是可迭代对象,如果一个对象拥有__next__()和__iter__()方法,是迭代器对象

2.2.3 应用场景

可迭代对象:适用于需要被遍历但不需要惰性计算的场景

例如,当需要遍历一个列表中的所有元素时,可以直接使用for循环

迭代器:适用于需要惰性计算或需要自定义遍历方式的场景

例如,当需要遍历一个非常大的数据集时,使用迭代器可以避免一次性将所有数据加载到内存中。此外,迭代器还可以用于实现自定义的遍历逻辑,如逆序遍历或按特定步长遍历

三、迭代器协议(了解即可)

在Python中,迭代器协议是指一种用于定义可迭代对象(iterable)和迭代器(iterator)的协议它提供了一种标准的方法来使对象可迭代,并能够在循环中逐一访问元素

迭代器协议主要涉及两个方法:__iter__() 和 __next__()

1、__iter__() 方法:

① 对于迭代器对象来说,通常这个方法会返回迭代器对象本身,使得迭代器也可以作为可迭代对象使用。这意味着迭代器需要实现这个方法,但返回的值通常是 self

② 对于可迭代对象(如列表、元组等),__iter__() 方法的作用是返回一个迭代器对象,该对象用于遍历可迭代对象中的元素

2、__next__() 方法:

① 这个方法应该返回序列中的下一个元素

② 当没有更多的元素可以返回时,应该引发一个 StopIteration 异常,以通知迭代过程已经结束。

一个对象如果实现了这两个方法(或对于迭代器来说,主要是实现了 __next__() 方法,并且可能也实现了返回自身的 __iter__() 方法),那么它就被认为是一个迭代器

迭代器的好处包括:

1、节省内存:迭代器只保存当前迭代的元素和迭代状态,而不是保存整个容器的数据

2、支持惰性求值:迭代器只有在需要时才会计算下一个元素,可以在处理大量数据时减少计算量

3、支持无限序列:迭代器可以处理无限序列,因为它只需要在需要时生成下一个元素

4、简化代码:使用迭代器可以减少代码的复杂度,提高代码的可读性和可维护性

在Python中,很多内置类型和自定义对象都是可迭代的,并且可以通过调用 iter() 函数获取对应的迭代器。此外,生成器也是迭代器的一种特殊实现,它通过函数来实现迭代逻辑,并使用 yield 语句来产生值。

四、自定义迭代器类

在Python中,自定义迭代器类通常是通过实现迭代器协议来完成的

迭代器协议要求一个对象必须实现两个特殊方法:__iter__() 和 __next__()

然而,对于纯粹的迭代器对象来说,__iter__() 方法通常只是简单地返回对象自身,而真正的迭代逻辑则是由 __next__() 方法来实现的

先通过一个普通的类带大家回忆一下,类的相关知识

eg1:普通的类

class Test(object):        # 定义了一个名为 Test 的类
    # 初始值是1,逐步递增1
    def __init__(self):   # Test 类有一个初始化方法 __init__,设置了一个实例变量 num,初始值为 1
        self.num = 1
    def funa(self):       # Test 类还有一个方法 funa,打印当前的 num 值,并将 num 增加 1
        print(self.num)
        self.num += 1
te = Test()                # 创建了一个实例 te
# 用for循环取出
for i in range(5):
    te.funa()

输出内容:

1
2
3
4
5

eg2:下面是一个自定义迭代器类的例子,这个类会生成一个指定范围内的整数序列:

class MyRangeIterator:
    def __init__(self, start, end):
        self.start = start
        self.end = end
        self.current = start - 1  # 初始化时current设为start的前一个值,以便第一次调用__next__()时返回start

    def __iter__(self):
        return self  # 返回迭代器对象本身

    def __next__(self):
        if self.current < self.end:
            self.current += 1  # 更新当前值
            return self.current  # 返回当前值
        else:
            raise StopIteration  # 如果没有更多元素,则抛出StopIteration异常

# 使用自定义迭代器
iterator = MyRangeIterator(1, 5)
for num in iterator:
    print(num)  # 输出: 1 2 3 4

今天的分享就到这里了,希望能对大家有所帮助~

上一篇:org.springframework.context.support.ApplicationListenerDetector 详细介绍


下一篇:【必备】2025年软考高项(信息系统项目管理师)考试大纲