Fluent Python笔记--可迭代对象,迭代器与生成器

当解释器想要迭代访问一个对象的时候,会调用iter(x)

  1. iter方法会检查对象是否实现了__iter__方法,如果实现了,就调用它返回一个迭代器。
  2. 如果没有实现__iter__,则去尝试调用__getitem__方法,解释器创建一个迭代器,按下表从0开始依次获取元素。
  3. 如果上面两个方法都没有实现,则抛出TypeError。错误信息为:"XXX object is not iterable"。

需要说明的一点是,在Python 2.X的环境下,常常有range()xrange()两种方式来创建一个可迭代对象(在Python 3.X中统一使用range(),效果和Python 2.X中的xrange()一致)。两者的区别在于前者返回的是一个计算好的列表,而后者返回的是一个惰性可迭代对象。列表并不是迭代器。

>>> a = range(7)
>>> b = xrange(7)
>>> c = (x for x in range(7))
>>> next(a)
TypeError: list object is not an iterator.
>>> next(b)
TypeError: xrange object is not an iterator.
>>> next(c)
0

那么,迭代器和可迭代对象又有什么区别呢?rangexrange对象都可以供多次迭代访问,而迭代器(上文中的c对象)仅可供一次迭代访问:从下表0开始到StopIteration
使用 iter 内置函数可以从可迭代对象获取迭代器的对象。如果对象实现了能返回迭代器的 __iter__方法,那么对象就是可迭代的。序列都可以迭代;实现了 __getitem__ 方法,而且其参数是从零开始的索引,这种对象也可以迭代。

最后用一个自定义的等差数列来说明可迭代对象的实现:

class ArithmeticProgression:
    def __init__(self, begin, step, end=None): 
        self.begin = begin
        self.step = step
        self.end = end # None -> 无穷数列

    def __iter__(self):
        result = type(self.begin + self.step)(self.begin) 
        forever = self.end is None 
        index = 0
        while forever or result < self.end: 
            yield result 
            index += 1
            result = self.begin + self.step * index 

# 也可以用下面方法来实现
def aritprog_gen(begin, step, end=None):
    result = type(begin + step)(begin)
    forever = end is None
    index = 0
    while forever or result < end:
        yield result
        index += 1
        result = begin + step * index

# 或者借助itertools来实现
def aritprog_gen(begin, step, end=None):
    import itertools
    first = type(begin + step)(begin)
    ap_gen = itertools.count(first, step)
    if end is not None:
        ap_gen = itertools.takewhile(lambda n: n < end, ap_gen)
    return ap_gen

你可能感兴趣的:(Fluent Python笔记--可迭代对象,迭代器与生成器)