• 欢迎访问蜷缩的蜗牛博客 蜷缩的蜗牛
  • 微信搜索: 蜷缩的蜗牛 | 联系站长 kbsonlong@qq.com
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

第八章 Python可迭代对象、迭代器和生成器

Python 蜷缩的蜗牛 8个月前 (02-08) 39次浏览 已收录

8.1 可迭代对象(Iterable)

大部分对象都是可迭代,只要实现了 __iter__ 方法的对象就是可迭代的。

__iter__ 方法会返回迭代器(iterator)本身,例如:

>>> lst = [1,2,3]
>>> lst.__iter__()
<listiterator object at 0x7f97c549aa50>

Python 提供一些语句和关键字用于访问可迭代对象的元素,比如 for 循环、列表解析、逻辑操作符等。

判断一个对象是否是可迭代对象:

>>> from collections import Iterable  # 只导入 Iterable 方法
>>> isinstance('abc', Iterable)     
True
>>> isinstance(1, Iterable)     
False
>>> isinstance([], Iterable)
True

这里的 isinstance()函数用于判断对象类型,后面会讲到。

可迭代对象一般都用 for 循环遍历元素,也就是能用 for 循环的对象都可称为可迭代对象。

例如,遍历列表:

>>> lst = [1, 2, 3]
>>> for i in lst:
...   print i
...
1
2
3

8.2 迭代器(Iterator)

具有 next 方法的对象都是迭代器。在调用 next 方法时,迭代器会返回它的下一个值。如果 next 方法被调用,但迭代器没有值可以返回,就会引发一个 StopIteration 异常。

使用迭代器的好处:

1)如果使用列表,计算值时会一次获取所有值,那么就会占用更多的内存。而迭代器则是一个接一个计算。

2)使代码更通用、更简单。

8.2.1 迭代器规则

回忆下在 Python 数据类型章节讲解到字典迭代器方法,来举例说明下迭代器规则:

>>> d = {'a':1, 'b':2, 'c':3}    
>>> d.iteritems()
<dictionary-itemiterator object at 0x7f97c3b1bcb0>
# 判断是否是迭代器
>>> from collections import Iterator
>>> isinstance(d, Iterator)
False
>>> isinstance(d.iteritems(), Iterator)
True
# 使用 next 方法。
>>> iter_items = d.iteritems()
>>> iter_items.next()
('a', 1)
>>> iter_items.next()
('c', 3)
>>> iter_items.next()
('b', 2)

由于字典是无序的,所以显示的是无序的,实际是按照顺序获取的下一个元素。

8.2.2 iter()函数

使用 iter()函数转换成迭代器:

语法:

iter(collection) -> iterator

iter(callable, sentinel) -> iterator

>>> lst = [1, 2, 3]    
>>> isinstance(lst, Iterator)
False
>>> lst.next()  # 不是迭代器是不具备 next()属性的
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'next'
>>> iter_lst = iter(lst)             
>>> isinstance(iter_lst, Iterator)
True
>>> iter_lst.next()
1
>>> iter_lst.next()
2
>>> iter_lst.next()
3

8.2.3 itertools 模块

itertools 模块是 Python 内建模块,提供可操作迭代对象的函数。可以生成迭代器,也可以生成无限的序列迭代器。

有下面几种生成无限序列的方法:

count([n]) –> n, n+1, n+2, …

cycle(p) –> p0, p1, … plast, p0, p1, …

repeat(elem [,n]) –> elem, elem, elem, … endlessly or up to n times 

也有几个操作迭代器的方法:

islice(seq, [start,] stop [, step]) –> elements from

chain(p, q, …) –> p0, p1, … plast, q0, q1, …

groupby(iterable[, keyfunc]) –> sub-iterators grouped by value of keyfunc(v) 

imap(fun, p, q, …) –> fun(p0, q0), fun(p1, q1), …

ifilter(pred, seq) –> elements of seq where pred(elem) is True

1)count 生成序列迭代器

>>> from itertools import *  # 导入所有方法    
# 用法 count(start=0, step=1) --> count object
>>> counter = count()    
>>> counter.next()
0
>>> counter.next()
1
>>> counter.next()
2
......

可以使用 start 参数设置开始值,step 设置步长。

2)cycle 用可迭代对象生成迭代器

# 用法 cycle(iterable) --> cycle object
>>> i = cycle(['a', 'b', 'c'])  
>>> i.next()
'a'
>>> i.next()
'b'
>>> i.next()
'c'

3)repeat 用对象生成迭代器

# 用法 repeat(object [,times]) -> create an iterator which returns the object,就是任意对象    
>>> i = repeat(1)
>>> i.next()
1
>>> i.next()
1
>>> i.next()
1
......

可使用无限次。

也可以指定次数:

>>> i = repeat(1, 2)    
>>> i.next()
1
>>> i.next()
1
>>> i.next()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration

4)islice 用可迭代对象并设置结束位置

