python基础 — 可迭代对象,迭代器和生成器

1、迭代(Iteration)

迭代(Iteration)是一种计算机编程的概念,指的是重复执行某段代码或操作的过程。它是通过循环结构实现的,用于对数据集合中的每个元素进行逐个处理。

在Python中,迭代(Iteration)是指对一个序列或可迭代对象依次访问其中的元素的过程。迭代是一种重复执行操作的过程,每次迭代处理一个元素,直到完成所有元素或满足特定条件。通过迭代,我们可以逐个获取序列中的元素并执行相应的操作。

Python提供了多种实现迭代的方式,常用的迭代方式有两种:

1. “for”循环:使用“for”关键字,对一个序列或可迭代对象中的每个元素进行遍历和处理。例如,在Python中:

for item in sequence:
    # 对item进行操作

2. “while”循环:根据条件判断表达式,当条件满足时,重复执行一段代码块。通常需要在循环体内更新条件以避免无限循环。例如:

while condition:
    # 执行代码块
    # 更新条件

迭代的好处是能够高效地处理大量数据和重复性任务,并且具有灵活性和通用性。它使得编程逻辑更加简洁和可读,并且减少了代码的冗余和重复编写。

需要注意的是,在进行迭代时,要确保迭代的终止条件和循环体内的操作是正确和合理的,以避免陷入无限循环或产生错误结果。此外,一些编程语言提供了额外的迭代控制语句,如“break”和“continue”,可以在特定情况下跳出循环或跳过当前的迭代步骤。

总而言之,迭代是计算机编程中一种重复执行代码或操作的方式,通过循环结构实现对数据集合中每个元素的逐个处理。它是处理大量数据和自动化重复任务的基础。

2、可迭代对象(Iterable)

在Python中,可迭代对象(Iterable)是一种数据类型,表示一组元素的集合或序列,可以使用循环语句(如for循环)对其进行遍历。也可以用于创建迭代器(Iterator)。

可迭代对象必须实现`__iter__()`方法,该方法返回一个迭代器(Iterator)对象,用于进行迭代操作。

Python中常见的可迭代对象包括但不限于:

- 列表(List)
- 元组(Tuple)
- 字符串(String)
- 集合(Set)
- 字典(Dictionary)
- 文件对象(File Object)
- range对象(Range Object)
- 生成器(Generator)

(1)使用for循环遍历可迭代对象示例:

my_list = [1, 2, 3]
for item in my_list:
    print(item)

my_string = "Hello"
for char in my_string:
    print(char)

在上述示例中,`my_list`和`my_string`都是可迭代对象,可以使用`for`循环语句对其进行遍历操作。

(2)可以使用内置函数 isinstance()判断对象是否是可迭代对象:

from collections.abc import Iterable, Iterator, Generator

my_list = [1, 2, 3, 4]

# 使用内置函数 isinstance()判断对象是否是可迭代对象
print(isinstance(my_list, Iterable))  # 判断是否可迭代 True
print(isinstance(my_list, Iterator))  # 判断是否是迭代器 False
print(isinstance(my_list, Generator))  # 判断是否是生成器 False

(3)可以使用内置函数 iter()将可迭代对象转换成迭代器:

my_iterator = iter(my_list)
print(isinstance(my_iterator, Iterator))  # True

(4)可以使用内置函数 next()获取迭代器的下一个元素,如果迭代器中没有更多的元素可供返回,则抛出StopIteration异常:

# 使用内置函数 next()获取迭代器的下一个元素,如果迭代器中没有更多的元素可供返回,则抛出StopIteration异常
print(next(my_iterator))    # 1
print(next(my_iterator))    # 2
print(next(my_iterator))    # 3
print(next(my_iterator))    # 4
print(next(my_iterator))    # StopIteration

3、迭代器(Iterator)

Python中,迭代器(Iterator)是可迭代对象(Iterable)背后的实现机制,它用于提供逐个访问可迭代对象中元素的接口。迭代器实现了迭代协议,包含两个核心方法:

  • __iter__()方法返回迭代器自身,这使得迭代器本身也是一个可迭代对象。
  • __next__()方法返回可迭代对象中的下一个元素。如果没有元素可以返回,则引发StopIteration异常。

如果在一个类中定义__iter__方法和__next__方法,那么这个类的实例就是一个迭代器。

