Python Iterator and Generator
Python Iterator and Generator
Iterator
迭代器(Iterator)和可迭代对象(Iterable)往往是绑定的。可迭代对象就是我们平时经常用的list ,string, tuple这种。事实上迭代器的概念会比可迭代对象宽泛很多,一会举几个例子就能明白。
在使用list这种数据类型的时候,我们经常会使用下面这种迭代方式:
# eg 1
mylist = [1,2,3,4]
for x in mylist:
print(x)
>>>1
>>>2
>>>3
>>>4
有时候会很奇怪for循环为什么可以这么用,列表的索引竟然会自动往后一个一个走,走到结尾了,还会自动停下来,不会有list out of range的报错。神奇。其实for循环做的事情不止这么简单。要说明这个问题,得先说迭代器具体怎么做,是什么。
要创建一个迭代器,就必须要实现两个方法,分别是__iter__()和__next__(),以及实现异常机制StopIteration。请看下面的例子:
# eg 2
class PowTwo:
"""Class to implement an iterator of powers of two"""
def __init__(self, max = 0):
self.max = max
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n <= self.max:
result = 2 ** self.n
self.n += 1
return result
else:
raise StopIteration
可以看到,迭代器是通过写一个类来定义的,类里面实现了刚刚所说的__iter__()和__next__()方法。这个迭代器是用来产生一系列2的指数次方的数字的,具体用法看下面:
a = PowTwo(4)
i = iter(a) # attention please
next(i)
>>>1
next(i)
>>>2
next(i)
>>>4
next(i)
>>>8
next(i)
>>>16
next(i)
>>>Traceback (most recent call last):
...
StopIteration
仔细看哦,第一行代码用4创建了一个实例a,设置了这个迭代器的迭代上限,然后并不是直接用这个实例就可以了,还得调用iter()函数去把a彻底进化成一个Iterator,进而有了接下来next()函数的闪亮登场。其实我也蛮奇怪,直接用这个类不好么,比如下面的代码:
a = PowTwo(4)
a.__iter__()
a.__next__()
>>>1
a.__next__()
>>>2
a.__next__()
>>>4
a.__next__()
>>>8
a.__next__()
>>>16
next(i)
>>>Traceback (most recent call last):
...
StopIteration
完全没问题,但是你自己比较一下二者的代码,哪个美一点毋庸置疑。。。再说了,跟装饰器一样,一切为了简洁优美而生嘛。
OK,可以回到最初的起点——for循环了。示例1中的代码,for循环到底做了什么呢,答案是,for循环其实是先把mylist变成迭代器,然后用while循环去迭代:
iter_obj = iter(mylist)
while True:
try:
element = next(iter_obj)
except StopIteration:
break
这样一路解释过来,应该就不难理解迭代器了。总结一下就是:
- 如何已经有一个可迭代对象,那么直接用
iter()函数去初始化它,然后疯狂next()即可; - 如果没有现成的可迭代对象,那就自己写一个类,类里面记得实现
__iter__()和__next__()方法,以及异常机制StopIteration,然后操作同1; - 如果你想要一个无限迭代器,不要实现异常机制
StopIteration即可。
Generator
这玩意儿就比迭代器复杂点了,所以还得分几个小点,逐个击破。
1. 生成器是啥
生成器也是Python中面向一系列需要迭代的问题,常用的解决方案。既然有了迭代器,可以解决很多迭代的问题,那为啥子还要生成器勒?
主要的原因是迭代器的开销太大了。对于一些小问题还好,大的问题需要迭代的元素很庞大的时候,迭代器就使不上劲儿了。而且,创建一个迭代器,说实话也还挺麻烦的,看看上面的小总结的第二点,你得实现这些方法和手动处理异常。
而且迭代器要写类,其实一个函数可以搞定的事情,何必那么复杂。正是应了这个景,生成器也就是在函数对象上搞事情的。
这个原因点到即止,先把生成器讲清楚了,自然就通透了。先看一个小例子,写一个生成器函数(Generator Function):
# eg 1
def my_gen():
n = 1
print('This is printed first')
yield n
n += 1
print('This is printed second')
yield n
n += 1
print('This is printed at last')
yield n
上面就是一个简单的生成器函数,多了一种关键字yield,细心看会发现这个函数竟然没有return!再细看代码,没错,yield替代了return。那怎么用呢,有两种用法如下:
# usage 1
a = my_gen()
next(a)
>>>This is printed first
1
next(a)
>>>This is printed second
2
next(a)
>>>This is printed at last
3
next(a)
>>>Traceback (most recent call last):
...
StopIteration
# usage 2
for item in my_gen():
print(item)
>>>
This is printed first
1
This is printed second
2
This is printed at last
3
对于用法1,把函数赋值给了a,然乎疯狂next()即可。你会发现,我们并没有像迭代器那样实现__iter__()和__next__()方法,以及异常机制StopIteration,只是用了一个yield关键字,这个生成器函数却达到了迭代器一样的效果。
对于用法2,更牛皮了,甚至不用赋值的操作,直接for这个生成器函数。。。
2. 循环机制生成器
刚刚那个小函数,就是一个最普通的例子,那问题是如果有多个n想要玩,岂不是来多少手动写多少?那当然还有循环的玩法,带有循环机制的生成器。下面是一个逆序输出的小例子:
# eg 2
def rev_str(my_str):
length = len(my_str)
for i in range(length - 1,-1,-1):
yield my_str[i]
for char in rev_str("hello"):
print(char)
>>>o
>>>l
>>>l
>>>e
>>>h
没错,真无聊,犯得着逆序输出的程序还得上生成器么,犯不着,但是,只是想给出这个循环机制生成器的概念。如果你发现这个rev_str()函数和普通的逆序函数完全一样,只是return换成了yield,那就万事大吉,要理解的就是这个。就这样一记简单的替换操作,你就得到了一个生成器,是不是比迭代器省事儿多了。
3. 生成器表达式(Generator Expression)
不知道你有没有用过列表生成式,没用过也应该看到过,这类似于匿名函数,语法简洁,比如:
# eg 3
my_list = [1, 3, 6, 10]
[x**2 for x in my_list]
>>>[1, 9, 36, 100]
生成器表达式和这个几乎一样,不信你看:
# eg 4
my_list = [1, 3, 6, 10]
a = (x**2 for x in my_list)
next(a)
>>>1
next(a)
>>>9
next(a)
>>>36
next(a)
>>>100
把列表生成式的[]直接改成(),就得到了一个生成器。
4. Why Generator???
(1). 简洁
回到最开始迭代器的那个类的例子,用生成器咋写呢?
def PowTwoGen(max = 0):
n = 0
while n < max:
yield 2 ** n
n += 1
简洁吧,然后你就可以用这个生成器函数遨游了。
(2). 开销小
同样的一个需要迭代的功能,如果用普通函数写,一旦需要迭代的元素特别多,在使用的时候,普通函数需要等所有的元素计算出来了,然后把返回值给你。生成器就不是了,它一次计算出一个,用的时候就取一个,并且它还会记住位置,下次用就计算下一个,这样对空间的开销也是很小的。
(3). 无限
看下面的函数:
def all_even():
n = 0
while True:
yield n
n += 2
写普通函数,你必然做不到写出一个可以无限操作的函数,生成器却可以。(迭代器也可以,就是麻烦点儿)
5. 再给一个例子
# 利用yield生成一个斐波那契数列的生成器
def fib(max):
n,a,b=0,0,1
while n<max:
yield b
a,b=b,a+b
n+=1
return 'done' # 要不要这句话都行
f=fib(6)
next(f) # 疯狂next()它
>>>
1
1
2
3
5
8
Traceback (most recent call last):
...
StopIteration: done
Python Iterator and Generator的更多相关文章
- [Python学习]Iterator 和 Generator的学习心得
[Python学习]Iterator 和 Generator的学习心得 Iterator是迭代器的意思,它的作用是一次产生一个数据项,直到没有为止.这样在 for 循环中就可以对它进行循环处理了.那么 ...
- Python3 Iterator and Generator
Python3 Iterator and Generator iterator 主要是利用 iter 函数 >>> list=[1,2,3,4] >>> it = ...
- babel 不能统编译Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise的问题
Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator.Generator.Set.Maps.Proxy.Reflect.Symbol.Promis ...
- Python生成器(generator)和迭代器(Iterator)
列表生成式 a = [i+1 for i in range(10)] print(a) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 这就是列表生成式 生成器(generator) ...
- Python之生成器(generator)和迭代器(Iterator)
generator 生成器generator:一边循环一边计算的机制. 生成器是一个特殊的程序,可以被用于控制循环的迭代行为.python中的生成器是迭代器的一种,使用yield返回值函数,每次调用y ...
- python中的generator, iterator, iterabel
先来看看如果遇到一个对象,如何判断其是否是这三种类型: from types import GeneratorType from collectiuons import Iterable, Itera ...
- Python中生成器generator和迭代器Iterator的使用方法
一.生成器 1. 生成器的定义 把所需要值得计算方法储存起来,不会先直接生成数值,而是等到什么时候使用什么时候生成,每次生成一个,减少计算机占用内存空间 2. 生成器的创建方式 第一种只要把一个列表生 ...
- python中的generator(coroutine)浅析和应用
背景知识: 在Python中一个function要运行起来,它在python VM中需要三个东西. PyCodeObject,这个保存了函数的代码 PyFunctionObject,这个代表一个虚拟机 ...
- (转)Python中的generator详解
本文转自:http://www.cnblogs.com/xybaby/p/6322376.html 作者:xybaby 注:本文在原文基础上做了一点点修改,仅仅作为个人理解与记忆,建议直接查看原文. ...
随机推荐
- Codeforces 755C:PolandBall and Forest(并查集)
http://codeforces.com/problemset/problem/755/C 题意:该图是类似于树,给出n个点,接下来p[i]表示在树上离 i 距离最远的 id 是p[i],如果距离相 ...
- websocket实现群聊和单聊(转)
昨日内容回顾 1.Flask路由 1.endpoint="user" # 反向url地址 2.url_address = url_for("user") 3.m ...
- django的命令, 配置,以及django使用mysql的流程
1.Django的命令: 下载 pip install django==1.11.16 pip install django==1.11.16 -i 源 创建项目 django-admin start ...
- Touch Bar 废物利用系列 | 在触控栏上显示 Dock 应用图标
都说 Intel 第八代 CPU 对比上代是牙膏不小心挤多了,而配备第八代 CPU 的 MacBook Pro,只有 Touch Bar 版本,虽然贵了一点,但就一个字 -- 买! 收到电脑后,兴冲冲 ...
- WinForm控件之【CheckedListBox】
基本介绍 复选框列表控件,以复选框的形式将一个或多个项列表展示,从目前的情况来看应用非常有限并不广泛. 常设置属性.事件 CheckOnClick:值为true时单击项即可更改项的勾选状态,值为fal ...
- Java的Hook线程及捕获线程执行异常
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.f ...
- Spark第一周
Why Scala 在数据集不是很大的时候,开发人员可以使用python.R.MATLAB等语言在单机上处理数据集.但是在大数据时代,数据集少说都是TB.PB级别,此时便需要分布式地处理.相较于上述语 ...
- .net持续集成cake篇之使用vs或者vscode来辅助开发cake脚本
使用Visual Studio来开发工具 前面我们都是通过手写或者复制的方法来编写Cake文件,Cake使用的是C#语言,如果仅使用简单的文本编辑器来编写显然效率是非常低下的,本节我们讲解如何使用ca ...
- 个人永久性免费-Excel催化剂功能第84波-批量提取OUTLOOK邮件附件
批量操作的事情常常能让人感到十分畅快,区别于一次次的手工的操作,它真正实现了“人工智能”想要的效果,人指挥机器做事情,机器就可以按着人意去操作.此篇给大家再次送了批量操作一绝活,批量下载OUTLOOK ...
- 个人永久性免费-Excel催化剂功能第40波-工资、年终奖个人所得税计算函数
学Excel的表哥表姐们必定有接触过个人所得税的案例学习,在计算个人所得税这个需求上,大家的层次也是很多种多样,当然Excel催化剂推荐的方式仍然是经过封装后的简单明了的自定义函数的方式,此篇已为财务 ...