python的生成器

生成器

可以参考迭代器的博客,因为生成器就是一种特殊的迭代器

举例

def gen(num):
    while num > 0:
        yield num
        num -= 1
    return


g = gen(5)
print("生成器本身是一种特殊的迭代器,所以也可以使用for loop的方式来迭代")
for i in g:
    print(i)

gg = gen(7)
print("生成器也可以使用next方法")
first = next(gg)
for j in gg:
    print(j)

结果

生成器本身是一种特殊的迭代器,所以也可以使用for loop的方式来迭代
5
4
3
2
1
生成器也可以使用next方法
6
5
4
3
2
1

生成器函数和生成器对象

经常叫生成器,迭代器很好理解,就是class,但是生成器有所不同

g = gen(5)
g是生成器对象
gen(5)是生成器函数
调用生成器函数会生成一个生成器对象保存到g中,不会返回一个值,只有当你对这个生成器对象使用next函数的时候,他才开始真正运行他的函数本体
当python发现函数中有一个yield的时候,就会把这个函数打上一个标签,说这个是一个生成器函数
运行到yield的时候,把num返回出去了,但是这个函数还没运行完,相当于被按了一个暂停键,下次再运行next的时候,会继续运行yield下面的代码
在运行若干次之后,运行到num=0了,这个时候会运行这个return了,由于在生成器里面,这个return等价于raise StopIteration

从使用者的角度,生成器和迭代器没啥区别,但是在原理上

迭代器是把迭代的状态保存到了对象里

生成器是是把这个状态保存到了frame(栈帧)里,这个函数运行到哪一步了,而不是通过一个变量来存储现在的状态

class NodeIter:
    def __init__(self, node):
        self.curr_node = node

    def __next__(self):
        if self.curr_node is None:
            # 如果数据已经到头了,就需要抛出错误
            raise StopIteration
        # 没有到头的话,就返回这个node,并且把下一个值存储
        node, self.curr_node = self.curr_node, self.curr_node.next
        return node

    def __iter__(self):
        return self


class Node:
    def __init__(self, name):
        self.name = name
        self.next = None

    def __iter__(self):
        # Node是一个Iterable,但是他的__iter__方法,返回了一个iterator
        return NodeIter(self)


node1 = Node("Node1")
node2 = Node("Node2")
node3 = Node("Node3")
node1.next = node2
node2.next = node3

for node in node1:
    # 等于for node in iter(node1),向Iterable要了一个iterator
    print(node.name)

上面这个是一个自己写的迭代器,我们接下来给它改造成一个生成器

"""
#!/usr/bin/env python
# -*- coding:utf-8 -*-
@Project : pythonTest
@File : diedaiqi.py
@Author : 张胤
@Date : 2023/5/8 16:23
@Description:
"""


class Node:
    def __init__(self, name):
        self.name = name
        self.next = None

    def __iter__(self):
        # 直接把这个__iter__函数做成一个生成器,也就是当iter的时候返回的是一个生成器Object,这个生成器Object本身就是一个iterator
        node = self
        while node is not None:
            yield node
            node = node.next


node1 = Node("Node1")
node2 = Node("Node2")
node3 = Node("Node3")
node1.next = node2
node2.next = node3

for node in node1:
    print(node.name)

生成器相对于迭代器还有一个更高级的用法,就是send

就是在这个生成器yield之后,把这个yiled的什么东西变成一个值,这个值还可以继续复制给生成器

def gen(num):
    while num > 0:
        yield num
        num -= 1
    return


gg = gen(7)
print("生成器也可以使用next方法")
first = next(gg)
# gg.send(10)
for j in gg:
    print(j)

结果

6
5
4
3
2
1
def gen(num):
    while num > 0:
        yield num
        num -= 1
    return


gg = gen(7)
print("生成器也可以使用next方法")
first = next(gg)
gg.send(10)
for j in gg:
    print(j)

结果

5
4
3
2
1
def gen(num):
    while num > 0:
        temp = yield num
        # 首先会yield num,然后不管你是next还是send取出来的,会把这个值返回出去,然后接下来拿你send的值,对于生成器来说next(g)和g.send(Node)是一样的
        if temp is not None:
            num = temp
        num -= 1
    # return 写不写都可以,毕竟return = return None


gg = gen(7)
print("生成器也可以使用next方法")
first = next(gg)
print(f"send:{gg.send(10)}")
for j in gg:
    # next(g)=g.send(Node),tmp会一直被赋值为null,num的值不变
    print(j)

# num被赋值成了10,然后又-1,所以下一次yield出来是9

结果

生成器也可以使用next方法
send:9
8
7
6
5
4
3
2
1

你可能感兴趣的:(Python,python)