[007]Python的函数_迭代器和生成器_全栈基础

您好!此笔记的文本和代码以网盘形式分享于文末!

因个人能力有限,错误处欢迎大家交流和指正!基础部分内容简单,但多且零散!

Python迭代器和生成器
迭代:可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代。
可迭代数据类型:字符串、列表、元组、字典、集合
可迭代协议:可迭代协议的定义非常简单,就是内部实现了__iter__方法
迭代器:迭代器是一个可以记住遍历的位置的对象,迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。节省内存
生成器:自己实现迭代器的功能代码叫生成器,在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
生成器的本质:就是迭代器,特点是惰性运算,开发者自定义;
生成器函数:一个包含yield关键字的函数就是一个生成器函数;
生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
生成器优点:延迟计算,一个返回一个结果,不会一次性生成所有结果,对于大数据处理很有意义。并且提高代码的可读性
用法栗子结果
迭代# 将数据集内的元素一个接一个取出来的过程叫做迭代
for i in [1, 2, 3, 'a']:
    print(i)
1
2
3
a
可迭代的数据类型# 字符串、列表、元组、字典、集合都是可迭代的
from collections import Iterable

s1 = '12ab'
li1 = [1, 2, 'a', 'b']
tu1 = (1, 2, 'a', 'c', )
di1 = {'a': 1, 'b': 2, }
se1 = {1, 2, 3, 4}
a = 123456789

print(isinstance(s1, Iterable))
print(isinstance(li1, Iterable))
print(isinstance(tu1, Iterable))
print(isinstance(di1, Iterable))
print(isinstance(se1, Iterable))
print(isinstance(a, Iterable))
True
True
True
True
True
False
可迭代协议:
内部实现了__iter__方法
# 对比可迭代数据类型中都有实现__iter__方法
print(dir(s1))
print(dir(tu1))
print(dir(a))
 
不同数据类型
中__iter__方法的包含
字典和集合的无序特性
其无__setstate__方法
print(set(dir(s1.__iter__())) - set(dir(s1)))
print(set(dir(li1.__iter__())) - set(dir(li1)))
print(set(dir(tu1.__iter__())) - set(dir(tu1)))
print(set(dir(di1.__iter__())) - set(dir(di1)))
print(set(dir(se1.__iter__())) - set(dir(se1)))
{'__next__', '__length_hint__', '__setstate__'}
{'__next__', '__length_hint__', '__setstate__'}
{'__next__', '__length_hint__', '__setstate__'}
{'__next__', '__length_hint__'}
{'__next__', '__length_hint__'}
三个方法的使用和介绍iter_1 = li1.__iter__()

# 获取迭代器中元素的长度
print(iter_1.__length_hint__())
# 根据索引值指定位置开始迭代
print(iter_1.__setstate__(2))

# 一个接一个的取值
print(iter_1.__next__())
print(iter_1.__next__())
4
None
a
b
__next__方法
及其异常处理
# __next__() 方法会由于无元素可取报异常
# 使用异常处理机制来处理掉异常
iter_1 = li1.__iter__()
while True:
    try:
        item = iter_1.__next__()
        print(item)
    except StopIteration:
        break
1
2
a
b
range()
是可迭代对象
但不是迭代器
from collections import Iterator
# range()关于iter和next方法测试
# 在range()执行后的内部是否有next和iter方法
print('__next__' in dir(range(12)))
print('__iter__' in dir(range(12)))

# 是否可迭代
print(isinstance(range(12), Iterable))
# 是否是迭代器
print(isinstance(range(12), Iterator))
False
True
True
False
生成器函数# 生成器函数
import time

def genrator_func():
    a = 1
    print('定义a 变量')
    yield a  # 暂停,等待下次next()方法的执行
    b = 2
    print('定义b变量')
    yield b
    c = 3
    print('定义c变量')
    yield c

gen1 = genrator_func()
print('g1: ', gen1)
print('-'*17)
print(next(gen1))
time.sleep(1)
print(next(gen1))
g1:  <generator object genrator_func at 0x000001BB7B30F990>
-----------------
定义a 变量
1
定义b变量
2
生成器函数二def produce():
    """
    生产定制手模
    月生产力最多13个
    """
    for i in range(13):
        yield '生产了第%d个手模' % i

produce_g = produce()

# 接受客户定制订单
print('请输入订单数量:')
num = int(input())

if num > 10:
    print('抱歉超过本月生产力,请返回重新输入!')

j = 0
for i in produce_g:
    if j < num <= 10:
        print(i)
        j += 1
    else:
        break