# 用法 islice(iterable, [start,] stop [, step]) --> islice object    
>>> i = islice([1,2,3],2)   
>>> i.next()             
1
>>> i.next()
2
>>> i.next()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration

正常的话也可以获取的 3。

5)chain 用多个可迭代对象生成迭代器

# 用法 chain(*iterables) --> chain object    
>>> i = chain('a','b','c')
>>> i.next()
'a'
>>> i.next()
'b'
>>> i.next()
'c'

6)groupby 将可迭代对象中重复的元素挑出来放到一个迭代器中

# 用法 groupby(iterable[, keyfunc]) -> create an iterator which returns    
>>> for key,group in groupby('abcddCca'):
...   print key,list(group)               
...
a ['a']
b ['b']
c ['c']
d ['d', 'd']
C ['C']
c ['c']
a ['a']

groupby 方法是区分大小写的,如果想把大小写的都放到一个迭代器中,可以定义函数处理下:

>>> for key,group in groupby('abcddCca', lambda c: c.upper()):    
...   print key, list(group)
...
A ['a']
B ['b']
C ['c']
D ['d', 'd']
C ['C', 'c']
A ['a']

7)imap 用函数处理多个可迭代对象

# 用法 imap(func, *iterables) --> imap object    
>>> a = imap(lambda x, y: x * y,[1,2,3],[4,5,6])   
>>> a.next()
4
>>> a.next()
10
>>> a.next()
18

8)ifilter 过滤序列

# 用法 ifilter(function or None, sequence) --> ifilter object    
>>> i = ifilter(lambda x: x%2==0,[1,2,3,4,5])
>>> for i in i:
...   print i
...
2
4

当使用 for 语句遍历迭代器时,步骤大致这样的,先调用迭代器对象的 __iter__ 方法获取迭代器对象,再调用对象的 __next__()方法获取下一个元素。最后引发 StopIteration 异常结束循环。


博客地址:http://lizhenliang.blog.51cto.com

QQ 群:323779636(Shell/Python 运维开发群 

8.3 生成器(Generator)

什么是生成器?

1)任何包含 yield 语句的函数都称为生成器。

2)生成器都是一个迭代器,但迭代器不一定是生成器。

8.3.1 生成器函数

在函数定义中使用 yield 语句就创建了一个生成器函数,而不是普通的函数。

当调用生成器函数时,每次执行到 yield 语句,生成器的状态将被冻结起来,并将结果返回 __next__ 调用者。冻结意思是局部的状态都会被保存起来,包括局部变量绑定、指令指针。确保下一次调用时能从上一次的状态继续。

以生成斐波那契数列举例说明 yield 使用:

斐波那契(Fibonacci)数列是一个简单的递归数列,任意一个数都可以由前两个数相加得到。

#!/usr/bin/python
# -*- coding: utf-8 -*-
def fab(max):
    n, a, b = 0, 0, 1
    while n < max:
        print b
        a, b = b, a + b
        n += 1
fab(5)

# python test.py
1
1
2
3
5

 使用 yied 语句,只需要把 print b 改成 yield b 即可:

#!/usr/bin/python
# -*- coding: utf-8 -*-
def fab(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        # print b
        a, b = b, a + b
        n += 1
print fab(5)
# python test.py
<generator object fab at 0x7f2369495820>

可见,调用 fab 函数不会执行 fab 函数,而是直接返回了一个生成器对象,上面说过生成器就是一个迭代器。那么就可以通过 next 方法来返回它下一个值。

>>> import test
>>> f = test.fab(5)   
>>> f.next()       
1
>>> f.next()                               
1
>>> f.next()
2
>>> f.next()
3
>>> f.next()
5

每次 fab 函数的 next 方法,就会执行 fab 函数,执行到 yield b 时,fab 函数返回一个值,下一次执行 next 方法时,代码从 yield b 的吓一跳语句继续执行,直到再遇到 yield。

8.3.2 生成器表达式

在第四章 Python 运算符和流程控制章节讲过,简化 for 和 if 语句,使用小括号()返回一个生成器,中括号[]生成一个列表。

回顾下:

# 生成器表达式
>>> result = (x for x in range(5))
>>> result
<generator object <genexpr> at 0x030A4FD0>
>>> type(result)
<type 'generator'>

# 列表解析表达式
>>> result = [ x for x in range(5)]
>>> type(result)
<type 'list'>
>>> result
[0, 1, 2, 3, 4]

第一个就是生成器表达式,返回的是一个生成器,就可以使用 next 方法,来获取下一个元素:

>>> result.next()
0
>>> result.next()
1
>>> result.next()
2
......

本文转载自 第八章 Python 可迭代对象、迭代器和生成器


蜷缩的蜗牛 , 版权所有丨如未注明 , 均为原创丨 转载请注明第八章 Python 可迭代对象、迭代器和生成器
喜欢 (0)
[]
分享 (0)