第十四章 - 可迭代的对象、迭代器和生成器

可迭代的对象、迭代器和生成器

1、生成器实现了迭代器的接口,所以生成器也是迭代器

2、迭代器从集合中取出元素,生成器用于“凭空”生成元素

3、yield from 合并生成器,创建通道

4、Python中所有集合都可以迭代

 

14.1 Sentence类第一版:单词序列

示例14-1

import re
import reprlib

RE_WORD = re.compile("\w+")


class Sentence(object):
    def __init__(self, text):
        self.text = text
        self.words = RE_WORD.findall(text)

    def __getitem__(self, item):  # 实现了getitem方法,Python也会自动创建一个迭代器。任何Python序列都实现了__getitem__方法;标准的序列也都实现了__iter__方法。
        return self.words[item]

    def __len__(self):
        return len(self.words)

    def __repr__(self):
        return "Sentence(%s)" % reprlib.repr(self.text)

s = Sentence("The time has come, the Walrus said")
print(s)
for word in s:
    print(word)
print(list(s))
>>>
Sentence('The time has...e Walrus said')
The
time
has
come
the
Walrus
said
['The', 'time', 'has', 'come', 'the', 'Walrus', 'said']

序列可以迭代的原因:iter函数

解释器需要迭代对象x时,会自动调用iter(x)。

内置的iter函数有以下作用:

1、检查对象是否实现了__iter__方法,如果实现了就调用他/她,获取一个迭代器。

2、如果没有实现__iter__方法,但是实现了__getitem__方法,python会创建一个迭代器,尝试按顺序获取元素。

3、如果尝试失败,Python抛出TypeError异常(“C object is not iterable”)。

 

从Python3.4开始,检查对象X能否迭代,最准确的方式是:调用iter(x)函数,如果不可迭代,再处理TypeError异常。

 

14.2 可迭代对象与迭代器的对比

可迭代对象:

  使用iter内置函数可以获取迭代器的对象,如果对象实现了能返回迭代器的__iter__方法,那么对象就是可迭代对象。

  注: Python语言内部会处理for循环和其他迭代上下文中的StopIteration异常(while不会)。

迭代器:

  只需要实现__next__和__iter__两个方法,它就是迭代器。

 

14.10 Python3.3中新出现的语法:yield from

如果生成器函数需要产出另一个生成器生成的值,传统的解决方法是使用嵌套的for循环。

示例1

def chain(*iterable):
    for it in iterable:
        for i in it:
            yield i

s = "ABC"
ss = tuple(range(10))
aa = list(chain(s, ss))
print(aa)
>>>>
['A', 'B', 'C', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

示例2

def chain2(*iterable):
    for it in iterable:
        yield from it  # yield from i完全代替了内层的for循环
s = "ABC"
ss = tuple(range(10))
aa = list(chain2(s, ss))
print(aa)
>>>>
['A', 'B', 'C', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

示例3

"""
iter(source, sentinel=None)  # sentinel哨符,当可调用对象返回这个值时触发迭代器抛出StopIteration异常
"""
def file_read(file):
    with open(file) as fp:
        for line in iter(fp.readline, "\n"):
            process_line(line)

 

示例4

yield关键字只能把最近的外层函数变成生成器函数,下面的示例将获取到一个死循环的函数,而不是生成器

def f():
    def do_yield(n):
        yield n
    x = 0
    while True:
        x += 1
        do_yield(x)

print(f)
>>>>
<function f at 0x014A2300>

示例5

基于yield from来实现

def b():
    def do_yield(n):
        yield n
    x = 0
    while True:
        x += 1
        yield from do_yield(x)

print(b())
>>>>
<generator object b at 0x009F66F0>

 

posted @ 2017-07-27 23:19  Vincen_shen  阅读(110)  评论(0)    收藏  举报