Python学习--07迭代器、生成器
迭代
如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。
Python里使用for...in来迭代。
常用可迭代对象有list、tuple、dict、字符串等。示例:
list:
for x in [1,2]:
print(x)
for x,y in [(1,2),(3,4)]:
print(x,y)
输出:
1
2
1 2
3 4
上面的for循环里,同时引用了两个变量,在Python里是很常见的。
tuple:
for x in (1,2):
print(x)
输出:
1
2
dict:
dict = {"name":"yjc", "age":18}
for v in dict:
print(v, dict[v])
for v in dict.values():
print(v)
for k,v in dict.items():
print(k,v)
输出:
name yjc
age 18
yjc
18
age 18
name yjc
dict默认迭代的key,可以使用dict.values()获取value;还可以使用dict.items()同时获取key和value。
字符串也是可迭代对象:
for ch in 'abcd':
print(ch)
输出:
a
b
c
d
如果要对list实现类似Java那样的下标循环可以使用内置的enumerate函数——可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:
for k,v in enumerate([1,2]):
print(k,v)
输出:
0 1
1 2
那么,如何判断一个对象是否可迭代呢?可以使用collections模块里的Iterable判断:
from collections import Iterable
print(isinstance([1,2], Iterable));
输出:
True
任何可迭代对象都可以作用于for循环,包括我们自定义的数据类型,只要符合迭代条件,就可以使用for循环。
列表生成式
列表生成式(List Comprehensions)是Python特有的用来创建list的生成式。
示例:
list = [x*x for x in range(1,10)]
print(list)
输出:
[1, 4, 9, 16, 25, 36, 49, 64, 81]
以上代码相当于:
list = []
for x in range(1,10):
list.append(x*x)
print(list)
看到这里大家应该理解Python列表生成式的含义了。运用列表生成式,可以写出非常简洁的代码。
我们再看几个示例:
1)输出偶数:
list = [x for x in range(1,10) if x % 2 == 0 ]
print(list)
输出:
[2, 4, 6, 8]
2)笛卡尔积
a = "AB"
b = "XYZ"
list = [m+n for m in a for n in b]
print(list)
输出:
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ']
3)大写转小写
list = [s.lower() for s in ['I', 'Love', 'Python', 100] if isinstance(s,str)]
print(list)
输出:
['i', 'love', 'python']
这里使用isinstance()判断类型,因为非字符串类型没有lower()方法,Python会报错,所以这里加了个判断:
>>> isinstance('love', str)
True
>>> isinstance(100, str)
False
生成器
前面我们使用列表生成式可以很方便的生成一个我们需要的列表。但是如果生成一个很大的列表,会比较占内存,例如range(1,10000000),如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都浪费了。
生成器(generator)不同于列表,它根据写好的算法,能够推算出下一个元素。生成器不属于list类型,属于generator类型。要创建一个生成器,第一种方法就是把列表生成式最外面的[]的改成()就行了:
L = [x for x in range(1,10) if x % 2 == 0 ]
print(type(L))
print(L)
g = (x for x in range(1,10) if x % 2 == 0 )
print(type(g))
print(g)
输出:
<class 'list'>
[2, 4, 6, 8]
<class 'generator'>
<generator object <genexpr> at 0x01EAEE90>
我们不能像list那样直接打印出generator。如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:
g = (x for x in range(1,10) if x % 2 == 0 )
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
输出:
2
4
6
8
Traceback (most recent call last):
File "/1.py", line 6, in <module>
print(next(g))
generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
我们可以使用for循环迭代generator:
g = (x for x in range(1,10) if x % 2 == 0 )
for x in g:
print(x)
输出:
2
4
6
8
for循环遇到StopIteration会停止迭代,不会扔出异常。
下面,我们引入生成器的另外一种创建方法,使用yield关键字。函数里如果有yield关键字,那么它将不再是一个函数,而是一个生成器,遇到yield中断,下次又从上次中断的地方继续执行。示例:
def test():
print('step 1:')
yield 11
print('step 2:')
yield 22
return 'ok'
g = test()
print(g)
print(next(g))
print(next(g))
print(next(g))
输出:
<generator object test at 0x005BEC38>
step 1:
11
step 2:
22
Traceback (most recent call last):
File "D:\Users\Desktop\1.py", line 12, in <module>
print(next(g))
StopIteration: ok
可以看到,test不是普通函数,而是generator,在执行过程中,遇到yield就中断,下次又继续执行。执行2次yield后,已经没有yield可以执行了,所以,第3次调用next(g)就报错。
函数改成generator后,同样可以使用for循环迭代:
for x in test():
print(x)
下面是斐波拉契数列生成的函数,大家自行看有啥区别:
def fib(n):
a,b,i=0,1,1
while i <= n:
a,b = b,a+b
i+=1
print(b)
def gfib(n):
a,b,i=0,1,1
while i <= n:
a,b = b,a+b
i+=1
yield b
fib(6)
gfib(6)
用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:
>>> g = fib(6)
>>> while True:
... try:
... x = next(g)
... print('g:', x)
... except StopIteration as e:
... print('Generator return value:', e.value)
... break
...
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done
迭代器
可以直接作用于for循环的一类是list、tuple、dict、set、str,另一类是generator。这些对象统称为可迭代对象:Iterable。
可以直接作用于next()的对象称为迭代器:Iterator。迭代器既可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
使用isinstance()判断一个对象是否是Iterable对象或者Iterator对象:
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
把list、dict、str等Iterable变成Iterator可以使用iter()函数:
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
Python的for循环本质上就是通过不断调用next()函数实现的,例如:
for x in [1, 2, 3, 4, 5]:
pass
实际上完全等价于:
# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
try:
# 获得下一个值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出循环
break
Python学习--07迭代器、生成器的更多相关文章
- Python学习 :迭代器&生成器
列表生成式 列表生成式的操作顺序: 1.先依次来读取元素 for x 2.对元素进行操作 x*x 3.赋予变量 Eg.列表生成式方式一 a = [x*x for x in range(10)] pri ...
- Python学习day17 迭代器&生成器
迭代器&生成器 1. 迭代器 1.1 迭代器 迭代:迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果.每一次对过程的重复称为一次"迭代" 迭代器:帮助对某种对象 ...
- python学习10—迭代器、三元表达式与生成器
python学习10—迭代器.三元表达式与生成器 1. 迭代器协议 定义:对象必须提供一个next方法,执行该方法或者返回迭代中的下一项,或者返回一个StopIteration异常,以终止迭代(只能往 ...
- Python学习笔记之生成器、迭代器和装饰器
这篇文章主要介绍 Python 中几个常用的高级特性,用好这几个特性可以让自己的代码更加 Pythonnic 哦 1.生成器 什么是生成器呢?简单来说,在 Python 中一边循环一边计算的机制称为 ...
- python各种模块,迭代器,生成器
从逻辑上组织python代码(变量,函数,类,逻辑:实现一个功能) 本质就是.py结尾的python文件(文件名:test.py,对应的模块名就是test) 包:用来从逻辑上组织模块的,本质就是一个目 ...
- python杂记-4(迭代器&生成器)
#!/usr/bin/env python# -*- coding: utf-8 -*-#1.迭代器&生成器#生成器#正确的方法是使用for循环,因为generator也是可迭代对象:g = ...
- Python学习之旅—生成器对象的send方法详解
前言 在上一篇博客中,笔者带大家一起探讨了生成器与迭代器的本质原理和使用,本次博客将重点聚焦于生成器对象的send方法. 一.send方法详解 我们知道生成器对象本质上是一个迭代器.但是它比迭代器对 ...
- Python学习之旅—生成器与迭代器案例剖析
前言 前面一篇博客笔者带大家详细探讨了生成器与迭代器的本质,本次我们将实际分析一个具体案例来加深对生成器与迭代器相关知识点的理解. 本次的案例是一个文件过滤操作,所做的主要操作就是过滤出一个目录下的文 ...
- python学习日记(迭代器、生成器)-乱七八糟
迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退 ...
随机推荐
- Dapper基本增删改查
说明: 1.在using语句块中不用dbConnection.Open(),因为Execute方法中会Open,并且在执行完成会Close. 2.在Ado.Net中要手动Open,在Using语句块中 ...
- DEV XtraGrid绑定非绑定列(转)
在Gridview创建一列 .将该列的UnboundType属性设置为bound(默认值)以外的数据类型 为该列设置一个窗体内全局唯一的FieldName,注意这个FieldName甚至不能出现在 ...
- QQ原创表情添加
有时候与QQ好友聊天时会收到一些自己比较喜欢的原创表情,如果我们想把这些QQ不支持直接保存的原创表情保存到电脑上该怎么做呢?我们以原创表情图片为例简单介绍一下. 首先,先建立一个存放表情图片的文件夹. ...
- php javascript
php100:103:Jquery javascript javascript:网页用来改进设计.验证表单.检测浏览器.创建cookies. Javascript(简称JS) 和 HTML 标签一样都 ...
- Java泛型的基本应用
一.泛型概述 jdk1.5版本以后出现的新特性,用于解决安全问题,是一个安全机制. 好处: 1,将运行时期的问题ClassCastException转到了编译时期. 2,避免了强制转换的麻烦. 什么时 ...
- yarn资源调度(网络搜集)
本文转自:http://www.itweet.cn/2015/07/24/yarn-resources-manager-allocation/ Hadoop YARN同时支持内存和CPU两种资源的调度 ...
- 关于iOS上的对象映射公用方法-备
具体的使用方法,请见下面说明,或者见工程里的单元测试代码.或者,参考原始文档: https://github.com/mystcolor/JTObjectMapping 使用方法 ======== 绝 ...
- CentOS安装Nginx,并配置nodejs反向代理
安装介绍 安装位置:/usr/local/nginx nginx安装包下载地址:http://nginx.org/download/nginx-1.7.11.tar.gz 安装依赖软件 安装nginx ...
- ural 1180 Stone Game
http://acm.timus.ru/problem.aspx?space=1&num=1180 #include <cstdio> #include <cstring&g ...
- Windows内存小结(有好多图,比较清楚)
以前写过一篇理解程序内存, 当时主要是针对用户态,下面再稍微深入一点: 我们以32位程序为例(不启用AWE), 总共4G虚拟空间,其中低2G属于用户态, 高2G属于操作系统内核, 每个程序都有自己的低 ...