生成器与迭代器(PY高级编程系列)

列表⽣成式

使用列表⽣成式, 可以创建列表; 但如果一个包含元素很多的列表, 占据的内存就很大;
而且这么多元素也不一定都完全使用, 这就浪费空间

generator生成器

generator生成器 (⼀边循环⼀边计算的机制), 元素都是有规律的, 是通过算法进行不断推算的, 只是使用时候会进行处理类型 range
保存了产生元素的算法 同时记录了当前游标位置(当前拿了第几个元素)
当生成器没有数据 再进行 next 会抛出StopIteration异常

列表⽣成式转为generator生成器 (第一种方法)

把最外层的中括号改为小括号

# 0~4 (包含0不包含5)的 2次方列表
a1 = [_ ** 2 for _ in range(5)]  # [0, 1, 4, 9, 16]
b1 = (_ ** 2 for _ in range(5))  # <generator object <genexpr> at ...>

print(a1, b1, sep='\n')
print(a1.__sizeof__(), b1.__sizeof__())  # 内存大小

maxSize = 10

a2 = range(maxSize + 1)  # 0 ~ 10 (包含10)
b2 = [_ for _ in a2]  # 这是列表式 占据可能比较大的内存(如果元素比较多) 但比 range 好, 可以把元素依次拿出来再处理
c2 = (_ for _ in a2)  # 生成器 generator (对象) 通过调用next函数获取值 不进行保存数据 每次调用时返回值 值的个数不定

print(a2, b2, c2, sep='\n')
print(a2.__sizeof__(), b2.__sizeof__(), c2.__sizeof__())  # 内存大小
print(len(a2), len(b2))  # 注意 生成器没有长度

01.生成器-001图

遍历生成器方法 (while/for)

# 注意 while 和 for 只能选择其中一种

# while
while True:
    try:
        d1 = next(c2)

        print('while', d1)
    except StopIteration as e:  # 当没有元素会报错
        break


a3 = (_ for _ in range(maxSize + 1) if _ % 2 == 0)  # 循环遍历+判断过滤

# for | 上面循环遍历会使游标移到最后 for的打印可能不执行
for k, _ in enumerate(a3):
    print('for', str(k).zfill(2), _)

01.生成器-002图

通过函数创建 (需要 函数内部使用 yield 关键字 | 使用scrapy爬虫时用过) (第二种方式)

# 以上列表生成式和生成器 个数都是有限的, 而且算法也比较简单
# 通过函数创建 (需要 函数内部使用 yield 关键字 | 使用scrapy爬虫时用过)
# 定义一个斐波那契数列函数
# 斐波那契数列 (Fibonacci sequence), 又称黄金分割数列
# 因数学家莱昂纳多·斐波那契 (Leonardo Fibonacci) 以兔子繁殖为例子而引入, 故又称为 "兔子数列"
# 在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2) (n ≥ 2,n ∈ N*)
# 0, 1, 1, 2, 3, 5, 8, 13, 21, 34,... | 数列
# 0, 1, 2, 3, 4, 5, 6, 07, 08, 09,... | 次数

def fibonacci_1(times):  # times: 次数 | 次数 >= 2 | 有限制的
    i = 0
    a, b = 0, 1
    
    while i < times:
        yield b  # b 斐波那契数列的元素 | yield 一般用于创建生成器 把yield后面变量值返回给生成器 不是返回给函数
        a, b = b, a + b  # a 和 b 重新赋值, 上一层的b值赋值给当前层a, 上一层的a+b的和赋值给b
        
        i += 1  # 层级数增加1


a4 = fibonacci_1(6)  # 当函数内有 yield 就是一个生成器
print(a4)
for k, _ in enumerate(a4):
    print('for', str(k).zfill(2), _)

print('-' * 80)


def fibonacci_2():  # 无限制
    a, b = 0, 1
    
    while True:  # 死循环
        t = yield b  # b 斐波那契数列的元素 | yield 一般用于创建生成器 把yield后面变量值返回给生成器 不是返回给函数
        a, b = b, a + b  # a 和 b 重新赋值, 上一层的b值赋值给当前层a, 上一层的a+b的和赋值给b
        print(t)  # 通过 next 多次可以返回一个 None, 当前层次并不会返回 | 这也说明 yield 没返回值


a5 = fibonacci_2()  # 当函数内有 yield 就是一个生成器 | 这个是无限的 别想用循环遍历 | 自然数的斐波那契数列
print(a5)
print(next(a5))  # 第1次
print(next(a5))  # 第2次 None出现在数字上面了
print(next(a5))  # 第3次 None出现在数字上面了
print(next(a5))  # 第4次 None出现在数字上面了
print(next(a5))  # 第5次 None出现在数字上面了
print(next(a5))  # 第6次 None出现在数字上面了
# 也可以这样打印
print(a5.__next__())  # 第7次 None出现在数字上面了
print(a5.__next__())  # 第8次 None出现在数字上面了
print(a5.__next__())  # 第9次 None出现在数字上面了
# 也可以这样 send 但第一个值必须 None 后面没所谓 但不能不传 | 不太好用
print(a5.send(None))
print(a5.send(0))  # 会把0也打印
print(a5.send(0))
print(a5.send(0))
print(a5.send(0))
print('end')


02.迭代器

说明

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

可以使用for循环的类型有:
一类是: 如list, tuple, dict, set, str…
一类是: 生成器(上面说的 generator)
这些统称为可迭代对象: Iterable

如何判断数据是否可迭代对象??

通过 isinstance(数据, 数据类型)

from collections.abc import Iterable

def isIterable(data):
    return isinstance(data, Iterable)


print(isIterable(range(5)))
print(isIterable([1, 2, 3, 4, 5]))
print(isIterable({}))
print(isIterable(tuple()))
print(isIterable((1, 2, 3, 4, 5)))

02.迭代器-001图

迭代器对象 Iterator

可以被next()函数调⽤并不断返回下⼀个值的对象称为迭代器
但注意 list, dict, str 都不是迭代器
这表示数据是个数据流, 未知长度, 是个有序序列,只能不断通过next() 函数实现按需计算下一个数据
计算是惰性的, 只有在需要返回下一个数据时它才会计算

from collections.abc import Iterator

def isIterator(data):  # 是否迭代器对象
    return isinstance(data, Iterator)


print('-' * 80)
print(isIterator(range(5)))
print(isIterator([1, 2, 3, 4, 5]))
print(isIterator({}))
print(isIterator(tuple()))
print(isIterator((1, 2, 3, 4, 5)))

02.迭代器-002图

这些都不是, 那些是呢?? 暂时只有生成器是

a2 = (_ for _ in range(5))
print(isIterator(a2))

02.迭代器-003图

把可迭代对象变成迭代器对象

在数据前加上iter

print('-' * 80)
print(isIterator(iter(range(5))))
print(isIterator(iter([1, 2, 3, 4, 5])))
print(isIterator(iter({})))
print(isIterator(iter(tuple())))
print(isIterator(iter((1, 2, 3, 4, 5))))

02.迭代器-004图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CY3761

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值