以下是一个示例,演示如何使用迭代器遍历列表的每个元素:

my_list = [1, 2, 3]

# 迭代器对象
my_iterator = my_list.__iter__()
print(my_list.__iter__())  # 

# 迭代
print(my_iterator.__next__())  # 1
print(my_iterator.__next__())  # 2
print(my_iterator.__next__())  # 3
print(my_iterator.__next__())  # StopIteration异常

在上述示例中,可迭代对象 my_list的__iter__()方法返回了一个迭代器对象,而迭代器对象的__next__()方法逐个取出可迭代对象中的元素,知道元素取完会抛出StopIteration异常。

内置函数 iter()可以将可迭代对象转换成迭代器对象。

my_list = [1, 2, 3]

print(iter(my_list))    # 

在Python中,可以通过实现一个类来创建自定义的迭代器。以下是创建迭代器的基本步骤:

1. 创建一个类,并让该类实现`__iter__()`和`__next__()`方法。

2. 在`__iter__()`方法中,返回迭代器对象本身(即返回`self`),以便在需要迭代器的地方使用。

3. 在`__next__()`方法中,定义每次迭代时返回的值,并在合适的条件下引发`StopIteration`异常来标识迭代结束。

下面是一个简单的示例,演示如何创建一个迭代器来生成一系列的数字:

class MyIterator:
    def __iter__(self):
        return self

    def __next__(self):
        # 定义每次迭代时返回的值
        # 在这个示例中,从0开始逐步递增
        if hasattr(self, 'current'):
            self.current += 1
        else:
            self.current = 0

        # 如果达到某个条件,可以选择引发 StopIteration 来终止迭代
        # 例如,当返回的值大于等于 10 时停止迭代
        if self.current >= 10:
            raise StopIteration

        return self.current


# 创建迭代器对象
my_iterator = MyIterator()

# 迭代
# print(my_iterator.__next__())
# print(my_iterator.__next__())
# print(my_iterator.__next__())
# print(my_iterator.__next__())

# 使用 for 循环迭代
for item in my_iterator:
    print(item)

运行以上代码,会输出数字0到9,表示成功创建并使用自定义的迭代器。

需要注意的是,迭代器可以保存状态,因此每次迭代时返回的值可以根据状态变化。同时,在合适的条件下引发`StopIteration`异常来结束迭代。

Python中的迭代器(Iterator)具有以下特点:

1. 惰性计算:迭代器在需要时才会生成和返回下一个元素,而不是一次性计算并存储所有元素。这使得迭代器非常适合处理大型或无限序列,节省了内存空间。

2. 单向性:迭代器只能向前遍历,不能后退或重复访问已经遍历过的元素。每次调用`next()`方法都会返回下一个元素,直到没有元素可返回时引发StopIteration异常。

3. 可迭代对象:迭代器本身也是一个可迭代对象,因此可以在`for`循环等迭代上下文中使用。通过调用内置函数`iter()`将可迭代对象转换为迭代器,或者直接构建自定义的迭代器对象。

4. 低级别接口:迭代器提供了一种低级别的数据访问接口,允许用户按需获取元素、控制迭代过程,并在必要时处理异常。相比于列表等高级数据结构,迭代器更加灵活和高效。

5. 一次性消耗:每个迭代器只能遍历一次可迭代对象中的元素。如果需要多次遍历,必须重新创建迭代器或使用其他方式进行处理。

迭代器在Python中被广泛应用于各种情况,例如处理大型数据集、文件读取、生成器函数、无限序列生成等。通过迭代器的特性,可以实现高效的数据处理和操作,提供了更加简洁和优雅的编程方式。

4、生成器(Generator)

Python中,生成器(Generator)是一种特殊类型的函数(迭代器),可以在需要时逐个生成值,而不是一次性生成所有值并将其存储在内存中。生成器使用yield语句来定义,当调用生成器函数时,它会返回一个迭代器对象,通过迭代器可以逐步获取生成的值。

生成器函数在执行过程中会生成一系列值,每次使用 yield 关键字暂停执行并返回一个值,下次调用时从上次暂停的地方继续执行。这种方式可以实现惰性计算,并且节省内存空间,因为生成器只在需要时才生成值,并且每次只保持一个值在内存中。

以下是一个简单的生成器函数的示例:

def my_generator():
    yield 1
    yield 2
    yield 3

# 调用生成器函数,返回一个生成器对象
generator = my_generator()

# 使用迭代器逐个获取生成的值
print(next(generator))  # 输出:1
print(next(generator))  # 输出:2
print(next(generator))  # 输出:3

生成器(Generator)函数的执行过程:

1. 当生成器函数被调用时,它并不会立即执行函数体内的代码。相反,它会返回一个生成器对象,生成器对象可以用于迭代或者调用 next() 函数来依次获取生成器函数 yield 语句返回的值。

2. 第一次调用 next() 或者使用迭代器进行遍历时,生成器函数开始执行,并执行到第一个 yield 关键字处。函数执行暂停,返回 yield 后面的表达式结果作为当前迭代的值。

3. 下一次调用 next(),生成器函数从上次暂停的地方继续执行,直到再次遇到 yield 关键字,函数再次暂停,返回 yield 后面的表达式结果。这个过程会一直重复,每次调用 next() 都会让生成器函数继续执行,直到函数执行完毕或者遇到 return 语句结束。

生成器函数通过 yield 实现了多次暂停和恢复的机制,每次暂停都会保存函数的状态,下次恢复时可以从暂停的地方继续执行。这种特性使得生成器非常适合处理大量数据或者需要延迟计算的情况,因为它能够按需生成数据,并且在生成过程中节省内存空间。

生成器(Generator)对象具有以下常用的方法:

1. `next()`:该方法用于获取生成器对象的下一个值。每次调用 `next()` 方法,生成器函数会继续执行并返回 `yield` 关键字后面的表达式结果。如果生成器函数已经执行完毕(没有更多的 `yield` 语句),则会抛出 `StopIteration` 异常。

2. `send(value)`:除了具有 `next()` 方法的功能外,还可以向生成器函数发送一个值,并将该值作为当前 `yield` 表达式的结果,并使生成器函数从上次暂停的地方继续执行。该方法可以使生成器函数在执行过程中获取外部传入的数据,并继续执行后续的代码。注意,第一次调用生成器时,应使用 `next()` 方法,因为无法在开始之前 "send" 任何值。

3. `close()`:用于显式关闭生成器,释放相关的资源。当生成器不再被使用时,建议使用该方法进行关闭操作。

4. `throw(type[, value[, traceback]])`:用于引发指定类型和参数的异常,在生成器内部进行捕获和处理。可以通过该方法实现对生成器的控制和异常处理。

5. `__iter__()`:使得生成器对象成为可迭代的,可以在 `for` 循环中直接使用。生成器本身就是可迭代的,因此该方法通常不需要显式调用。

这些方法使得生成器对象具有灵活的控制和高效的惰性计算特性,可以根据需要按需生成和处理数据。值得注意的是,生成器对象在一次迭代后就会耗尽,无法再次遍历。如果希望重新迭代生成器函数,需要重新创建生成器对象。

这些方法使得生成器成为处理大量数据或需要延迟计算的情况下的强大工具,在节省内存和提高效率方面发挥重要作用。

下面是一个使用send()方法的简单示例:

def my_generator():
    while True:
        value = yield
        print("Received:", value)

# 创建生成器对象
gen = my_generator()

# 启动生成器,使其处于暂停状态并准备接收数据
next(gen)  # 或 gen.send(None)

# 使用 send() 方法向生成器发送数据
gen.send("Hello")  # 输出: Received: Hello
gen.send(123)      # 输出: Received: 123

# 停止生成器的运行
gen.close()

在上述示例中,定义了一个生成器函数my_generator()。该生成器函数通过yield语句暂停执行,并用value变量接收来自调用方的数据。每次调用.send()方法,都会将数据发送给生成器函数,并继续执行相应的代码段。

需要注意的是,首次调用生成器对象的.send()方法时,需要先调用一次.next()方法(或者参数为None.send()方法),让生成器处于可接收数据的状态。

判断一个对象是否是生成器(Generator)的几种方式:

1. 从函数结构上判断,如果一个函数中包含了yield关键字,那么该函数就可以被称为生成器函数(Generator Function)。

2. 直接使用print()函数打印对象,打印输出结果:

3. 使用内置函数isinstance()types.GeneratorType来判断对象的类型是否为生成器(Generator)。当返回True时,该对象是生成器对象;当返回False时,则不是生成器对象。

