广告
返回顶部
首页 > 资讯 > 后端开发 > Python >python 生成器
  • 596
分享到

python 生成器

生成器python 2023-01-30 21:01:23 596人浏览 安东尼

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

摘要

先来讲一个列表生成式列表生成式:就是一个用来生成列表的特定语法形式的表达式。基础语法格式[exp for iter_var in iterable]普通创建列表是这样的a = [1

先来讲一个列表生成式

列表生成式:就是一个用来生成列表的特定语法形式的表达式。


基础语法格式

[exp for iter_var in iterable]


普通创建列表是这样的

a = [1,2,3]

如果想要生成0到9的列表,一个个写太麻烦了。用列表生成式,就简单多了

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

执行输出

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


值还可以做计算,比如

a = [i*2 for i in range(10)]
print(a)

执行输出

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]


上面一句代码,相当于运行了3行代码

a = []
for i in range(10):
    a.append(i*2)
print(a)

执行输出,同上。



python中,这种一边循环一边计算的机制,称为生成器:generator。

要创建一个generator,有很多种方法。

第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

a = (i*2 for i in range(5))
print(a)

执行输出

<generator object

这是一个生成器对象,它保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。


通过__next__()方法,获取下一个内容,打印3个数据

a = (i*2 for i in range(5))
print(a.__next__())
print(a.__next__())
print(a.__next__())

执行输出

0

2

4


如果数据很多呢?方法是使用for循环,因为generator也是可迭代对象:

a = (i*2 for i in range(5))
for i in a:
    print(i)

执行输出

0

2

4

6

8


下面对比一下列表生成式和生成器,生成一百万数据,哪个比较快

#!/usr/bin/env Pythoncoding: utf-8
__author__ = 'www.py3study.com'

import time

#获取函数执行时间
def exec_time(func):
    start_time = time.time()
    func()
    stop_time = time.time()
    print('the variable run time is %s' % (stop_time - start_time))

#列表生成式
def a():
    list_gen = [i * 2 for i in range(10000000)]

#生成器
def b():
    iteration = (i * 2 for i in range(10000000))

exec_time(a)
exec_time(b)

执行输出

the variable run time is 1.0684430599212646

the variable run time is 0.0


很明显,生成器要快。为什么呢?因为它不存储所有值,而列表生成器存储了所有的值。


再举个例子

a = [i*2 for i in range(1000)]
b = (i*2 for i in range(1000))

输出a的第100个值

print(a[100])

执行输出 200


输出b的第100个值

print(b[100])

执行报错

TypeError: 'generator' object is not subscriptable

为什么呢?因为前面的数据还没跑,直接咔嚓跳到100,找不到了。

它不支持像列表的获取,切片等操作。

它只有一种方式,就是一个个去取。


总结

生成器 只有在调用时才会生成相应的数据

只记录当前的位置

只有一个__next__()方法,基本不会用到它,一般通过for循环来迭代它。


generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

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

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

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return 'done'

fib(10)

执行输出

1

1

2

3

5

8

13

21

34

55


a,b表示每个数字的前2个值,n表示第几个数

a, b = b, a + b

相当于

t = (b, a + b) # t是一个tuple
a = t[0]
b = t[1]

比如a等于2,后一个数是前2个数的和,也就是1+2,那么b等于3

每循环一次,把a向前推1个位置。


但不必显式写出临时变量t就可以赋值。

上面的函数可以输出斐波那契数列的前N个数:


仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:

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

print(fib(10))

执行输出

generator object fib at 0x0000029FC0F00F68


这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:


这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

f = fib(10)
print(f.__next__())
print(f.__next__())
print("============")
print(f.__next__())
print(f.__next__())

执行输出

1

1

============

2

3


在上面fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。


同样的,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:

f = fib(10)
for i in f:
    print(i)


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

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

f = fib(10)
while True:
    try:
        x = next(f)
        print('f:', x)
    except StopIteration as e:
        print('Generator return value:', e.value)
        break

执行输出

f: 1

f: 1

f: 2

f: 3

f: 5

f: 8

f: 13

f: 21

f: 34

f: 55

Generator return value: None


next(f)等同于f.__next__()


