深度解读可迭代对象(Iterable)、迭代器(Iterator)、生成器(generator)

此类文章网络上繁多,鄙认为基础语法部分直接阅读官方API是最高效且较全面的。如下从官方API角度解读。

Iterable可迭代对象

iterable官方API

An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an __iter__() method or with a __getitem__() method that implements sequence semantics.

Iterables can be used in a for loop and in many other places where a sequence is needed (zip(), map(), …).
When an iterable object is passed as an argument to the built-in function iter(), it returns an iterator for the object. This iterator is good for one pass over the set of values.
When using iterables, it is usually not necessary to call iter() or deal with iterator objects yourself. The for statement does that automatically for you, creating a temporary unnamed variable to hold the iterator for the duration of the loop. See also iterator, sequence, and generator.

如上要点归纳:
1、Iterable是指一次能够返回其中一个成员的对象。比如所有序列类型(如list, str 和 tuple)、所有非序列类型(如字典、文件对象和自定义的所有实现了__getitem__()或__iter__()方法的类)
2、Python内置函数iter()接受一个可迭代对象,返回值是一个迭代器(Iterator)
3、Iterable常用在for循环、zip()、map()…此类场景中。但当使用Iterables时,没必要用iter()函数,for声明、zip()、map()会帮我们自动调用。见下例

from collections.abc import Iterable, Iterator
from collections import deque
class Iter:
    def __init__(self, *args):
        self._l = list()
        self._l.extend(args)

    def __iter__(self):
        print("use __iter__")
        return iter(self._l)

    def __getitem__(self,index):
        print("use __getitem__")
        if index<len(self._l):
            return self._l[index]
        else:
            raise IndexError
it1 = Iter(1, 2)
it2 = Iter(3, 4)
for i in iter(it1):#手动调用iter函数
    print(i,end=" ")
print("\n-----------------------")
for i in it1:#由输出可知for声明自动调用了iter函数
    print(i,end=" ")
print("\n-----------------------")
it = zip(it1,it2)
print("zip done")#由输出可知zip自动调用了iter函数
for i, j in it:
    print(i,j,end=" ")
print("\n-----------------------")
it1 = map(lambda x: x ** 2, it1)#由输出可知map自动调用了iter函数
print("map done")
for i in it1:
    print(i,end=" ")

输出如下

use __iter__
1 2 
-----------------------
use __iter__
1 2 
-----------------------
use __iter__
use __iter__
zip done
1 3 2 4 
-----------------------
use __iter__
map done
1 4 

将类中的__iter__()函数注释掉,保留__getitem__()。上述代码输出结果如下。可以看到调用__getitem__()的次数比__iter__()多。

use __getitem__
1 use __getitem__
2 use __getitem__

-----------------------
use __getitem__
1 use __getitem__
2 use __getitem__

-----------------------
zip done
use __getitem__
use __getitem__
1 3 use __getitem__
use __getitem__
2 4 use __getitem__

-----------------------
map done
use __getitem__
1 use __getitem__
4 use __getitem__

iter

内置函数iter官方API

Return an iterator object. The first argument is interpreted very differently depending on the presence of the second argument. Without a second argument, object must be a collection object which supports the iterable protocol (the __iter__() method), or it must support the sequence protocol (the __getitem__() method with integer arguments starting at 0). If it does not support either of those protocols, TypeError is raised. If the second argument, sentinel, is given, then object must be a callable object. The iterator created in this case will call object with no arguments for each call to its __next__() method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned.

当类中同时定义了__iter__和__getitem__两种魔法方法的时候,iter()函数会优先选择__iter__,只有在__iter__不存在的时候才会选择__getitem__。
对比上述演示代码输出可以看到定义__iter__方法是更好的方式。

如何判断一个对象是否是Iterable

collections.abc.Iterable官方API

ABC for classes that provide the __iter__() method.
Checking isinstance(obj, Iterable) detects classes that are registered as Iterable or that have an __iter__() method, but it does not detect classes that iterate with the __getitem__() method. The only reliable way to determine whether an object is iterable is to call iter(obj).

唯一可信赖用于判断对象obj是否是可迭代对象的方式是调用 iter(obj),如果不报错,说明是可迭代对象,反之则不是。

Iterator迭代器

An object representing a stream of data. Repeated calls to the iterator’s __next__() method (or passing it to the built-in function next()) return successive items in the stream. When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its __next__() method just raise StopIteration again.
Iterators are required to have an __iter__() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted.
One notable exception is code which attempts multiple iteration passes. A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container.

