guxh的python笔记:迭代

1,可迭代对象iterator,迭代器iterator,生成器generator

可迭代对象iterable:实现了__iter__方法的类,iter()方法可以从iterable中获取iterator。

迭代器Iterator:1)实现__iter__方法(返回自己)和__next__(获取值)方法的类。2)生成器。

生成器generator:含yeild,生成器属于迭代器。

上述三种类型都可作用于for循环。

list、dict、str虽然是iterable,却不是iterator,为什么呢?因为iterator表示的是一个数据流,可以被next()调用不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把数据流看作一个序列,但我们无法提前知道序列长度,只有不断通过next()进行下一个计算。iterator甚至可以表示无限大的数据流,list不可能无限大。

2,可迭代对象与迭代器的关系

关于可迭代与迭代器的关系,具体实现细节可参考“3实现可迭代的方法”中的经典版方法。

s = 'abcdefg'    # s是个iterator,<class 'str'>

s可以被迭代:

for i in s:
   print(i)

迭代的本质是从iterable获取iterator(iterable的__iter__方法return了一个iterator),然后再不断使用iterator的next()方法获取值:

sit = iter(s) # it是个iterator,<class 'str_iterator'>
while True:
  try:
     print(next(sit))
  except StopIteration:
    break 

判断是否可迭代,iterable和iterator都可以被迭代:

isinstance(s, collections.Iterable) # True
isinstance(sit, collections.iterable) # True

但s不能被next,sit可以被next,因为s是iterable没有__next__,sit是iterator具有__next__

3,实现对象可迭代的方法

实现一个序列类型,接受输入值x,返回从x到11的值。

3.1,方法一:python序列鸭子类型

python在尝试迭代对象时,找不到__iter__就会去调用__getitem__,__getitem__实现从0开始的索引取值即可

class Foo:
    def __init__(self, data):
        self.data = data

    def __getitem__(self, i):
        return range(self.data, 11)[i]

 

3.2,方法二:经典版

iterable+iterator,构建Foo的iterator,缺点是代码量大。

关键点:iterable的__iter__返回iterator;iterator的__iter__返回self,__next__逐个取值

class Foo:
    def __init__(self, data):
        self.data = data

    def __iter__(self):    # iterable中的__iter__返回iterator
        return Foo_iterator(self.data)

class Foo_iterator:
    def __init__(self, data):
        self.data = data

    def __iter__(self):    # iterator中的__iter__返回自己
        return self

    def __next__(self):    # iterator实现__next__
        if self.data > 10:
            raise StopIteration
        else:
            num = self.data
        self.data += 1
        return num

看看Foo的实例和返回的iterator:

f = Foo(1)
fit = iter(f)
print(type(f))  # <class '__main__.Foo'>
print(type(fit))  # <class '__main__.Foo_iterator'>

对比下内置的iterable类,是不是完全一致:

s = 'abc'
sit = iter(s)
print(type(s))  # <class 'str'>
print(type(sit))  # <class 'str_iterator'>

r = range(10)
rit = iter(r)
print(type(r))  # <class 'range'>
print(type(rit))  # <class 'range_iterator'>

3.3,方法三:糟糕版

Foo自己实现__next__和__iter__,让Foo既是iterable,也是自己的iterator,糟糕不推荐

class Foo:
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        return self

    def __next__(self):
        if self.data > 10:
            raise StopIteration
        else:
            num = self.data
        self.data += 1
        return num

  

3.4,方法四:generator版

用generator实现iterable中的__iter__方法

class Foo:
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        for i in range(self.data, 11):
            yield i

看看Foo的实例和返回的iterator,发现iter()返回了一个generator:

f = Foo(1)
fit = iter(f)
print(type(f))    #  <class '__main__.Foo'>
print(type(fit))   #  <class 'generator'>

备注:Foo中的__iter__获取数据时,用的是惰性获取range(非惰性就是list(range(self.data, 11)))。一般推荐用惰性函数实现,例如用finditer替代findall。

3.5,方法五:生成器表达式

class Foo:
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        return (i for i in range(self.data, 11))

 

4,生成器函数

待补充

猜你喜欢

转载自www.cnblogs.com/guxh/p/10235220.html