yield保持了函数的中断状态。返回当前状态的时,再次执行yield时,继续执行下面的代码。


下面讲一个吃包子的例子

先看前半段

import time
def consumer(name):
    print("%s 准备吃包子啦!" %name)
    while True:
       baozi = yield

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))

c = consumer("zhang")
c.__next__()
c.__next__()

执行输出

zhang 准备吃包子啦!(第一次next执行效果)

包子[None]来了,被[zhang]吃了!(第二次next执行效果)


因为包子还没做,还不能吃

下面做一个包子

import time
def consumer(name):
    print("%s 准备吃包子啦!" %name)
    while True:
       baozi = yield

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))

c = consumer("zhang")
c.__next__()
b1 = "韭菜馅"
c.send(b1)

执行输出

zhang 准备吃包子啦!

包子[韭菜馅]来了,被[zhang]吃了!


send ()方法,是唤醒yield,并且给yield传值。而__next__()不会传值,只是唤醒调用。

所以输出了 包子[韭菜馅]

这里看到了2个任务,一个是吃包子,一个是做包子

下面把做包子的流程规范一下,完整代码如下

#!/usr/bin/env python
# coding: utf-8
__author__ = 'www.py3study.com'

import time
def consumer(name):
    print("%s 准备吃包子啦!" %name)
    while True:
       baozi = yield
       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))

def producer(name):
    c = consumer('A')
    c2 = consumer('B')
    c.__next__()
    c2.__next__()
    print("%s开始准备做包子啦!" %name)
    for i in range(3):
        time.sleep(1)
        print("做了2个包子!")
        c.send(i)
        c2.send(i)

producer("kang")

执行输出

baozi.gif

注意下面几行代码:

c = consumer('A')
c2 = consumer('B')
c.__next__()
c2.__next__()

为什么声明了c和c2之后,还要执行__next__()方法?

因为consumer它不是函数,它包含了yield,所以它是一个生成器。

生成器必须要用指定的方法,才能调用,执行里面的代码。比如__next__()或者send()

执行了__next__(),就是为了输出

print("%s 准备吃包子啦!" %name)

这一段话。

之后执行

print("%s开始准备做包子啦!" %name)

下面的send()执行之后,就会执行以下代码

baozi = yield
print("包子[%s]来了,被[%s]吃了!" %(baozi,name))


这个例子,就是一个简单的 协程 效果。

--结束END--

本文标题: python 生成器

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

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

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

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

