迭代

如果给定一个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对象,但listdictstr虽然是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迭代器、生成器的更多相关文章

  1. Python学习 :迭代器&生成器

    列表生成式 列表生成式的操作顺序: 1.先依次来读取元素 for x 2.对元素进行操作 x*x 3.赋予变量 Eg.列表生成式方式一 a = [x*x for x in range(10)] pri ...

  2. Python学习day17 迭代器&生成器

    迭代器&生成器 1. 迭代器 1.1 迭代器 迭代:迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果.每一次对过程的重复称为一次"迭代" 迭代器:帮助对某种对象 ...

  3. python学习10—迭代器、三元表达式与生成器

    python学习10—迭代器.三元表达式与生成器 1. 迭代器协议 定义:对象必须提供一个next方法,执行该方法或者返回迭代中的下一项,或者返回一个StopIteration异常,以终止迭代(只能往 ...

  4. Python学习笔记之生成器、迭代器和装饰器

    这篇文章主要介绍 Python 中几个常用的高级特性,用好这几个特性可以让自己的代码更加 Pythonnic 哦 1.生成器 什么是生成器呢?简单来说,在 Python 中一边循环一边计算的机制称为 ...

  5. python各种模块,迭代器,生成器

    从逻辑上组织python代码(变量,函数,类,逻辑:实现一个功能) 本质就是.py结尾的python文件(文件名:test.py,对应的模块名就是test) 包:用来从逻辑上组织模块的,本质就是一个目 ...

  6. python杂记-4(迭代器&生成器)

    #!/usr/bin/env python# -*- coding: utf-8 -*-#1.迭代器&生成器#生成器#正确的方法是使用for循环,因为generator也是可迭代对象:g = ...

  7. Python学习之旅—生成器对象的send方法详解

    前言 在上一篇博客中,笔者带大家一起探讨了生成器与迭代器的本质原理和使用,本次博客将重点聚焦于生成器对象的send方法. 一.send方法详解  我们知道生成器对象本质上是一个迭代器.但是它比迭代器对 ...

  8. Python学习之旅—生成器与迭代器案例剖析

    前言 前面一篇博客笔者带大家详细探讨了生成器与迭代器的本质,本次我们将实际分析一个具体案例来加深对生成器与迭代器相关知识点的理解. 本次的案例是一个文件过滤操作,所做的主要操作就是过滤出一个目录下的文 ...

  9. python学习日记(迭代器、生成器)-乱七八糟

    迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退 ...

随机推荐

  1. spring boot了解

    spring4倾向于基于注解的配置,强化的注解的功能,对比与spring3还是有很多的区别:spring boot对spring的各个组件功能管理,基于默认配置即可简单构建一个spring4的项目,对 ...

  2. jQuery的map()与jQuery.map()总结

    请注意他们不是同一个函数.前者是jQuery对象的实例方法(即$.fn.map),后者是一个仅仅挂在jQuery对象下的静态方法(即$.map). 他们用法的异同:map()的返回值是包裹了一个Arr ...

  3. SQL复制表结构和数据

    1.复制表结构和数据 select * into 目的数据库名.dbo.目的表名 from 原表名 select * into my0735home.dbo.infoMianTest from inf ...

  4. UICollectionView 讲解-备

    什么是UICollectionView UICollectionView是一种新的数据展示方式,简单来说可以把他理解成多列的UITableView(请一定注意这是UICollectionView的最最 ...

  5. Windows下python安装matplotlib

    此文为转载,原文地址为:http://blog.csdn.net/u010585135/article/details/42127273 一.下载matplotlib安装包:网址http://matp ...

  6. DES加解密实现方式

    private static readonly byte[] _keys = { 0x22, 0x84, 0x56, 0x98, 0x90, 0xAB, 0xpD, 0xEF }; private s ...

  7. 导出excel的三种方式

    第一种是Response输出,这种方式输出的文件不符合标准的excel格式,在打开的时候会有提示,而且不好控制内容.第一种是Response输出,这种方式输出的文件不符合标准的excel格式,在打开的 ...

  8. C51系列RAM寄存器表

    特殊功能寄存器地址表 SFR 符号 字节 地址 位地址和位名称 D7 D6 D5 D4 D3 D2 D1 D0 P0口 P0 80H P0.7 P0.6 P0.5 P0.4 P0.3 P0.2 P0. ...

  9. C51 库函数

    C-51软件包的库包含标准的应用程序,每个函数都在相应的头文件(.h)中有原型声明.如果使用库函数,必须在源程序中用预编译指令定义与该函数相关的头文件(包含了该函数的原型声明).例如:#include ...

  10. WIN7笔记本显示连接不可用

    如图所示,找不到任何无线网络 解决方法: 不小心把无线关掉而已,笔记本键盘上F5~F12找看看有没有无线标志,有的话要先按下 Fn键不放,再按下那个有无线标志的Fn键.