如上要点归纳:
1、Iteraor是一个表示数据流的对象,可通过重复调用__next__方法(或对其使用Python内置函数next())来获取数据流中元素。当没有元素遍历完时,抛出 StopIteration 异常。
2、迭代器要求实现返回自身self的__iter__方法。所以iterator都是iterable。
3、注意点:容器对象 (例如 list) 在你每次将其传入iter()函数或是在 for 循环中使用时都会产生一个全新的迭代器。
如果你尝试使用在之前迭代过程中已经被耗尽的容器迭代器会显得好像这是个空容器。

补充:迭代器的主要特点是它只在需要时才生成下一个值,这种延迟计算的方式使得迭代器适合处理大数据集和无限序列,因为它不会一次性将所有数据都加载到内存中,而是按需生成和处理数据。

代码演示:一个斐波那契数列迭代器

class Fib(object):
    def __init__(self):
        self.a = 0
        self.b = 1
    def __next__(self):
        self.a , self.b = self.b , self.a + self.b
        return self.a
    def __iter__(self):
        print("use __iter__")
        return self
it=iter(Fib())
print(next(it))
print(next(it))
print(next(it))

generator生成器

generator官方API

A function which returns a generator iterator. It looks like a normal function except that it contains yield expressions for producing a series of values usable in a for-loop or that can be retrieved one at a time with the next() function.
Usually refers to a generator function, but may refer to a generator iterator in some contexts. In cases where the intended meaning isn’t clear, using the full terms avoids ambiguity.

如上要点归纳:
1、生成器属于迭代器,故可以用next()函数获取值,也可以在for循环中使用。
2、生成器有两种形式:由生成函数创造的生成迭代器 或 生成器表达式。

generator iterator:An object created by a generator function.
generator expression:An expression that returns an iterator.

代码演示

#含yield表达式的生成函数
def my_gene():
    for i in range(3):
        yield i
for i in my_gene():
    print(i)
g=my_gene()#type(g):<class 'generator'>
print(next(g))
print(next(g))
/*
0
1
2
0
1
*/

#生成器表达式
gene1 = (x for x in range(1, 5))
gene2 = (x for x in [1,2,3])
print(type(gene1))#<class 'generator'>

sequence序列

sequence官方API

An iterable which supports efficient element access using integer indices via the __getitem__() special method and defines a __len__() method that returns the length of the sequence. Some built-in sequence types are list, str, tuple, and bytes. Note that dict also supports __getitem__() and __len__(), but is considered a mapping rather than a sequence because the lookups use arbitrary immutable keys rather than integers.
The collections.abc.Sequence abstract base class defines a much richer interface that goes beyond just __getitem__() and __len__(), adding count(), index(), __contains__(), and __reversed__(). Types that implement this expanded interface can be registered explicitly using register().

如上要点归纳:
1、sequence是定义了__getitem__()和__len__()函数的可迭代对象,内置序列有list、str、tuple、bytes,dict虽然也实现了__getitem__()和__len__()函数函数,但它是映射类型。
2、抽象基类collections.abc.Sequence中定义了许多接口如count(), index(), __contains__(), and __reversed__()可用于扩展。

collections.abc官方API

补充:collections.abc 模块定义了一系列抽象基类,继承这些基类则必须实现其中的抽象方法,否则会引发 TypeError 错误。
可用issubclass() 或 isinstance()方法于测试一个类是否提供某个特定的接口,例如是否为 hashable 或是否为 mapping 等。

如下列举一些collections.abc常见的抽象基类

ABCInherits fromAbstract MethodsMixin Methods
Container__contains__
Hashable__hash__
Iterable__iter__
IteratorIterable__next____iter__
GeneratorIteratorsend, throwclose, __iter__, __next__
CollectionSized, Iterable, Container__contains__, __iter__, __len__
SequenceReversible, Collection__getitem__, __len____contains__, __iter__, __reversed__, index, and count
SetCollection__contains__, __iter__, __len____le__, __lt__, __eq__, __ne__, __gt__, __ge__, __and__, __or__, __sub__, __xor__, and isdisjoint
MappingCollection__getitem__, __iter__, __len____contains__, keys, items, values, get, __eq__, and __ne__

Mixin Methods的含义可以参考下这篇文章

  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值