python生成器

利用迭代器,我们可以在每次迭代获取数据时(通过next()方法)按照特定规律进行生成。但是我们在实现一个迭代器时,关于当前迭代的状态需要我们自己记录,进而才能根据当前的状态生成下一个数据。为了达到纪录当前状态,并配合next()函数进行迭代使用,可以采用更简洁的语法。
生成器(generator),生成器是一种特殊迭代器,它比迭代器更优雅

生成器创建方法

1.把一个列表生成式的 [ ] 改成 ( )

li = [x ** 2 for x in range(6)]
print(li)
'''
[0, 1, 4, 9, 16, 25]
'''

gen = (x ** 2 for x in range(6))
print(gen)
'''
<generator object <genexpr> at 0x00000268D3C48BF8>
'''

print("通过next()函数取得下一个值")
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
'''
通过next()函数取得下一个值
0
1
4
9
16
25

'''

print("通过for遍历")
gen = (x ** 2 for x in range(6))
for i in gen:
    print(i, end=' ')
'''
通过for遍历
0 1 4 9 16 25 

'''

2.用函数实现

import collections


class FibIterator(object):
    """斐波那契数列迭代器"""

    def __init__(self, n):
        # 记录生成fibonacci的数列的个数
        self.n = n
        # 记录当前遍历的下标
        self.current_index = 0
        # 记录fibonacci数列前面的两个值
        self.num1 = 0
        self.num2 = 1

    def __next__(self):
        """被next()函数调用来获取下一个数"""
        if self.current_index < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1 + self.num2
            self.current_index += 1
            return num
        else:
            raise StopIteration

    def __iter__(self):
        """迭代器的__iter__返回自身即可"""
        return self

在用迭代器实现的方式中,我们要借助几个变量(n、current_index、num1、num2)来保存迭代的状态。现在我们用生成器来实现一下。

def fib(n):
    current_index = 0
    num1, num2 = 0, 1
    while current_index < n:
        # print(num1) # 打印斐波那契数列
        """
         1. 假如函数中有yield,则不再是函数,而是生成器
         2. yield 会产生一个断点
         3. 假如yield后面紧接着一个数据,就会把数据返回,
            作为next()函数或者for ...in...迭代出的下一个值
        """
        yield num1
        num1, num2 = num2, num1 + num2
        current_index += 1

if __name__ == '__main__':
    # 假如函数中有yield,则不再是函数,而是一个生成器
    gen = fib(5)

    #  生成器是一种特殊的迭代器
    for num in gen:
        print(num)

在使用生成器实现的方式中,我们将原本在迭代器__next__方法中实现的基本逻辑放到一个函数中来实现,但是将打印输出方式换成 yield,此时新定义的函数便不再是函数,而是一个生成器了。简单来说:只要在函数中有yield关键字的 就称为 生成器

此时按照调用函数的方式( 案例中为gen = fib(5) )使用生成器就不再是执行函数体了,而是会返回一个生成器对象( 案例中为gen ),然后就可以按照使用迭代器的方式来使用生成器了。

# 使用for...in ...打印生成器的内容

if __name__ == '__main__':
    # 假如函数中有yield,则不再是函数,而是一个生成器
    gen = fib(5)

    #  生成器是一种特殊的迭代器
    for num in gen:
        print(num)
'''
0
1
1
2
3
5
'''

生成器的执行过程

def fib(n):
    current_index = 0
    num1, num2 = 0, 1
    print("---1---")
    while current_index < n:
        print("---2---")
        # print(num1) # 打印斐波那契数列
        yield num1  # 假如函数中有yield,则不再是迭代器,而是生成器
        print("---3---")
        num1, num2 = num2, num1 + num2
        current_index += 1
        print("---4---")


if __name__ == '__main__':
    # 假如函数中有yield,则不再是函数,而是一个生成器
    gen = fib(5)

    # 取得生成器的下一个值
    print(next(gen))
    print(next(gen))
    print(next(gen))
'''
---1---
---2---
0
---3---
---4---
---2---
1
---3---
---4---
---2---
1
'''
  • 在函数中如果出现了yield关键字,那么该函数不再是一个普通函数而是一个生成器函数

  • yield关键字有两点作用:

    • 保存当前运行状态(断点),然后暂停执行,即将生成器(函数)挂起
    • 将yield关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用
  • 可以使用next()函数让生成器从断点处继续执行,即唤醒生成器(函数)

生成器支持的方法

  • close()

    • 手动关闭生成器函数,后面调用会直接引起StopIteration异常

      def gen():
          yield 1
          yield 2
          yield 3
          yield 4
      
      
      g = gen()
      print(next(g))
      print(next(g))
      g.close()
      print(next(g))  # 回溯
      '''
      1
      2
        
      StopIteration
      '''
      
  • send()

    • send()的作用就是使receive赋值为其所传送的值,然后让生成器执行到下一个yield
    • 如果生成器未启动,则必须在使用send()前启动生成器,而启动的方法可以是gen.next(),也可以是gen.send(None)执行到第一个yield处。之后就可以使用send()不断的传入值了
    • 如果已启动,则send(para)的作用就是给x付志伟发送的值(send的参数),然后让生成器执行到下一个yield
def gen():
    value = 0
    while True:
        receive = yield value
        if receive == "e":
            break
        value = "got:%s" % receive


# send()的作用就是使receive赋值为其所传送的值,然后让生成器执行到下一个yield

g = gen()
print(g.send(None))
print(g.send("aaa"))
print(g.send(123))
'''
0
got:aaa
got:123
'''
print(g.send("e"))
'''
StopIteration
'''
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值