下载Word文档
猜你喜欢
  • python列表生成器与生成器
    列表生成器是python内置的非常简单却非常强大的。生成一个列表[1,2,3,4]可以用list(range(1,5))列表生成器的应用如果上面的公式加上判断,就可以筛选出想要的结果,比如仅需要偶数的平方使用多层循环生成器生成器与列表生成器...
    99+
    2023-01-31
    生成器 列表 python
  • python生成器
    所属网站分类: python基础 > 装饰器,迭代器,生成器 作者:慧雅 原文链接: http://www.pythonheidong.com/blog/article/20/ 来源:python黑洞网 www.python...
    99+
    2023-01-31
    生成器 python
  • python 生成器
    先来讲一个列表生成式列表生成式:就是一个用来生成列表的特定语法形式的表达式。基础语法格式[exp for iter_var in iterable]普通创建列表是这样的a = [1...
    99+
    2023-01-30
    生成器 python
  • Python---生成器
    # 生成器 # 通过列表生成式,我们可以直接创建一个列表 # 但是,受到内存限制,列表容量肯定是有限的 # 创建一个100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了 #...
    99+
    2023-01-31
    生成器 Python
  • Python:生成器
        生成器是Python中的一个高级用法,有段时间我对生成器的理解颇为费劲,直到我看到一句话“yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行”后,让我恍然大悟,这是生成器中的状态挂起,这句话让我想起...
    99+
    2023-01-31
    生成器 Python
  • Python生成器/生成器函数/推导式/
    1. 生成器   生成器的本质就是迭代器   在python中有三种⽅方式来获取⽣生成器:     1. 通过生成器函数     2. 通过各种推导式来实现⽣成器     3. 通过数据的转换也可以获取生成...
    99+
    2023-01-31
    生成器 函数 Python
  • Python 生成器 generator
    前提条件: 如果函数含有yield就是生成器,执行过程中遇到yield就跳出。 举例:def gen():for i in range(10):x = yield iprint(x)g=ge()print(g.send(None)))pri...
    99+
    2023-01-31
    生成器 Python generator
  • Python生成器和基于生成器的协程
    小编给大家分享一下Python生成器和基于生成器的协程,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、什么是生成器Generator生成器就是可以生成值的函数2.当一个函数里有了 yield关键字就成了生成器3.生成器可...
    99+
    2023-06-15
  • python 生成器&迭代器
      一、生成器 1、列表生成器:列表生成式就像是一个厨师,他只会做这n(n为任意整数)道菜,想吃甚麽做甚麽,不吃不做,不浪费空间;而列表表达式就相当于已经做好的n盘菜,占用空间。2、生成器的创建方法: s = (x*2 for x in...
    99+
    2023-01-30
    生成器 迭代 python
  • Python之yield生成器
    1、对比range和xrange的区别:>>> print range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> print xrange(10) xrange(10)...
    99+
    2023-01-31
    生成器 Python yield
  • 【25】Python生成器generat
    列表生成式一个小题目:将里列表[0,1,2,3]里面的数值都加1.方法1: a=[0,1,2,3] b=[] for i in range(len(a)): b.append(i+1) a=b print(a) 方法2: a = [...
    99+
    2023-01-31
    生成器 Python generat
  • python -- 密码生成器
    小Q:中庭地白树栖鸦,冷露无声湿桂花;今夜月明人尽望,不知秋思落谁家? 王建《十五夜望月》两个密码生成代码实例=============================================================#!/u...
    99+
    2023-01-31
    生成器 密码 python
  • Python中的生成器
    目录1.列表生成式2.生成器1.列表生成式 代码演示: # 列表生成式 list_1 = [x**2 for x in range(10)] # x**2处也可以放函数 pri...
    99+
    2022-11-12
  • 详解Python生成器和基于生成器的协程
    目录一、什么是生成器二、基于生成器的协程三、协程的注意点四、协程装饰器五、python3原生协程一、什么是生成器 Generator 1.生成器就是可以生成值的函数 2.当一个函数里...
    99+
    2022-11-12
  • python迭代器和生成器
    1.经典迭代器 import re RE_WORD = re.compile('\w+') class Sentence: def __init__(self, text): self.text = te...
    99+
    2023-01-30
    生成器 迭代 python
  • Python迭代器与生成器
    生成器仅仅拥有生成某种东西的能力,如果不用__next__方法是获取不到值得。创建一个生成器函数>>> def scq(): ...    print("11") # 当函数代码块中遇到yield关键字的时候,这个函数就是...
    99+
    2023-01-31
    生成器 迭代 Python
  • python中的生成器(generator)
    一、生成器 生成器是 Python 中非常有用的一种数据类型,它可以让你在 Python 中更加高效地处理大量数据。生成器可以让你一次生成一个值,而不是一次生成一个序列,这样可以节省内存并提高性能 二、实现generator的两种方式 py...
    99+
    2023-09-18
    python 前端 linux
  • python进阶之生成器
    迭代器   什么叫迭代     可以被for循环的就说明他们是可迭代的,比如:字符串,列表,字典,元祖,们都可以for循环获取里面的数据   下面我们看一个代码:   1 number = 12345 2 for i in number...
    99+
    2023-01-30
    进阶 生成器 python
  • Python生成器的用法
    这篇文章主要讲解了“Python生成器的用法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python生成器的用法”吧!一、生成器在 Python 中,使用了 yield 的函数被称为生成器...
    99+
    2023-06-02
  • python高级-生成器(17)
    1. 什么是⽣成器 通过列表⽣成式,我们可以直接创建⼀个列表。但是,受到内存限制,列表容量肯定是有限的。⽽且,创建⼀个包含100万个元素的列表,不仅占⽤很⼤的存储空间,如果我们仅仅需要访问前⾯⼏个元素,那后⾯绝⼤多数元素占⽤的空间都⽩⽩浪...
    99+
    2023-01-31
    生成器 高级 python
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作