python generator_Python Generator漫谈

作为一个Python初学者, Python的格式化语法让众多编程小白追捧, 它的语法糖让代码变得简洁易读,它的庞大开源库让它在各个领域都能发挥作用. 但我时常感受到这个门槛极低的语言远没有表面上看起来易懂易用. 在Python的学习之路上, 我也时常迷茫于自己是否真正掌握了这门语言. Stackoverflow上有一篇帖子很好地说明了Python的进阶之路, 于是我准备顺着这个思路写写各个要点.

根据这篇帖子, Python进阶之路: 从小白到大神. 其中, 前两点分别是Discover list comprehensions 和 Discover generators(生成器). 身为小白的我, 心里暗想generators是个啥。于是,研究了一番,遂成此文。

注: 全文使用Python3.5, 标准库.

谈起Generator, 与之相关的的概念有{list, set, tuple, dict} comprehension and container

iterable

iterator

generator fuction and iterator

generator expression

接下来, 我们分别来看看这些概念:

{list, set, tuple, dict} comprehension and container

Container是存储元素的数据结构, 一般存储在内存中. 在Python中,常见的container包括但不限于:list, deque, …

set, …

tuple, namedtuple, …

dict, defaultdict, Counter, …

简单举例:

assert 1 in [1, 2, 3] # list

assert 1 in {1, 2, 3} # set

assert 1 in (1, 2, 3) # tuple

d = {1: 'foo', 2: 'bar', 3: 'qux'}

assert 1 in d # dict

特别的, String也是container. 我们可以查询一个substring是否在string里, 如:

s = 'foobar'

assert 'foo' in s

assert 'x' not in s # string 包含所有的 substrings. 需要注意的是string并不存储这些substrings, 只是可以如此查询

iterable

一般说来,大部分的containers是iterable.而iterable不限于containers,还包括像文件.

iterable是实现了__iter__()方法的对象.该方法返回的是的一个iterator对象.其中,iterator的目的是返回所有元素.来看例子:

from collections import Iterable, Iterator

x = [1, 2, 3]

y = iter(x)

z = iter(x)

next(y)

Out: 1

next(y)

Out: 2

next(z)

Out: 1

next(z)

Out: 2

type(x)

Out: list

isinstance(x, Iterable)

Out: True

type(y)

Out: list_iterator

isinstance(y, Iterable)

Out: True

可以看出, x是list, 也是iterable. y和z都是x的返回值, 也就是iterators, 互相独立. iterators通过___next___()这个方法返回元素,每执行一次, 返回一个元素. 值得注意的是,y作为iterable的实例, 它也是iterator. iterable是一个比iterator更大的概念.

import dis

x = [1, 2, 3]

dis.dis('for _ in x: pass')

1 0 SETUP_LOOP 14 (to 17)

3 LOAD_NAME 0 (x)

6 GET_ITER

>> 7 FOR_ITER 6 (to 16)

10 STORE_NAME 1 (_)

13 JUMP_ABSOLUTE 7

>> 16 POP_BLOCK

>> 17 LOAD_CONST 0 (None)

20 RETURN_VALUE

更深入的, 我们可以明显看出在for循环中, Python每次都是调用FOR_ITER这个指令实现了读取下一个next()的功能, 也就是说, for循环中,首先利用GET_ITER得到x的返回值, 一个iterator. 再通过FOR_ITER得到其中的元素. 如此实现了循环的功能.

iterator

那么什么是iterator? 就像之前我们提到的, iterator可以通过调用__next___()生成下一个值. 我们也可以说有__next___()这个方法的都可以是iterator. 这与它如何生成值无关. 我们具体看一个例子:

from itertools import islice

class seq:

def __init__(self):

self.gap = 2

self.curr = 1

def __iter__(self):

return self

def __next__(self):

value = self.curr

self.curr += self.gap

return value

f = seq()

list(islice(f, 0, 10))

Out: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

以上, 我们构建了一个等差数列, 差为2. 其中, f既是iterable(因为iter方法), 也是iterator(因为有next方法).

对于iterator, next方法做的两件事是:更新iterator的状态,到下次调用;

返回当前调用结果, eg: return value.

generator function and iterator

Ok. 终于到了本文的正题 generator. 首先下定义, generator是返回generator iterator的function(函数). 具体来说, 它可以让你更优雅的实现iterator, 而不用写带有__iter__() 和 __next__() 的类. 继续以上面那个等差数列为例, 我们看看generator如何的优雅的完成它:

def seq():

gap, curr = 2, 1

while True:

yield curr

curr = curr + gap

f = seq()

list(islice(f, 0, 10))

Out: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

以上, 我们看到了让它如此优雅的原因 yield.

让我们看看这段code是如何运行的,

首先, seq是一个Python程序, 它返回的是iterator. 当 f = seq() 被调用, generator 会准备好返回. 但这时没有执行任何代码.

