IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> python3之 生成器 -> 正文阅读

[Python知识库]python3之 生成器

一、什么是生成器?

我们知道,通过“列表生成式” 可以直接创建一个列表,但是列表生成式 存在一个缺陷:当列表生成式的数值非常大时,会出现运行缓慢,内存不足,若足够大,将造成计算机死机。一次性创建出一个列表,如果数值很大,就会占用很大的存储空间,而假如我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间就都白白浪费了。

那么是否有一种可以不用一次性创建,而是根据需要的时候再去推算出来,这样就不会占用很大的内存空间。

而“生成器” 就是因此诞生的。在Python中,这种一边循环一边计算的机制,一次生成一个值的特殊类型函数,称为生成器:generator

generator 是一个可迭代对象,那么它就是遵循迭代器协议的,要想获取元素,可以调用next()方法去获取,当然一般我们直接用for循环即可。

二、生成器的基本格式

(1)把一个“列表生成式” 的中括号 [] 改成 小括号 ()

(表达式 for 变量 in 序列)

举例:

g = (i for i in range(1, 10))
print(g)

输出结果:(是一个可迭代对象)

<generator object <genexpr> at 0x000001994DDFDBC8>

那么我们如果去取值呢?使用for循环。

g = (i for i in range(1, 10))
# print(g)

for x in g:
    print(x)

输出的结果:

1
2
3
4
5
6
7
8
9

(2)如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator 生成器
generator和函数的执行流程不一样。函数是顺序执行遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回再次执行时是从上次返回的yield语句处继续执行后面的语句

举例:

def odd():
    print("步骤1")
    yield 1
    print("步骤2")
    yield 2
    print("步骤3")
    yield 3


print(odd())  # 查看一下odd()是什么类型

输出的结果:(生成器,可迭代对象)

<generator object odd at 0x0000018B1E17D8C8>

再来看看在每次调用next()的时候执行后返回的结果:

def odd():
    print("步骤1")
    yield 1
    print("步骤2")
    yield 2
    print("步骤3")
    yield 3

o = odd()
print(next(o))

输出的结果:(可见遇到yield 就返回)

步骤1
1

连续执行两次next(o):

def odd():
    print("步骤1")
    yield 1
    print("步骤2")
    yield 2
    print("步骤3")
    yield 3


# print(odd())  # 查看一下odd()是什么类型
# 把可迭代对象 赋值给o
o = odd()
print(next(o))
print(next(o))

输出的结果:(可见遇到yield 就返回,再次执行,是从上次返回的yield语句处继续执行后面的语句)

步骤1
1
步骤2
2

连续执行三次next(o):

def odd():
    print("步骤1")
    yield 1
    print("步骤2")
    yield 2
    print("步骤3")
    yield 3


# print(odd())  # 查看一下odd()是什么类型
# 把可迭代对象 赋值给o
o = odd()
print(next(o))
print(next(o))
print(next(o))

输出的结果:(可见遇到yield 就返回,再次执行,是从上次返回的yield语句处继续执行后面的语句)

步骤1
1
步骤2
2
步骤3
3

三、练习题

(1)把以下fib()函数变成 generator

"""著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...
"""


# 用函数的方式
def fib(k):
    n, a, b = 0, 0, 1
    while n < k:
        print(b)
        a, b = b, a + b
        n = n + 1
    return "done"


o = fib(6)
print(o)

说明:

  a, b = b, a + b 赋值语句相当于:
  
  t = (b, a + b) # t是一个tuple
  a = t[0]
  b = t[1]
 

解答

仔细分析,其实fib()函数 实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑和生成器很类似。所以我们只需要把print(b) 改成 yield b ,就可以了。

# 用生成器(generator)的形式


def fib(k):
    n, a, b = 0, 0, 1
    while n < k:
        yield b  # 执行到这里就跳出循环了,再次执行的时候从下一条语句开始执行
        a, b = b, a + b
        n = n + 1
    return "done"


g = fib(6)  # 此时的fib(6) 是一个可迭代对象
print(g)

for i in g:
    print(i)

输出的结果:

<generator object fib at 0x00000130B79DDBC8>
1
1
2
3
5
8

但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:

def fib(k):
    n, a, b = 0, 0, 1
    while n < k:
        yield b  # 执行到这里就跳出循环了,再次执行的时候从下一条语句开始执行
        a, b = b, a + b  
        n = n + 1
    return "done"


g = fib(6)
while True:
    try:
        x = next(g)
        print(x)
    except StopIteration as e:
        print("Generator return value:", e.value)
        break

输出的结果:

1
1
2
3
5
8
Generator return value: done

(2)以list的方式不断输出杨辉三角的每一行。

"""
杨辉三角定义如下:

          1
         / \
        1   1
       / \ / \
      1   2   1
     / \ / \ / \
    1   3   3   1
   / \ / \ / \ / \
  1   4   6   4   1
 / \ / \ / \ / \ / \
1   5   10  10  5   1
把每一行看做一个list,试写一个generator,不断输出下一行的list:
"""

解答:

def triangles(k):
    L = [1]
    while True:
        yield L
        L = [L[i]+L[i+1] for i in range(len(L)-1)]  # 计算下一行的中间值,先不管头尾
        L.insert(0, 1)  # 在列表的第一位插入1
        L.append(1)  # 在列表的最后一位追加1
        if len(L) > k:
            break


g = triangles(10)
print(g)

for x in g:
    print(x)

输出的结果:

[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]

说明:


# my_list = [L[i]+L[i+1] for i in range(len(L)-1)]
# print(my_list)


"""
        L = [L[i]+L[i+1] for i in range(len(L)-1)]  相当于:
        my_list = []
        for i in range(len(L)-1):
        my_list.append(L[i] + L[i+1])
        print(my_list)
        """
  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-08-08 11:17:17  更:2021-08-08 11:20:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 10:00:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码