迭代器
迭代器时一个可以记住遍历位置的对象
迭代器对象 从第一个元素开始访问,直到所有元素被访问完结束
迭代器只能前进,不能后退
可迭代对象
实现了
__iter__()方法的对象或者实现了可以返回一个迭代器的
__getitem__()方法(支持下标索引)
- 每迭代一次,都会返回对象中的下一个元素 
- 一直向后读取,知道迭代了所有的数据 
# 列表是一个可迭代对象
my_list = [1, 2, 3]
# 使用 for 循环遍历可迭代对象
for item in my_list:
    print(item)
# 使用 iter() 函数获取迭代器
my_list_iter = iter(my_list)
print(my_list_iter)  # 输出 <list_iterator object at 0x...>迭代器
实现了
__iter__()和__next__()方法的对象
__iter__()返回迭代器自身,而__next__()返回序列中的下一个值如果没有值可返回,则会引发
StopIteration异常
# 通过 iter() 函数获取迭代器
my_list_iter = iter(my_list)
# 使用 next() 函数获取下一个元素
print(next(my_list_iter))  # 输出 1
print(next(my_list_iter))  # 输出 2
print(next(my_list_iter))  # 输出 3
# 如果继续调用 next(),会引发 StopIteration 异常
try:
    print(next(my_list_iter))
except StopIteration:
    print("End of iterator")自定义迭代器
- 可迭代对象的 迭代器一旦被完全消费,状态不会重置 
- 每次需要重新迭代时,可以创建新的迭代器实例,或实现返回新迭代器实例的 - __iter__方法
class MyIterator:
    def __init__(self, data):
        print("Initializing MyIterator")
        self.data = data
        self.index = 0
    def __iter__(self):
        print("Calling __iter__")
        return self
    def __next__(self):
        print("Calling __next__")
        if self.index < len(self.data):
            result = self.data[self.index]
            self.index += 1
            return result
        raise StopIteration
# 创建可迭代对象和迭代器
test_list = [1, 2, 3, 4]
my_iterable = MyIterator(test_list)
# 初始化完成,打印类型
print(type(test_list))     # <class 'list'>
print(type(my_iterable))   # <class '__main__.MyIterator'>
# 使用 for 循环遍历
for item in my_iterable:
    print("Iterating item:", item)
# TODO:再次使用for循环,就不执行了
for item in my_iterable:
	print("Inerating angin", item)
##################
# 使用 for 循环遍历
for item in MyIterator(test_list):
    print(item)
# 再次创建新的迭代器实例
for item in MyIterator(test_list):
    print(item)区别和联系
- 可迭代对象:可以用 - iter()函数获取迭代器的对象。常见的内置类型如列表、元组、字符串等都是可迭代对象。
- 迭代器:实现了 - __iter__()和- __next__()方法的对象。迭代器本身也是可迭代对象,因为它实现了- __iter__()方法并返回自身。
常用的内置函数和方法
- iter(obj):获取对象的迭代器。
- next(iterator[, default]):获取迭代器的下一个元素,如果迭代结束则返回默认值(如果提供)。
- list()和tuple()中也可以传递可迭代对象
for循环的本质
- 先吊用 - iter()函数,它会自动调用可迭代对象中的- __iter__方法,返回这个可迭代对象的 迭代器
- 对获取到的迭代器 不断调用 - next()函数,它会自动调用迭代器中的- __next__方法来获取下一个值
- 但遇到 - StopInteration异常后,循环结束
生成器
生成器(Generator)是 Python 中的一种用于创建迭代器的简便方式,是一类特殊的迭代器
让你在迭代过程中产生值,而不需要一次性将所有值加载到内存中,大量数据或流式数据时特别有用(惰性求值)
基本概念
- 生成器函数:使用 - yield关键字的函数,这个函数在调用时返回一个生成器对象。
- 生成器表达式:类似于列表推导式,但使用小括号而不是方括号,返回一个生成器对象。 
特点
- 惰性求值:生成器按需生成值,可以节省内存。 
- 状态记忆:生成器在每次产生值后会记住其状态,下一次迭代会从上次停止的地方继续。 
生成器函数
使用 yield 关键字的函数会返回一个生成器对象
每次调用生成器的 __next__() 方法时,生成器函数会运行到下一个 yield 语句,返回相应的值,并暂停执行,保存当前的执行状态。
def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b
# 使用生成器函数
fib = fibonacci(10)
for num in fib:
    print(num)生成器表达式
生成器表达式使用类似列表推导式的语法,但用小括号包裹
它们返回一个生成器对象,可以像迭代器一样使用
# 创建一个生成器表达式,生成从0到9的平方数
squares = (x * x for x in range(10))
# 使用生成器
for square in squares:
    print(square)send、next的区别
在启动生成器时,第一个方法调用必须是
next或send(None),因为在生成器启动时没有yield语句可以接收值。
- 功能不同: - next方法:恢复生成器执行到下一个- yield语句,并返回该- yield语句的值。
- send方法:向生成器发送一个值,并恢复生成器执行到下一个- yield语句。发送的值成为上一个- yield表达式的返回值。
 
- 启动生成器: - next方法:可以用来启动生成器。
- send方法:必须以- send(None)的形式来启动生成器。
 
- 用法场景: - next方法:用于简单的值生成和迭代。
- send方法:用于需要向生成器内部传递数据的复杂交互。
 
def interactive_generator():
    print('Generator started')
    value = yield 1
    print(f'Received: {value}')
    value = yield 2
    print(f'Received: {value}')
    value = yield 3
    print(f'Received: {value}')