接下来, 这个generator实例在islice()中被使用. 仍然没有执行代码. 然后, list()开始建立list. 为了得到list的元素, list()开始调用islice()的next()方法抓取元素, 也就是要在 f 函数中取元素.

记住每次只生成一个元素. 这是代码开始运行到 gap, curr = 2, 1 初始化变量. 接着进入始终为真的循环, 到了yield语句. 它做两件事: 1.暂停, 并更新状态到下一次yield, 2. 返回当前结果, 也就是curr值, 1. 这个值接着被传到了islice(), 最后加到list中. list现在是 [1].

list()继续要下一个值. 暂停的 f 函数继续运行下一个语句curr + gap. curr 现在是2. 继续进入下一个while循环, 遇到 yield. 同样的, yield做两件事: 1.暂停下来调整状态; 2. 返回值2. 值返回到list, list 等于 [1, 2].

如此循环直到list取完10个元素. 特别的, 在第11次去值, islice()会有exception: StopIteration. 告诉list已经取值结束.

generator expression

generator expression是Python的另一种generator. 相信大家都用过list expression, 比如生成一列数的平方:

numbers = [1, 2, 3, 4, 5, 6]

[x ** 2 for x in numbers]

[1, 4, 9, 16, 25, 36]

generator expression很类似, 比如

squares_list = (x * x for x in numbers)

squares_list

at 0x10435eaf0>

next(squares_list)

Out: 1

list(squares_list)

Out: [4, 9, 16, 25, 36]

以上, 不再累述.

Summary

下图说明了各个概念之间的关系,

最后,谈谈为什么要使用generators. 它能帮你实现更优雅的代码, 减少中间变量和不必要的数据结构,从而代码量, 节省内存空间和运算性能.

针对一个循环代码,

def something():

result = []

for ... in ...:

result.append(x)

return result

你可以做这样的转换

def iter_something():

for ... in ...:

yield x

感谢阅读,欢迎大家修改指正.

本文作者:Early Kid

更多内容,请访问:BitTiger.io, 扫描下面二维码,关注微信公众账号“论码农的自我修养”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/244368.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php5.5 连接数据库,php5.5 session_set_save_handler 连接数据库问题

好久前忘了在什么地方抄来的,一直好用,但是升级到PHP5.5就不好用了 出现警告服务器无法修改PHP.ini 只好自己试着用mysqli写 但是一直写不出来 请高手指教!!谢谢回复讨论(解决方案)把 mysql_ 都改成 mysqli_>把 mysql_ 都改成 …

python获取屏幕文字_详解:四种方法教你对Python获取屏幕截图(PyQt , pyautogui)...

前言:今天为大家带来的内容是详解:四种方法教你对Python获取屏幕截图(PyQt , pyautogui)本文具有不错的参考意义,希望能够帮助到大家!Python获取电脑截图有多种方式,具体如下:1. PIL中的ImageGrab模块2. wi…

支付宝php异步回调,支付宝支付成功之后异步回调处理

/*** alipay_notify.php.* User: lvfk* Date: 2017/10/26 0026* Time: 13:48* Desc: 支付宝支付成功异步通知*/include_once (__DIR__./../alipay-sdk-PHP-20171023143822/AopSdk.php);//验证签名$aop new \AopClient();$aop->alipayrsaPublicKey \Comm\Pay\Alipay::ALIPA…

python frame如何置顶_Python tkinter frame父窗口小部件排列列

我把滚动条放在一个框架里,框架放在一个小部件里。这个框架上面有一个标签。上面的标签有三列。带有滚动条的框架有三列。我无法让框架内和框架上方的三根柱子对齐。在如果您能帮我排好纵队,我们将不胜感激。谢谢。在以下是MWE:import tkinte…

MySQL和mq一致性,Mysql与Redis一致性问题

缓存一致性产生背景如果每次频繁的访问数据库的时候,虽然查询底层使用B树索引 但还会做磁盘的IO操作,可能会对数据库的压力非常大。所以为了能够减轻数据库的访问压力,会使用一些缓存实现减轻数据库的压力。比如 Redis、es、ehcache、oscache…

python boolean_Python成为专业人士笔记-Boolean 布尔操作符研究

专业人士笔记”系列目录:创帆云:Python成为专业人士笔记--强烈建议收藏!每日持续更新!​zhuanlan.zhihu.com‘and’ 和 ‘or’ 并不一定返回一个布尔值当使用or时,如果为真,它将返回表达式中的第一个值&…

python八大选择排序_python之八大排序方法

排序方法 平均情况 最好情况 最坏情况 辅助空间 稳定性冒泡排序 O(n^2) O(n) O(n^2) O(1) 稳定选择排序 O(n^2) O(n^2) O(n^2) O(1) 不稳定插入…

int arr 13 java,java学习13 - 数组的定义、操作、异常、二维数组

