迭代器和生成器

本文详细介绍了迭代器的概念,可迭代对象的特性及其在Python中的应用,包括列表推导式、yield关键字的生成器以及装饰器与生成器的结合。重点讲述了如何创建和使用生成器,以及生成器如何处理可变数据类型。
摘要由CSDN通过智能技术生成

迭代器

【一】迭代器介绍

  • 迭代器就是用来迭代取值的工具,而迭代是重复反馈过程的活动

    • 其目的通常是为了逼近所需的目标或结果,每一次对过程的重复称为一次“迭代”

    • 而每一次迭代得到的结果会作为下一次迭代的初始值,单纯的重复不是迭代

goods = ['gdy', 'knight', 'acer', 'dell', 'sony']
​
index = 0
while index < len(goods):
    print(goods[index])             # 将列表中每一个元素都单独输出一次
    index += 1              

【二】可迭代对象

【1】什么是可迭代对象
  • 通过索引的方式进行迭代取值,很简单

    • 但仅适用于序列类型:字符串,列表 ,元组。对于没有索引的字典、集合等非序列类型

    • 必须找到一种不依赖索引来进行迭代取值的方式,这就需要迭代器

  • 想要了解迭代器就必须要先搞清楚什么是可迭代对象(lterable)

【2】可迭代对象
  • 从语法形式上讲,内置有iter的方法的对象就是可迭代对象

# 【1】整数类型
age = 18
print(age.__iter__)     # 'int' object has no attribute '__iter__'
# 【2】浮点数类型
salary = 100.00
print(salary.__iter__)      # 'float' object has no attribute '__iter__'
# 【3】字符串类型
name = 'knight'
print(name.__iter__())      # <str_iterator object at 0x0000023ADAF1A800>
# 【4】列表类型
num_list = [1,2,3]
print(num_list.__iter__())      # <list_iterator object at 0x000001A797E1A800>
# 【5】字典类型
data_dict = {'name':'knight'}
print(data_dict.__iter__())     # <dict_keyiterator object at 0x000001FE0D2B3880>
# 【6】布尔类型
is_true = True
print(is_true.__iter__)     # 'bool' object has no attribute '__iter__'
# 【7】元组类型
num_tuple = (1,2,3)
print(num_tuple.__iter__())     # <tuple_iterator object at 0x0000020FBA5EA800>
# 【8】集合类型
num_set = {1,2,3,4}
print(num_set.__iter__())   # <set_iterator object at 0x000001A8DF0C01C0>
【3】总结

可迭代类型:字符串、列表、元组、集合、字典

不可迭代类型:整数、浮点数、布尔

【三】迭代器对象

【1】生成可迭代对象的两种方式
# 【1】__iter__()
name = 'knight'
print(name.__iter__())      # <str_iterator object at 0x000002B70671A800>
# 【2】iter(数据)
print(iter(name))       # <str_iterator object at 0x000002B70671A800>
【2】迭代器对象取值next
name = 'knight'
name_iter = iter(name)
# 方法一
print(name_iter.__next__())         # k
print(name_iter.__next__())         # n
print(name_iter.__next__())         # i
# 方法二
print(next(name_iter))              # g
数据类型的
# 调用obj.__iter__()方法返回的结果就是一个迭代器对象
# 迭代器对象是内置有iter和next方法的对象,打开的文件本身就是一个迭代器对象
# 【1】字符串
name = 'knight'
name_iter = name.__iter__()
print(name_iter)        # <str_iterator object at 0x0000015CFFB8A800>
print(name_iter.__next__())     # k
print(name_iter.__next__())     # n
print(name_iter.__next__())     # i
print(name_iter.__next__())     # g
#【2】列表
num_list = [1,2,3]
num_list_iter = iter(num_list)
print(next(num_list_iter))          # 1
#【3】字典
user_dict = {'name':'knight'}
user_dict_iter = iter(user_dict)
print(user_dict_iter.__next__())    # name
#【4】元组
num_tuple = (1,2,3)
num_tuple_iter = iter(num_tuple)
print(next(num_tuple_iter))         # 1
#【5】集合
num_set = {1,2,3}
num_set_iter = iter(num_set)
print(next(num_set_iter))       # 1
【3】总结

