返回顶部
首页 > 资讯 > 后端开发 > Python >一文详解python生成器
  • 479
分享到

一文详解python生成器

python 2022-06-14 00:06:22 479人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

本篇文章给大家带来了关于python的相关知识,其中主要介绍了关于生成器的相关问题,包括了生成器的概念、生成器的执行过程、yield以及生成器方法等内容,下面一起来看一下,希望对大家有帮助。本篇文章给大家带来了关于Python的相关知识,其

本篇文章给大家带来了关于python的相关知识,其中主要介绍了关于生成器的相关问题,包括了生成器的概念、生成器的执行过程、yield以及生成器方法等内容,下面一起来看一下,希望对大家有帮助。

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于生成器的相关问题,包括了生成器的概念、生成器的执行过程、yield以及生成器方法等内容,下面一起来看一下,希望对大家有帮助。

1. 生成器概念

生成器(英文:generator)是一个非常迷人的东西,也常被认为是 Python 的高级编程技能。不过,我依然很

乐意在这里跟读者——尽管你可能是一个初学者——探讨这个话题,因为我相信各位大佬看本教程的目的,绝非仅仅 将自己限制于初学者水平,一定有一颗不羁的心——要成为 Python 高手。那么,开始了解生成器吧。

还记得上节的“迭代器”吗?生成器和迭代器有着一定的渊源关系。生成器必须是可迭代的,诚然它又不仅仅是

迭代器,但除此之外,又没有太多的别的用途,所以,我们可以把它理解为非常方便的自定义迭代器。

2. 简单的生成器

>>> my_generator = (x*x for x in range(4))

这是不是跟列表解析很类似呢?仔细观察,它不是列表,如果这样的得到的才是列表:

>>> my_list = [x*x for x in range(4)]

以上两的区别在于是 [] 还是 () ,虽然是细小的差别,但是结果完全不一样。

>>> dir(my_generator)
['__class__', '__delattr__', '__doc__', '__fORMat__', '__getattribute__', '__hash__', '__init__',
'__iter__',
'__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running',
'next',
'send', 'throw']

为了容易观察,我将上述结果进行了重新排版。是不是发现了在迭代器中必有的方法 __inter__() 和 next() ,这说明它是迭代器。如果是迭代器,就可以用 for 循环来依次读出其值

>>> for i in my_generator:
... print i
...
0
1
4
9
>>> for i in my_generator:
... print i
...

当第一遍循环的时候,将 my_generator 里面的值依次读出并打印,但是,当再读一次的时候,就发现没有任何结果。这种特性也正是迭代器所具有的。

如果对那个列表,就不一样了:

>>> for i in my_list:
... print i
...
0
1
4
9
>>> for i in my_list:
... print i
...
0
1
4
9

难道生成器就是把列表解析中的 [] 换成 () 就行了吗?这仅仅是生成器的一种表现形式和使用方法罢了,仿照

列表解析式的命名,可以称之为“生成器解析式”(或者:生成器推导式、生成器表达式)。

生成器解析式是有很多用途的,在不少地方替代列表,是一个不错的选择。特别是针对大量值的时候,如上节所说的,列表占内存较多,迭代器(生成器是迭代器)的优势就在于少占内存,因此无需将生成器(或者说是迭代器)实例化为一个列表,直接对其进行操作,方显示出其迭代的优势。比如:

>>> sum(i*i for i in range(10))
285

注意观察上面的 sum() 运算,不要以为里面少了一个括号,就是这么写。是不是很迷人?如果列表,你

不得不:

>>> sum([i*i for i in range(10)])
285

通过生成器解析式得到的生成器,掩盖了生成器的一些细节,并且适用领域也有限。下面就要剖析生成器的内部,深入理解这个魔法工具

3. 定义和执行过程

yield 这个词在汉语中有“生产、出产”之意,在 Python 中,它作为一个关键词(你在变量、函数、类的名称中

就不能用这个了),是生成器的标志。

>>> def g():
... yield 0
... yield 1
... yield 2
...
>>> g
<function g at 0xb71f3b8c>

