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知识库 -> python进阶【必会】(一)---------你会用python的生成器吗? -> 正文阅读

[Python知识库]python进阶【必会】(一)---------你会用python的生成器吗?

目录

🍉前言:

🍉什么是生成器:

🍉如何创建生成器:

1)小括号创建法

2)函数+yield关键字创建法

🍉如何使用生成器:

?????????? 1)利用next()语句:

?????????? 2)利用send()语句:

?????????? 3)利用for循环语句读取:

🍉总结


🍉前言:

对于python初学者来说,当我们试图去看一些开源的项目时,总会因为一些高级用法而卡住,诸如带有"yield"关键字的生成器,带有"@"符号的装饰器等等。这时,我们就需要主动去弄懂这些高级的用法,以求得到更快的进步。

所以,我希望从python的生成器开始,逐步的去总结一些高级的用法来和大家一起交流学习。文章结合了一些实例,力求通俗易懂,希望大家能静下心来不要跳读,这样才能得到更大的收获。

🍉什么是生成器:

在写python程序时,如果我们想要生成一组有规律的数据,可以利用for循环来生成并将数据存放在列表里,比如:

a = [x for x in range(10)]
print(a)

#运行结果:
#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

?但是,这种方式存在着一个问题。我们将全部数据都生成在列表里,可是很多时候我们不会全部的用到它们,这样,就浪费了内存空间。

所以,我们想,能不能按需的去执行这段代码,即每需要一个数据就去生成一个数据。换句话说,就是延缓这个for循环的执行过程,不让它一次跑完10轮,我们每调用它一次,它才执行一轮,才生成一个数据

这就是生成器(generator)。


🍉如何创建生成器:

理解了什么是生成器,那就来看如何创建一个生成器,下面介绍两种方法:

1)小括号创建法

a=(x for x in range(10))
print(type(a))

#运行结果:
#<class 'generator'>

?如图所示,我们将数据的生成规则用小括号围住,就创建了一个生成器类型的对象。

2)函数+yield关键字创建法

有时,我们想要表示的生成规则比较复杂,不能用一行代码表示。这时我们就需要把它写成一个多行的函数,通过调用这个函数就会返回一个生成器对象。

举个例子,如果我们想要生成斐波那契数列的前10个数,正常的函数写法是这样的:

def fib():
    n = 0
    a,b = 0,1
    while n<10:
        n+=1
        print(b,end=" ")
        a,b=b,a+b
fib()

#运行结果:
#1 1 2 3 5 8 13 21 34 55 

而如果我们在函数中加上关键字yield,就可以得到一个生成器,如图所示。

def fib():
    n = 0
    a,b = 0,1
    while n<10:
        n+=1
        print(b,end=" ")
        yield
        a,b=b,a+b
a = fib()
print(type(a))

#运行结果: 
#<class 'generator'>

🍉如何使用生成器:

现在我们创建好了一个生成器对象,该如何使用它呢,下面介绍三种使用生成器的方法。

1)利用next()语句:

def fib():
    n = 0
    a,b = 0,1
    while n<10:
        n+=1
        print(b)
        yield
        a,b=b,a+b

a = fib()
print(type(a))
print("第一次调用生成器生成了:",end="")
next(a)
print("第二次调用生成器生成了:",end="")
next(a)
print("第三次调用生成器生成了:",end="")
next(a)

"""
运行结果:
<class 'generator'>
第一次调用生成器生成了:1
第二次调用生成器生成了:1
第三次调用生成器生成了:2
"""

之前提到,生成器的核心思想就是延缓执行过程,按需执行。当我们需要它执行了,就去调用

next()方法,它就会执行一轮。

那怎样才算执行一轮呢,这就用到了yield关键字,yield在函数体中就起到了标识停止位置的作用。

当我们第一次调用next函数时,会从头开始执行生成器函数体中的语句,直到遇到yield关键字时停止执行,这就算完成了一轮的执行,而第二次调用next函数,又会在之前的停止位置继续执行,

直到遇到下一个yield再停止。

这样,这个函数的执行进度就牢牢的控制在我们的手中,其中,next()就相当于启动按钮,而yield就相当于我们设置的断点。

为了让大家更直观的看到yield的作用,下面这个动图展示了程序的单步执行过程:

另外还要注意的是,对于一个生成器来说,如果它的循环轮次是有限的,则我们可以调用的next次数就是有限的,比如上例,我们定义的生成器规则是生成数列的前10项,则当我们第11次调用next时就会抛出StopIteration

2)利用send()语句:

通过next()语句,我们实现了让生成器逐步的执行,但是如果我们想在每次执行时去给生成器传递参数,该怎么实现呢。这就需要要用到send()语句了,它不仅有着像next()语句一样的逐步执行功能,还支持参数的传递。

我们用 "生成器.send(要传递的参数)"这种方式来实现逐步执行+传递参数,我们传递的参数会被yield左边的变量接收。例:

def fib():
    while 1:
        send_num = yield
        print(send_num,end=" ")

a = fib()

a.send(None)
a.send(2)
a.send(3)

#运行结果:
#2 3

为什么参数会在yield处被接收呢,因为我们每次用next(这里是send)调用生成器时,总会在上次停止的位置开始执行,而上次停止的位置就恰好在yield这个断点上。

正是因为这个原因,我们不能在第一次调用生成器时就传递参数,因为第一次调用是从函数的第一句话开始执行,而不是在yield的位置,没有变量来接收参数,所以我们第一次调用时总会将None放在参数位置。

既然提到了为生成器传递参数,那如何让生成器返回参数呢,很简单,将我们希望返回的值添加到yield后面即可,比如:

def f():
    n = 0
    while n<10:
        n+=1
        yield n

a = f()
print(type(a))

num1 =next(a)
num2 =next(a)
num3 =next(a)
print("第一次调用生成器返回的值:",num1)
print("第二次调用生成器返回的值:",num2)
print("第三次调用生成器返回的值:",num3)

"""
运行结果:
第一次调用生成器返回的值: 1
第二次调用生成器返回的值: 2
第三次调用生成器返回的值: 3
"""

3)利用for循环语句读取:

我们通过next/send语句与函数中的yield关键字实现了延缓执行,但是有的时候我们也会想让这种按需执行的方式再连贯起来,比如我们想要利用一个已有的生成器去创建一个新的生成器,这时我们就可以利用生成器的可迭代的特性,用for循环来连贯的执行。

比如下面的例子,我们通过遍历生成器a,又生成了一个新的生成器b。

def natrual_number():
    n = 0
    while 1:
        yield n
        n+=1

a = natrual_number()
b = (x*x for x in a)
print(type(a),type(b))

#运行结果:
#<class 'generator'> <class 'generator'>

?这里来解释一下什么是可迭代对象(Iterable),可迭代对象就是可以使用for xx in 来取出自身元素的对象,比如list,dict,str,generator等类型,我们可以用python提供的isinstance方法来判断一个对象是否为可迭代的,代码如下,大家可以去测试一下。

from collections import Iterable
print(type([]),isinstance([],Iterable))
print(type({}),isinstance({},Iterable))
print(type("abc"),isinstance("abc",Iterable))
print(type((x for x in range(10))),isinstance((x for x in range(10)),Iterable))

#运行结果:
<class 'list'> True
<class 'dict'> True
<class 'str'> True
<class 'generator'> True

?利用for循环这种方法来使用我们的斐波那契生成器:

def fib():
    n = 0
    a,b = 0,1
    while n<10:
        n+=1
        print(b)
        yield
        a,b=b,a+b

a = fib()
for s in a:
    s

#运行结果:
#1 1 2 3 5 8 13 21 34 55 

🍉总结

综合来看,我觉得最重要的一点,就是要理解好我们为什么需要生成器,即,为了去延缓一个多轮的执行过程,让这个过程不要一次执行完。那该如何去实现延缓呢,即,利用next/send的启动作用,以及yield的断点作用来实现。理解了这些后,大家可以结合我上面给出的例子,去实战一下,自己编写几个生成器,这样能够更深刻的体会到生成器的作用。

以上,就是我对python生成器的一点总结和理解,希望对大家有些帮助。

如果您喜欢我的文章,请点赞关注,咱们一起学习一起进步!您的支持是我创作最大的动力!如有问题可以在评论区留言或者私信与我交流,我会尽力解答!咱们下篇文章见!

?

?

?

  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-12 16:33:29  更:2021-08-12 16:34:19 
 
开发: 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/19 19:04:15-

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