gen = interactive_generator()
# 启动生成器,必须使用 next 或 send(None)
print(next(gen))  # Generator started, 输出: 1
# 使用 send 向生成器发送数据,并继续执行到下一个 yield
print(gen.send('first'))  # Received: first, 输出: 2
print(gen.send('second'))  # Received: second, 输出: 3
# 生成器到此结束,再调用会引发 StopIteration 异常
# print(next(gen))  # 会引发 StopIteration 异常高级用法
斐波那契数列
斐波那契数列:
# 返回列表
def fib_list(n):
    if n == 1:
        return [1]
    if n == 2:
        return [1, 1]
    fibs = [1, 1]
    for i in range(2, n):
        fibs.append(fibs[-1] + fibs[-2])
    return fibs
# yield实现
def fib_yield(n):
    if n == 1:
        yield 1
    if n == 2:
        yield 1
        yield 1
    fibs = [1, 1]
    for i in range(2, n):
        fibs.append(fibs[-1] + fibs[-2])
        yield fibs[-1]
# 递归实现
def fib_recursion(n):
    if n == 1 or n == 2:
        return 1
    return fib_recursion(n - 1) + fib_recursion(n - 2)
# 返回单个值
def fib(n):
    if n == 1 or n == 2:
        return 1
    return fib(n - 1) + fib(n - 2)
print(fib_list(10))无限序列
生成器可以用于生成无限序列,只在需要时产生值。
def count(start=0, step=1):
    n = start
    while True:
        yield n
        n += step
# 使用无限生成器
counter = count(10, 2)
for _ in range(5):
    print(next(counter))管道模式
生成器可以通过管道模式连接,用于数据流的逐步处理。
def integers():
    for i in range(1, 9):
        yield i
def squared(seq):
    for i in seq:
        yield i * i
def negated(seq):
    for i in seq:
        yield -i
# 使用管道模式
numbers = integers()
squared_numbers = squared(numbers)
negated_numbers = negated(squared_numbers)
for num in negated_numbers:
    print(num) yield from
yield from 可以用于委托部分生成工作给另一个生成器。
def generator_a():
    yield 1
    yield 2
def generator_b():
    yield from generator_a()
    yield 3
    yield 4
# 使用生成器
for num in generator_b():
    print(num)总结
- 生成器函数:使用 - yield关键字定义,生成器函数每次暂停在- yield语句处,返回值并保存状态
- 生成器表达式:类似列表推导式,使用小括号,返回生成器对象 
- 优点:生成器惰性求值,节省内存,可以处理无限序列和管道数据流 
- 高级用法:无限序列、管道模式、`yield from` 用于简化生成器代码 
- 生成器是 Python 中处理大量数据和流式数据的强大工具,通过按需生成值来优化性能和内存使用 
yield拓展
yield与协程(coroutines)有密切关系
协程是一种更为复杂和灵活的生成器,用于实现多任务协作和异步编程
Python 中,yield和 yield from 可以用来创建简单的协程
yield 和 协程
- 生成器(Generators): - 生成器是使用 - yield关键字定义的函数,它们每次调用时生成一个值并暂停执行,保留当前的执行状态
- 生成器是协程的基础 
 
- 协程(Coroutines) - 协程是可以在执行过程中暂停并恢复的函数,允许在暂停点进行数据传输 
- 协程的一个显著特点是可以通过 - yield表达式接收外部发送的数据。
 
基本生成器示例
def simple_generator():
    yield 1
    yield 2
    yield 3
gen = simple_generator()
print(next(gen))  # 输出: 1
print(next(gen))  # 输出: 2
print(next(gen))  # 输出: 3协程示例
协程不仅可以产出值,还可以接收值。下面是一个简单的协程示例:
def simple_coroutine():
    print('Coroutine started')
    x = yield
    print(f'Coroutine received: {x}')
coro = simple_coroutine()
print(next(coro))  # 启动协程,输出: Coroutine started
print(coro.send(42))  # 向协程发送数据,输出: Coroutine received: 42在这个示例中,yield表达式不仅可以返回值,还可以通过 send 方法接收值
这个特性使协程能够在不同执行点之间交换数据。
yield from 和 子生成器
yield from 可以简化协程代码,使得一个生成器可以委派其部分操作给另一个生成器。
def generator_a():
    yield 1
    yield 2
def generator_b():
    yield from generator_a()
    yield 3
    yield 4
for value in generator_b():
    print(value)  # 输出: 1, 2, 3, 4async/await 
在 Python 3.5 引入了 async 和 await 关键字,用于创建和管理协程
这些关键字使得编写异步代码更加直观和强大
import asyncio
async def async_coroutine():
    print('Coroutine started')
    await asyncio.sleep(1)
    print('Coroutine ended')
# 运行协程
asyncio.run(async_coroutine())yield 与 async/await 的对比
- yield:用于生成器和协程,适用于简单的协作多任务和数据流操作
- async/await:用于现代协程,适用于异步编程和并发操作
总结
- 生成器:使用 - yield创建,主要用于逐步生成值
- 协程:使用 - yield和- yield from创建,允许在执行过程中暂停和恢复,可以在暂停点交换数据
- async/await:用于现代协程,提供更简洁的异步编程语法,适合处理 I/O 绑定和高并发任务 
yield是协程的基础,允许在执行过程中暂停和恢复而
async和await提供了更高层次的抽象,简化了异步编程模型
 
             
           
             
                         
             
            
评论区