Python学习 之 迭代器和生成器

本文深入探讨了Python中迭代器和生成器的概念及其应用。包括如何创建和使用迭代器,生成器的基本原理及四种创建方式,同时展示了如何通过生成器节省内存资源,并介绍了生成器的高级用法如预激生成器和给生成器传值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


迭代器

简介

  • 特点
    • 可以被for循环
    • 节省内存空间
    • 没有索引取值的概念, 所以只能依次取值, 不会被跳过
  • 可迭代的数据类型
    • list, dict, tuple, str, range, set
  • 可迭代协议: 在内部实现了__iter__方法, 查看示例: dir(range)
  • 迭代器协议: 迭代器协议在内部实现__iter__方法和__next__方法

可迭代对象 --> 迭代器

"""
	可迭代对象.__iter__() --> 迭代器
	next(迭代器) 或者 迭代器.__next__() --> 从迭代器中取值

"""

# 列表是可迭代对象
l = [1,2,3]

# 可迭代对象.__iter__() --> 变成了迭代器 
i = l.__iter__()

while True:
	# try..excpt是用来捕捉报错的语句
	try:
		# print(i.__next__())
		# 等同于
		print(next(a))
	except: StopIteration:
		break
		

判断是否为可迭代对象或迭代器

from collections import Iterable,Iterator

# 这是一个可迭代对象, 但不是迭代器
a = [1,2,3]
print(isinstance(a, Iterable)) # 判断a是不是可迭代的	--> True
print(isinstance(a, Iterator)) # 判断a是不是迭代器   	--> False

# 将可迭代对象转化成迭代器
b = a.__iter__() 
print(isinstance(b, Iterable)) # 判断a是不是可迭代的	--> True
print(isinstance(b, Iterator)) # 判断a是不是迭代器		--> True


生成器

简介

  • 定义
    • 由开发者自定义的迭代器, 称为生成器
    • 本质就是迭代器
  • 要点
    • 一个生成器只能取一次值 ☆☆☆☆☆
    • 不调用的时候不会执行

创建生成器 - 4种方式

# 1. 用迭代对象.__iter__()
g = range(5).__iter__()


# 2. 生成器表达式
# 语法: (result for循环 [if判断])
g = (i for i in range(10) if i % 2 == 0) # 此时 g 是一个生成器


# 3. yield 生成器函数
# 包含yield关键字的函数, 就是生成器函数
# 
def G():
	for i in range(10)
		yield i # yield 右侧就是被作为返回值放入生成器的

g = G() # 此时 g 是一个生成器


# 4. yield from, 也是生成器函数
def G2():
	yield from range(10)

g = G2() # 效果同上	


取值 - 4种方式

# 创建一个生成器
g = range(10).__iter__()

# next(), 每次执行, 将 yield 右侧的值作为返回值, 左侧如果有赋值语句, 等下次 next() 执行
print(next(g))  # 结果为0

# __next__()
print(g.__next__()) # 结果为 1

# for
for i in g:
	print(i)

# list, 类型强转
print(list(g))

# 注意: 如果使用生成器函数创建生成器, 每次执行函数都会创建新的生成器, 所有要将生成器保存用来使用


示例

  • 实现 range() 函数
    def myRange(start, end, step=1):
    	# 起始值 < 结束值
        while start < end:
        	# 将起始值放入迭代器
            yield start
            # 按照步长增加
            start += step
    
    # 验证
    for i in myRange(1,5,2):
    	print(i)
    
    
  • 实现 tail -f “a.txt” | grep “404”
    import time
    
    def myTail(fileName, grepStr):
        with open(fileName, "r") as f:
        	# 光标放到最后
            f.seek(0, 2)
            while 1:
            	# 拿到单行的数据, 如果到末尾, readline() 会返回空
                l = f.readline().strip()
                # 如果 l 为真, 且过滤的字符串在 l 中, 那么就将 l 放入生成器
                if l and grepStr in l:
                    yield l
                else:
                	# 否则停止 0.05 秒
                    time.sleep(0.05)
    
    # 循环验证
    while 1:
        for l in myTail("a.txt", "404"):
            print(l)
    	
    

其他用法

给生成器传值

  1. 定义生成器
  2. 创建生成器
  3. 激活生成器: next()
  4. 执行 send 方法
    1. 先将值赋值给 yield, 再通过 yield 赋值给等号左边的变量名
    2. 执行 next() 方法
# 定义一个生成器
def G():
	ret1 = yield 			# 激活, yield 右侧没有值, 说明没有值放入生成器
							# send(1), 将 1 赋值给 ret1, 执行 next()
	ret2 = yield ret1		# 将 ret1 放入生成器, 取出得到 1
							# send(10), 将 10 赋值给 ret2, 执行 next()
	ret3 = yield ret2		# 将 ret2 放入生成器, 取出得到 10
							# send(100), 将 100 赋值给 ret3,  先执行 ret3=ret3+100, 再执行 next()
	ret3 = ret3 + 100		
	yield ret3				# 将 ret3 放入生成器, 取出得到 200
	
# 创建
g = G()
# 激活
print(next(g))				# None

# 传参
print(g.send(1))
print(g.send(10))
print(g.send(100))


预激生成器 - 通过装饰器实现

def wrapper(func):
	def inner(*args, **kwargs):
		ret = func(*args, **kwargs)
		# 在装饰器中激活
		next(ret)
		return ret
	return inner

@wrapper
def G():
   	ret1 = yield
	ret2 = yield ret1
	ret3 = yield ret2
	ret3 = ret3 + 100		
	yield ret3

# 拿到生成器, 因为在装饰器中已经激活过, 所以不需要重复激活
g = G()

print(g.send(10))
print(g.send(20))
print(g.send(30))


列表推导式, 生成器表达式, 字典推导式, 集合推导式

  • 列表推导式
    """ 返回一个列表 """
    
    # [返回值 for循环 if判断]
    
    l = [i for i in range(10) if i % 2 == 0]
    print(type(l), list(l)) # <class 'list'> [0, 2, 4, 6, 8]
    
    
  • 生成器表达式
    """ 返回一个生成器 """
    	
    # (返回值 for循环 if判断)
    
    g = (i for i in range(10) if i % 2 == 0)
    print(type(g), list(g)) # <class 'generator'> [0, 2, 4, 6, 8]
    
    
  • 字典推导式
    k = ["a", "b"]
    v = [1, 2]
    
    d = {k[i]:v[i] for i in range(len(k))}
    
    print(type(d), d) # <class 'dict'> {'a': 1, 'b': 2}
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值