具有iter和next的对象就是迭代器对象

在八大基本数据类型中除了整数、浮点数、布尔,其他都是迭代对象

【四】迭代器的优缺点

  • 优点

    • 不使用索引取值(字典是不支持索引取值的)

    • 取到这个值的时候就会保存到当前状态,下一次从这个位置开始向下取值

  • 缺点

    • 除非取值取到尽头否则永远不知道终止索引在哪里

    • 取一次记一次位置,下一次的其实位置是上一次的终止位置,无法回头

    • 调用next取值的前提是已经生成并且得到了一个迭代器对象iter

    • 同一个对象想要再次迭代只能重新创建迭代器对象

生成器

【一】什么是生成器

  • 生成器是一种特殊的迭代器

  • 在你需要的时候就给你数据,你不需要就不给

【二】生成器的创建方式

【1】列表推导式
print([i for i in range(10)])   # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 如果将列表生成是外面的的方括号换成元组就会生成一个生成器对象
print((i for i in range(10)))   # <generator object <genexpr> at 0x000001CB3F124270>
【2】yield 关键字
def add(i):
    yield i
​
​
add(2)      # 会进入到add函数,将原本的函数对象转换为生成器对象
res = add(2)    # <generator object add at 0x000002AD9BBDCBA0>
print(res.__next__())   # 想取值只能是 next 迭代取值
def add(i):
    # i = 1
    while True:
        yield i     # 第一次 next
​
​
res = add(1)
print(res)  # <generator object add at 0x000002810B67CBA0>
print(next(res))  # 1
print(next(res))  # 1
res = add(2)
print(next(res))  # 1
print(next(res))  # 1

【三】生成器案例

# 【一】调用函数
def eater():
    print('开始吃饭 ovo ')
    while True:
        food = yield
        print(f'得到的食物是 :>>>> {food}, 开始吃饭喽 :>>>> {food}')


res = eater()
print(res)  # <generator object eater at 0x000002094832AAC0>
print(res.__next__())
# 打印开始吃饭
# None   原因就是在生成器内部的 yield 中没有返回值
print(res.__next__())
# 打印 得到的食物是 :>>>> None, 开始吃饭喽 :>>>> None
# None  原因就是在生成器内部的走完了上面的 又回到了 yield 中结果 yield 没有返回值

# 【二】向生成器中传值
def eater():
    print('开始吃饭 ovo ')
    while True:
        food = yield
        print(f'得到的食物是 :>>>> {food}, 开始吃饭喽 :>>>> {food}')
        
res = eater()
# print(res)
print(res.__next__())
res.send("青椒肉丝")        # 向yield传值,并且让生成器继续向下走
print(res.__next__())
res.send("芹菜肉丝")
print(res.__next__())

【四】装饰器 + 生成器

def init_iter(func):
    # func 我的生成器函数
    def inner(*args, **kwargs):
        # g 得到的生成器对象
        g = func(*args, **kwargs)
        # 调用自己生成器向下走
        next(g)
        # 走回来的返回值返回出去
        return g

    return inner


@init_iter
def eater():
    print('开始吃饭 ovo ')
    while True:
        food = yield
        print(f'得到的食物是 :>>>> {food}, 开始吃饭喽 :>>>> {food}')


res = eater()
res.send("鱼香肉丝")
res.send("宫保鸡丁")

【五】生成器内部修改可变数据类型

def init_iter(func):
    # func 我的生成器函数
    def inner(*args, **kwargs):
        # g 得到的生成器对象
        g = func(*args, **kwargs)
        # 调用自己生成器向下走
        next(g)
        # 走回来的返回值返回出去
        return g
    return inner
@init_iter
def eater():
    print('开始吃饭')
    food_list = []
    while True:
        food = yield
        food_list.append(food)
        print(f'得到的食物:{food}')
        print(f'当前后厨已经做好了:{food_list}')
​
​
res = eater()
res.send("青椒肉丝")
res.send("芹菜肉丝")
​
# 开始吃饭
# 得到的食物:青椒肉丝
# 当前后厨已经做好了:['青椒肉丝']
# 得到的食物:芹菜肉丝
# 当前后厨已经做好了:['青椒肉丝', '芹菜肉丝']
  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值