建立了一个非常简单的函数,跟以往看到的函数唯一不同的地方是用了三个 yield 语句。然后进行下面的操作:

>>> ge = g()
>>> ge
<generator object g at 0xb7200edc>
>>> type(ge)
<type 'generator'>

上面建立的函数返回值是一个生成器(generator)类型的对象。

>>> dir(ge)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']

在这里看到了 __iter__() 和 next() ,说明它是迭代器。既然如此,当然可以:

>>> ge.next()
0
>>> ge.next()
1
>>> ge.next()
2
>>> ge.next()
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
StopIteration

从这个简单例子中可以看出,那个含有 yield 关键词的函数返回值是一个生成器类型的对象,这个生成器对象就是迭代器。

我们把含有 yield 语句的函数称作生成器。生成器是一种用普通函数语法定义的迭代器。通过上面的例子可以看出,这个生成器(也是迭代器),在定义过程中并没有像上节迭代器那样写 __inter__() 和 next() ,而是只要用了 yield 语句,那个普通函数就神奇般地成为了生成器,也就具备了迭代器的功能特性。

yield 语句的作用,就是在调用的时候返回相应的值。详细剖析一下上面的运行过程:

1. ge = g() :除了返回生成器之外,什么也没有操作,任何值也没有被返回。

2. ge.next() :直到这时候,生成器才开始执行,遇到了第一个 yield 语句,将值返回,并暂停执行(有的称之

为挂起)。

3. ge.next() :从上次暂停的位置开始,继续向下执行,遇到 yield 语句,将值返回,又暂停。

4. gen.next() :重复上面的操作。

5. gene.next() :从上面的挂起位置开始,但是后面没有可执行的了,于是 next() 发出异常。

从上面的执行过程中,发现 yield 除了作为生成器的标志之外,还有一个功能就是返回值。那么它跟 return 这个返回值有什么区别呢?

4. yield

为了弄清楚 yield 和 return 的区别,我写了两个函数来掩饰:

>>> def r_return(n):
... print "You taked me."
... while n > 0:
... print "before return"
... return n
... n -= 1
... print "after return"
...
>>> rr = r_return(3)
You taked me.
before return
>>> rr
3

从函数被调用的过程可以清晰看出, rr = r_return(3) ,函数体内的语句就开始执行了,遇到 return,将值返

回,然后就结束函数体内的执行。所以 return 后面的语句根本没有执行。这是 return 的特点

下面将 return 改为 yield:

>>> def y_yield(n):
... print "You taked me."
... while n > 0:
...     print "before yield"
...     yield n
...     n -= 1
...     print "after yield"
...
>>> yy = y_yield(3) #没有执行函数体内语句
>>> yy.next() #开始执行
You taked me.
before yield
3 #遇到 yield,返回值,并暂停
>>> yy.next() #从上次暂停位置开始继续执行
after yield
before yield
2 #又遇到 yield,返回值,并暂停
>>> yy.next() #重复上述过程
after yield
before yield
1
>>> yy.next()
after yield #没有满足条件的值,抛出异常
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
StopIteration

结合注释和前面对执行过程的分析,读者一定能理解 yield 的特点了,也深知与 return 的区别了。

一般的函数,都是止于 return。作为生成器的函数,由于有了 yield,则会遇到它挂起,如果还有 return,遇到它就直接抛出 SoptIteration 异常而中止迭代。

#!/usr/bin/env Python
# coding=utf-8

def fibs(max):
    """
    斐波那契数列的生成器
    """
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
if __name__ == "__main__":
    f = fibs(10)
    for i in f:
        print i ,

运行结果如下:

$ python 21501.py
1 1 2 3 5 8 13 21 34 55

用生成器方式实现的斐波那契数列是不是跟以前的有所不同了呢?大家可以将本教程中已经演示过的斐波那契数列实现方式做一下对比,体会各种方法的差异。

经过上面的各种例子,已经明确,一个函数中,只要包含了 yield 语句,它就是生成器,也是迭代器。这种方式显然比前面写迭代器的类要简便多了。但,并不意味着上节的就被抛弃。是生成器还是迭代器,都是根据具体的使用情景而定。