# 样品生产
print('样品展示:', '\n', produce_g.__next__())
print(next(produce_g))
请输入订单数量:
11
抱歉超过本月生产力,请返回重新输入!
样品展示:
 生产了第1个手模
生产了第2个手模
生成器监听文件输入列子  
.send应用
时间间隔可更清晰的
看到运行顺序
import time

def generator():
    print('开始')
    content = yield '返回1'
    print('第一个yield的值:', content)
    print('Two')
    content2 = yield '返回2'
    print('第二个yield的值:', content2)
    print('Three')
    content3 = yield "返回3"
    print('第三个yield的值:', content3)
    print('four')
    yield '第4次返回'

g = generator()
# 第一次运行只能使用next或send(None)
print(g.send(None))
print('\n')
time.sleep(6)
# send 作用相当于next方法并将传递参数为 yield的返回值
print(g.send('第2次传入参数'))
print('\n')
time.sleep(6)
# next方法 相当于 send(None) 即 temp = None
print(g.__next__())
print('\n')
time.sleep(6)
# 最后一个yield不能接受外部的值
print(g.send(None))
开始
返回1


第一个yield的值: 第2次传入参数
Two
返回2


第二个yield的值: None
Three
返回3


第三个yield的值: None
four
第4次返回
计算移动平均值import time

def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        print("第%d次执行" % count)
        term = yield average
        total += term
        count += 1
        average = total / count
        print('第%d次接收的term值为:' % count)
        print(term)

g_avg = averager()
print('第一次调用send')
print('第一次生成器yield返回值为', next(g_avg))
print('\n')
time.sleep(6)
print('第二次调用send')
print('第二次生成器yield返回值为', g_avg.send(15))
print('\n')
time.sleep(6)
print('第三次调用send')
print('第三次生成器yield返回值为', g_avg.send(30))
print('\n')
time.sleep(6)
print('第四次调用send')
print('第四次生成器yield返回值为', g_avg.send(10))
第一次调用send
第0次执行
第一次生成器yield返回值为 None


第二次调用send
第1次接收的term值为:
15
第1次执行
第二次生成器yield返回值为 15.0


第三次调用send
第2次接收的term值为:
30
第2次执行
第三次生成器yield返回值为 22.5


第四次调用send
第3次接收的term值为:
10
第3次执行
第四次生成器yield返回值为 18.333333333333332
计算移动平均值
预激协程
def init(func):
    def inner(*args, **kwargs):
        g = func(*args, **kwargs)
        next(g)
        return g
    return inner

@init
def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        print("第%d次执行" % count)
        term = yield average
        total += term
        count += 1
        average = total / count
        print('第%d次接收的term值为:' % count)
        print(term)

g_avg = averager()
print('\n', '开始')
print('第一次调用send')
print('第一次生成器yield返回值为', g_avg.send(15))
print('\n')
print('第二次调用send')
print('第二次生成器yield返回值为', g_avg.send(30))
print('\n')
print('第三次调用send')
print('第三次生成器yield返回值为', g_avg.send(10))
第0次执行

 开始
第一次调用send
第1次接收的term值为:
15
第1次执行
第一次生成器yield返回值为 15.0


第二次调用send
第2次接收的term值为:
30
第2次执行
第二次生成器yield返回值为 22.5


第三次调用send
第3次接收的term值为:
10
第3次执行
第三次生成器yield返回值为 18.333333333333332
yield fromdef gen1():
    for c in 'AB':
        yield c
    for i in range(3):
        yield i

print(list(gen1()))

def gen2():
    yield from 'AB'
    yield from range(3)

print(list(gen2()))
['A', 'B', 0, 1, 2]
['A', 'B', 0, 1, 2]
列表推导式1# 30以内所有能被3整除的数
multiples = [i for i in range(30) if i % 3 is 0]
print(multiples)
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
生成器表达式1# 生成器表达式
multiples1 = (i for i in range(30) if i % 3 is 0)
print(multiples1)
print(next(multiples1))
print(multiples1.__next__())
print(next(multiples1))
<generator object <genexpr> at 0x0000011DA10FF8E0>
0
3
6
列表推导式2
又称列表解析
缺点:内存占用大
机器容易卡死
multiples = [i for i in range(30) if i % 3 is 0]

def squared(x):
    return x ** 2