isinstance(obj, types.GeneratorType)

4. 使用内置函数isinstance()和collections.abc模块中的Generator类来判断对象的类型是否为生成器(Generator)。当返回True时,该对象是生成器对象;当返回False时,则不是生成器对象。

isinstance(obj, collections.abc.Generator)

5. 使用inspect模块提供的isgenerator()方法来判断对象的类型是否为生成器(Generator)。当返回True时,该对象是生成器对象;当返回False时,则不是生成器对象。

inspect.isgenerator(obj)

相比于常规的函数,生成器(Generator)具有以下特点:

1. 惰性计算:生成器以惰性方式逐个生成值,只在需要时才计算和返回结果。这种特性使得生成器非常适合处理大量数据或无限序列。

2. 状态保存:生成器可以暂停执行,并保存当前状态。当再次调用生成器时,它会从上一次暂停的位置继续执行。这使得生成器在迭代过程中能够保存中间结果或参数状态。

3. 节省内存:由于生成器以惰性计算的方式工作,它不会一次性生成所有的值,而是根据需要逐个生成。这种机制节省了内存空间,尤其适用于处理大型数据集或无限序列。

4. 迭代器接口:生成器实现了迭代器接口,因此可以使用`next()`函数或使用`for`循环对生成器进行遍历。这样可以方便地按需获取生成器产生的值。

由于生成器的上述特点,它在以下场景中特别有用:

1. 处理大型数据集:通过生成器逐个生成数据项,可以减少对于内存的需求,提高处理大型数据集的效率。

2. 无限序列:生成器可以方便地创建无限序列,如斐波那契数列、素数生成等。因为生成器只在需要时生成值,所以可以使用生成器来处理需要无限延伸的序列。

3. 懒加载数据:当处理需要耗费大量计算资源或时间的数据时,生成器允许按需逐个获取数据项,实现懒加载的效果,从而避免一次性加载所有数据。

4. 协程和异步编程:生成器还可以用于实现协程和异步编程模型,通过`yield`和`send()`方法的结合使用,实现非阻塞式的并发操作,提高程序的运行效率。

总之,生成器是一种功能强大且灵活的工具,在处理大数据集、惰性计算、无限序列、懒加载数据和异步编程等场景中都有广泛应用。

5、迭代器和生成器的区别

Python中的生成器是一种特殊类型的迭代器。虽然它们在某些方面相似,但也有几个关键的区别:

1. 定义方式:生成器使用函数定义,通过`yield`关键字返回一个值,并可以在后续调用中恢复执行状态,实现按需生成值的功能。迭代器可以通过实现`__iter__()`和`__next__()`方法来创建,也可以使用类似`iter()`和`next()`的内置函数进行操作。

2. 内存占用:生成器按需生成值,并且不会事先将所有值存储在内存中,因此在处理大数据集或无限序列时非常高效。相反,迭代器可能需要在内存中存储整个序列或数据集,无论是否立即需要使用。

3. 实现复杂度:生成器可以通过简单的函数定义和`yield`语句轻松创建,从而使代码更加简洁和易读。相比之下,实现迭代器需要额外编写`__iter__()`和`__next__()`方法,并管理迭代状态等较复杂的逻辑。

4. 迭代语法支持:生成器可以直接使用`for`循环进行迭代、使用列表解析和生成器表达式生成序列。迭代器需要自行实现迭代逻辑,才能支持`for`循环和其他迭代语法。

5. 状态保存:生成器在每次`yield`语句处暂停执行,并保存函数的当前状态,包括局部变量和执行位置。当生成器恢复时,可以接着上次的执行继续运行。而迭代器通常没有这种特性,一旦迭代完成或出现异常,则无法再次使用。

总的来说,生成器是一种更高级、更方便的迭代器实现方式,通过简单的函数定义和`yield`语句,可以按需生成值,提供了更加灵活和高效的迭代方式。而迭代器则更底层,需要手动实现迭代逻辑和存储状态,并且可能需要在内存中保持整个序列或数据集。


reference:

内置类型 | 迭代器类型 — Python 3.8.16 文档

9.8. 迭代器 — Python 3.8.16 文档

你可能感兴趣的:(Python基础,python,可迭代对象,迭代器,生成器,iter,迭代)