5. 生成器方法

在 python2.5 以后,生成器有了一个新特征,就是在开始运行后能够为生成器提供新的值。这就好似生成器

和“外界”之间进行数据交流。

>>> def repeater(n):
... while True:
...     n = (yield n)
...
>>> r = repeater(4)
>>> r.next()
4
>>> r.send("hello")
'hello

当执行到 r.next() 的时候,生成器开始执行,在内部遇到了 yield n 挂起。注意在生成器函数中, n = (yield

n) 中的 yield n 是一个表达式,并将结果赋值给 n,虽然不严格要求它必须用圆括号包裹,但是一般情况都这

么做,请大家也追随这个习惯。

当执行 r.send("hello") 的时候,原来已经被挂起的生成器(函数)又被唤醒,开始执行 n = (yield n) ,也就是

讲 send() 方法发送的值返回。这就是在运行后能够为生成器提供值的含义。

如果接下来再执行 r.next() 会怎样?

>>> r.next()

什么也没有,其实就是返回了 None。按照前面的叙述,读者可以看到,这次执行 r.next() ,由于没有传入任何值,yield 返回的就只能是 None.

还要注意,send() 方法必须在生成器运行后并挂起才能使用,也就是 yield 至少被执行一次。如果不是这样:

>>> s = repeater(5)
>>> s.send("how")
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
TypeError: can't send non-None value to a just-started generator

就报错了。但是,可将参数设为 None:

>>> s.send(None)
5

这是返回的是调用函数的时传入的值。

此外,还有两个方法:close() 和 throw()

• throw(type, value=None, traceback=None):用于在生成器内部(生成器的当前挂起处,或未启动时在定

义处)抛出一个异常(在 yield 表达式中)。

• close():调用时不用参数,用于关闭生成器。

推荐学习python视频教程

以上就是一文详解python生成器的详细内容,更多请关注编程网其它相关文章!

--结束END--

本文标题: 一文详解python生成器