# 30以内所有能被3整除的数的平方
multiples2 = [squared(i) for i in range(30) if i % 3 is 0]
print(multiples2)
[0, 9, 36, 81, 144, 225, 324, 441, 576, 729]
生成器表达式2
优点:几乎不占内存
multiples3 = (squared(i) for i in range(30) if i % 3 is 0)
print(multiples3)
print(next(multiples3))
print(multiples3.__next__())
print(next(multiples3))
<generator object <genexpr> at 0x000002388D6BF990>
0
9
36
列表推导式3# 嵌套列表中查询 两个‘e’的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]

eenames = [name for lst in names for name in lst if name.count('e') >= 2]
print(eenames)
['Jefferson', 'Wesley', 'Steven', 'Jennifer']
生成器表达式3eenames1 = (name for lst in names for name in lst if name.count('e') >= 2)
print(eenames1)
print(next(eenames1))
print(eenames1.__next__())
print(next(eenames1))
<generator object <genexpr> at 0x0000024A95F9F9E8>
Jefferson
Wesley
Steven
python内置函数sum# 使用迭代器协议访问对象的函数sum
ret1 = sum(x ** 2 for x in range(4))
print(ret1)
14
字典推导式1# 将字典的Key和Value对调
dic1 = {'a': 1, 'b': 2, }
dic1_frequency = {dic1[k]: k for k in dic1}
print(dic1_frequency)
{1: 'a', 2: 'b'}
字典推导式2# 合并大小写对应的 value值,将K统一成小写
dic2 = {'a': 1, 'b': 2, 'A': 7, 'D': 6, }
print(list(k for k in dic2.keys()))
print(list(l1.lower() for k in dic2.keys() for l1 in k))
print(list(dic2.get(l1.lower()) for k in dic2.keys() for l1 in k))
print(list(dic2.get(l1.lower(), 0) for k in dic2.keys() for l1 in k))

print(list(l1.upper() for k in dic2.keys() for l1 in k))
print(list(dic2.get(l1.upper()) for k in dic2.keys() for l1 in k))
print(list(dic2.get(l1.upper(), 0) for k in dic2.keys() for l1 in k))


dic2_sortout = {k.lower(): dic2.get(k.lower(), 0) + dic2.get(k.upper(), 0) for k in dic2.keys()}
print(dic2_sortout)
['a', 'b', 'A', 'D']
['a', 'b', 'a', 'd']
[1, 2, 1, None]
[1, 2, 1, 0]
['A', 'B', 'A', 'D']
[7, None, 7, 6]
[7, 0, 7, 6]
{'a': 8, 'b': 2, 'd': 6}
集合推导式# 计算列表中每个值的平方且自带去重
squared = {x ** 2 for x in [1, -2, -1, 3]}
print(squared)
{1, 4, 9}
拓展1def demo():
    for i in range(4):
        yield i


g = demo()
g1 = (i for i in g)
g2 = (i for i in g1)
print(list(g1))
print(list(g2))
print('\n')

g3 = demo()
g4 = (i for i in g3)
g5 = (i for i in g4)
print(list(g5))
print(list(g4))
print('\n')

g6 = demo()
g7 = (i for i in g6)
g8 = (i for i in list(g7))
print(list(g8))
print('\n')

g9 = demo()
g10 = (i for i in g9)
g11 = (i for i in list(g10))
print(list(g11))
print(list(g10))
print('\n')

g12 = demo()
g13 = (i for i in g12)
print(list(g13))
g14 = (i for i in list(g13))
print(list(g11))
print('\n')
[0, 1, 2, 3]
[]


[0, 1, 2, 3]
[]


[0, 1, 2, 3]


[0, 1, 2, 3]
[]


[0, 1, 2, 3]
[]
拓展2def add(n, i):
    return n+i


def test():
    for i in range(4):
        yield i


g = test()
for n in [1, 10]:
    g = (add(n, i) for i in g)

print(list(g))
[20, 21, 22, 23]
拓展2def add(n, i):
    return n+i

def test():
    for i in range(4):
        yield i

print('g:')
g = test()
for n in [1, 10]:
    g = (add(n, i) for i in g)
print(list(g))

print('g1:')
g1 = test()
for n in [10, 1]:
    g1 = (add(n, i) for i in g1)
print(list(g1))

print('g12:')
g10 = test()
for n in [1, ]:
    g11 = (add(n, i) for i in g10)
for n in [10, ]:
    g12 = (add(n, i) for i in g11)
print(list(g12))
g:
[20, 21, 22, 23]
g1:
[2, 3, 4, 5]
g12:
[20, 21, 22, 23]

愿有更多的朋友,在网页笔记结构上分享更逻辑和易读的形式:

链接:暂无
提取码:暂无

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值