iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >python生成器怎么定义和使用
  • 480
分享到

python生成器怎么定义和使用

2023-07-02 08:07:18 480人浏览 泡泡鱼

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

摘要

本文小编为大家详细介绍“python生成器怎么定义和使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Python生成器怎么定义和使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1. 生成器概念生成器(英文:

本文小编为大家详细介绍“python生成器怎么定义和使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Python生成器怎么定义和使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

python生成器怎么定义和使用

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...0149>>> for i in my_generator:... print i...

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

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

>>> for i in my_list:... print i...0149>>> for i in my_list:... print i...0149

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

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

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

>>> 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 语句的作用,就是在调用的时候返回相应的值。详细剖析一下上面的运行过程:

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

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

为挂起)。

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

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

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>>> rr3

从函数被调用的过程可以清晰看出, 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 yield3 #遇到 yield,返回值,并暂停>>> yy.next() #从上次暂停位置开始继续执行after yieldbefore yield2 #又遇到 yield,返回值,并暂停>>> yy.next() #重复上述过程after yieldbefore yield1>>> 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-8def fibs(max):    """    斐波那契数列的生成器    """    n, a, b = 0, 0, 1    while n < max:        yield b        a, b = b, a + b        n = n + 1if __name__ == "__main__":    f = fibs(10)    for i in f:        print i ,

运行结果如下:

$ python 21501.py1 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://www.lsjlt.com/news/340570.html(转载时请注明来源链接)

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

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • python生成器怎么定义和使用
    本文小编为大家详细介绍“python生成器怎么定义和使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“python生成器怎么定义和使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1. 生成器概念生成器(英文:...
    99+
    2023-07-02
  • Python生成器怎么使用
    本篇内容介绍了“Python生成器怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!生成器仅仅拥有生成某种东西的能力,如果不用__nex...
    99+
    2023-06-17
  • python闭包怎么定义和使用
    闭包是指在函数内部定义的函数,并且该函数可以访问外部函数的变量。定义闭包的一般步骤如下:1. 在外部函数中定义一个内部函数。2. 内...
    99+
    2023-10-11
    python
  • 如何使用代码生成器自定义Entity
    今天小编给大家分享一下如何使用代码生成器自定义Entity的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。代码生成器自定义En...
    99+
    2023-06-30
  • Python生成器yield怎么使用
    这篇“Python生成器yield怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Python生成器yield怎么使用...
    99+
    2023-07-02
  • Python生成器和协程怎么用
    本篇内容主要讲解“Python生成器和协程怎么用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python生成器和协程怎么用”吧!认识生成器你将如何生成任意长度...
    99+
    2024-04-02
  • CSS派生选择器怎么定义使用
    这篇文章主要讲解了“CSS派生选择器怎么定义使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“CSS派生选择器怎么定义使用”吧!CSS派生选择器通过依据元素在其位置的上下文关系来定义样式,你...
    99+
    2023-07-04
  • Python中怎么定义和使用元组
    本篇内容介绍了“Python中怎么定义和使用元组”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!定义和使用元组在Python中,元组也是多个元...
    99+
    2023-06-01
  • python长整型怎么定义和使用
    在Python中,长整型可以通过在数字后面添加"L"或"l"来定义。长整型可以表示任意大的整数,不受默认整型的范围限制。示例代码如下:```python# 定义长整型long_num = 12345678901234567890L# 输...
    99+
    2023-08-11
    python
  • Python枚举类怎么定义和使用
    本篇内容主要讲解“Python枚举类怎么定义和使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python枚举类怎么定义和使用”吧!一些具有特殊含义的类,其实例化对象的个数往往是固定的,比如用...
    99+
    2023-06-30
  • python列表生成器怎么使用
    本篇内容介绍了“python列表生成器怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!列表生成式基础语法[exp for iter_v...
    99+
    2023-07-02
  • 用 Python 定义 Schema 并生成 Parquet 文件详情
    目录一、简单字段定义1、定义 Schema 并生成 Parquet 文件2、验证 Parquet 数据文件二、含嵌套字段定义1、验证 Parquet 数据文件 Java 和 Pyth...
    99+
    2024-04-02
  • python怎么使用send启动生成器
    小编给大家分享一下python怎么使用send启动生成器,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1、说明send方法启动生成器的时候可以传参数。如果第一次启...
    99+
    2023-06-15
  • Python异步之生成器怎么使用
    这篇文章主要介绍“Python异步之生成器怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Python异步之生成器怎么使用”文章能帮助大家解决问题。正文生成器是 Python 的基本组成部分。...
    99+
    2023-07-05
  • python生成器和yield关键字怎么用
    这篇文章主要介绍了python生成器和yield关键字怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。下列代码用于先体验普通列表推导式和生成器的差别:# def...
    99+
    2023-06-26
  • python中的迭代器和生成器怎么用
    这篇“python中的迭代器和生成器怎么用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“python中的迭代器和生成器怎么用...
    99+
    2023-06-29
  • 使用代码生成器自定义Entity的部分注解
    目录代码生成器自定义Entity部分注解前因查找了我的代码生成器那个配置类随后在templates/entity.java.ftl里还有一点代码生成器最新版配置方案代码生成器自定义E...
    99+
    2024-04-02
  • Python、Linux和Apache:如何生成可自定义的二维码?
    随着二维码在各个领域的应用日益普及,越来越多的人开始关注如何生成可自定义的二维码。在这篇文章中,我们将介绍如何使用Python、Linux和Apache生成可自定义的二维码。 一、Python生成二维码 Python是一种强大的编程语言,...
    99+
    2023-07-23
    linux apache 二维码
  • Python中迭代器与生成器怎么使用
    一、迭代器(foreach)1、可迭代的对象内置有__iter__方法的都叫可迭代的对象。Python内置str、list、tuple、dict、set、file都是可迭代对象。x = 1.__iter__ # SyntaxError: ...
    99+
    2023-05-22
    Python
  • php interface怎么定义和使用
    在PHP中,可以使用interface关键字来定义一个接口。接口是一种规范,用于定义类应该实现的方法。一个类可以实现一个或多个接口,...
    99+
    2023-10-22
    php
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作