本文链接: https://lsjlt.com/news/32908.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 一文详解python生成器
    本篇文章给大家带来了关于python的相关知识,其中主要介绍了关于生成器的相关问题,包括了生成器的概念、生成器的执行过程、yield以及生成器方法等内容,下面一起来看一下,希望对大家有帮助。本篇文章给大家带来了关于Python的相关知识,其...
    99+
    2022-06-14
    python
  • 一文详解Python中生成器的原理与使用
    目录什么是生成器迭代器和生成器的区别创建方式生成器表达式基本语法生成器函数yield关键字yield和returnyield的使用方法生成器函数的基本使用send的使用可迭代对象的优...
    99+
    2024-04-02
  • 一文详解Golang如何生成Excel文档
    本篇文章给大家带来了关于Golang的相关知识,其中主要跟大家介绍怎么用Golang生成Excel文档 ,感兴趣的朋友下面一起来看一下吧,希望对大家有帮助。基于数据生成 Excel 文档是一个很常见的需求,本文将介绍如何使用 Go 的 Ex...
    99+
    2023-05-14
    Excel 后端 Go
  • Python 3 之 生成器详解
    ------ 生成器 ------------------------------------------------------------------如今Python对延迟提供更多的支持——它提供了工具在需要的时候才产生结果,而不是立即...
    99+
    2023-01-31
    生成器 详解 Python
  • python迭代器,生成器详解
    目录迭代器 生成器 总结迭代器 聊迭代器前我们要先清楚迭代的概念:通常来讲从一个对象中依次取出数据,这个过程叫做遍历,这个手段称为迭代(重复执行某一段代码块,并将每一次迭代得到的结...
    99+
    2024-04-02
  • 详解Python生成器和基于生成器的协程
    目录一、什么是生成器二、基于生成器的协程三、协程的注意点四、协程装饰器五、python3原生协程一、什么是生成器 Generator 1.生成器就是可以生成值的函数 2.当一个函数里...
    99+
    2024-04-02
  • python迭代器与生成器详解
    例子 老规矩,先上一个代码: def add(s, x): return s + x def gen(): for i in range(4): yield i base = gen() ...
    99+
    2022-06-04
    生成器 详解 迭代
  • 一篇文章带你了解python迭代器和生成器
    目录python迭代器和生成器1、迭代器2、生成器总结python迭代器和生成器 1、迭代器 这里用字典示例 while True 属于无限循环,因字典元素有限,所以用try做...
    99+
    2024-04-02
  • 一文带你探寻Python中的生成器
    目录什么是python生成器为什么需要python生成器调用python程序内存信息辅助说明python案例代码运行程序运行后内存信息查看python生成器原理生成器表达式总结面试官...
    99+
    2023-05-15
    Python生成器原理 Python生成器使用 Python生成器
  • 详解如何通过Python制作一个密码生成器
    目录原由编程思路代码效果如下补充原由 定期更换密码是一种非常重要的安全措施,这种做法可以有效地保护你的账户和个人信息不受黑客和网络攻击者的侵害。 密码泄露是一个非常普遍的问题,许多人...
    99+
    2023-05-19
    Python实现密码生成器 Python密码生成器 Python密码
  • python 读取excel文件生成sql文件实例详解
    python 读取excel文件生成sql文件实例详解 学了python这么久,总算是在工作中用到一次。这次是为了从excel文件中读取数据然后写入到数据库中。这个逻辑用java来写的话就太重了,所以这次考...
    99+
    2022-06-04
    文件 详解 实例
  • 如何通过一篇文章了解Python中的生成器
    目录前言生成器也是迭代器生成器推导式无限生成器生成器实际用法1. 读取文件行2.读取文件内容高级生成器用法总结前言 生成器很容易实现,但却不容易理解。生成器也可用于创建迭代器,但生成...
    99+
    2024-04-02
  • Python 迭代器与生成器实例详解
    Python 迭代器与生成器实例详解 一、如何实现可迭代对象和迭代器对象 1.由可迭代对象得到迭代器对象 例如l就是可迭代对象,iter(l)是迭代器对象 In [1]: l = [1,2,3,4] ...
    99+
    2022-06-04
    生成器 详解 实例
  • Python异步之生成器示例详解
    目录正文1. 什么是异步生成器1.1. Generators1.2. Asynchronous Generators2. 如何使用异步生成器2.1. 定义2.2. 创建2.3. 一步...
    99+
    2023-03-22
    Python 异步生成器 Python 异步
  • 一文搞懂python中的迭代器和生成器
    可迭代对象和迭代器 迭代(iterate)意味着重复,就像 for 循环迭代序列和字典那样,但实际上也可使用 for 循环迭代其他对象:实现了方法 __iter__ 的对象(迭代器协...
    99+
    2024-04-02
  • MybatisPlus代码生成器含XML文件详解
    目录MybatisPlus代码生成器含XML所需依赖代码如下MybatisPlus代码生成器,自用版本不带xmlMybatisPlus代码生成器含XML 所需依赖         &...
    99+
    2024-04-02
  • caffe的python接口生成solver文件详解学习
    目录solver.prototxt的文件参数设置生成solver文件简便的方法训练模型(training)solver.prototxt的文件参数设置 caffe在训练的时候,需要一...
    99+
    2024-04-02
  • 一、python 生成一维码
    生活中到处可见一维码,几乎所有的正规产品上都可以看到,这几天好奇使用python可不可以实现生成一维码,并打印的功能,还真让我找到方法了,下面记录一下过程。 所需软件: pyBarcode 0.7 https://pypi....
    99+
    2023-01-31
    python 一维码
  • 详解OpenCV-Python Bindings如何生成
    目录目标OpenCV-Python bindings如何生成如何扩展新的模块到Python?目标 在本章中,将了解: 如何生成OpenCV-Python bindings如何将新的O...
    99+
    2023-05-12
    OpenCV-Python Bindings Python Bindings
  • python生成密码字典详解
    代码和代码运行的结果: 代码: import itertools as its words="rot123" a=its.product(words,repeat=4) name...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作