续java学习12:1、数组,引用类型变量,保存数据实际是保存的数组的首地址2、定义数组容器三要素,数据类型,大小(长度),数组名3、数组的定义公式一:数据类型[] 数组名 new 数据类型[元素个数或数组长度]4、数…

clustalw序列比对_序列比对(二)

Homology is the central concept for all of biology.——David Wake. Science, 1994前言正如前面引用的这句话,同源性是生物学中的核心问题。研究序列的同源性问题,就要用到序列比对的工具,上一篇笔记简单介绍了序列比对的原理,…

java js引擎,Java8 Nashorn JavaScript引擎

使用Java8,Nashorn大大提高了JavaScript 引擎引入,以取代现有的Nashorn Java脚本引擎。Nashorn提供2至10倍更好的性能,因为它直接编译代码在存储器,并传递到字节码JVM.Nashorn使用invokedynamics函数,在Java7引入以提高…

pr渲染程序选哪个_PR的bug你遇到过几个?

哈喽 大家好呀 我是K同学!对于Pr的用户来讲,Pr有很多BUG让人很奔溃,不仅Pr奔溃了,人都奔溃了作为Pr的老用户,今天我就来盘点下,我遇到过Pr的变态BUG第一个Pr不支持微软输出法这是我使用Pr遇到的第一个BUG&a…

java model 中文乱码,java传值乱码解决方法

在做JavaWeb时,总是时不时的会遇到中文传值乱码问题,在你把所有”ISO-8859-1”改成“UTF-8”发现还是没什么用。于是我就找到了一个百试百灵的方法(至少目前我是),就是强行转换成“UTF-8”编码。看代码:RequestMapping("/suc…

检查一列数据的重复项 vba_提取重复值,但字典不是重点。

本例的问题描述:1:源数据与提取的结果在同一个工作表里面;2:提取K、M、O、Q列里面不重复的数据(注意,数据列里面有空白的行);3:把提取出来的结果放在A2单元格的下方,不能有空白行&am…

swiper怎么让不会回弹,为什么我的滚动条拉上拉下都会回弹呢?

其它都是正常的,就是拉上去拉下来自己又回弹回去了,拉不到最底部也拉不到最顶部,拉来拉去都会是这样的category/index.vueimport CategoryHeader from "./header";import CategoryTab from "./tab";import CategoryConte…

异构服务器 微服务_Spring Cloud Alibaba Sidecar 多语言微服务异构

Spring Cloud Alibaba Sidecar 介绍自 Spring Cloud Alibaba 2.1.1 版本后增加了 spring-cloud-alibaba-sidecar 模块作为作为一个代理的服务来间接性的让其他语言可以使用spring cloud alibaba等相关组件。通过与网关的来进行路由的映射,从而可以做到服务的获取&am…

采用的php cms分校站点 打开特别慢,phpcms v9 打开网站特别慢 增加数据库缓存方法...

SET GLOBAL QUERY_CACHE_SIZE80000000;设置好查询缓存的大小就行了。比如设置个20MB.SET GLOBAL QUERY_CACHE_SIZE20000000;mysql会将查询SQL和结果集存到缓存中,等下次遇到相同的SQL语句时,结果集从缓存中读取。1.设置缓存大小时,至少给它40…

python3 console input_Python3 tkinter基础 Button command 单击按钮 在console中打印文本

Python : 3.7.0OS : Ubuntu 18.04.1 LTSIDE : PyCharm 2018.2.4Conda : 4.5.11typesetting : Markdowncode"""Author : 行初心Date : 18-10-1Blog : www.cnblogs.com/xingchuxinGitee : gitee.com/zhichengjiu"""import tkinter as tk# 面向对象…

matlab教程点语言,编程语言 / Matlab教程_电脑教程学习网( 5 )

逐次超松弛方法(SOR方法)求解方程组日期:2014-09-26 21:03:34点击:370好评:0#includeiostream.h//逐次超松弛方法(SOR方法)求解方程组 #includemath.h #includeiomanip.h #define n 3 void main() { double A[n][n]{{5,2,1},{-1,4,2},{2,-3,1…

python中timedelta_Python – 使用时间戳,timedelta的日期和时间比较

我花了过去一小时挖掘Python文档和许多SO问题;请原谅我是另一个Python新手被Python时代的谜团所困扰.我的目标是确定当前时间和某个日期/时间之间的差异,而不管过去/将来,并返回可执行的格式,如秒.例如,如果输入是下午2:00和下午4:00(现在),我想要说“-7200”,表示事件发生在两…

php hex2bin nodejs,Nodejs Serialport文档翻译

版本号:Serialport5.0.0-beta3本文链接想象一个世界,你可以在那写javascript来控制搅拌机,灯,安全系统或者甚至是机器人。是的,我说的是机器人。那个世界就是这儿,现在使用node serialport。它提供一个非常简单的接口所…