python中可迭代对象,迭代器,生成器的区别和联系

刚开始接触python的同学在各种参考书或者网上资料中经常看到迭代器,生成器,可迭代等字眼,并且可能对此感到迷惑。那么今天我们就来仔细梳理一下这几个概念的关系,经过这次梳理,大家应该就可以比较清晰地区分了。

首先,看一下“可迭代”。

可迭代,是指一个对象的属性。python中的对象,可以分为可迭代对象,不可迭代对象。当我们说一个对象是“可迭代”的时候,这个可迭代对象会具有一些特定的特点和属性。

1、直观来看,可迭代对象可以通过for循环去遍历,比如list,str等:

>>> a = [1,2,3]
>>> for i in a:
        print(i)      
1 2 3

>>> a = "hello"
>>> for i in a:
print(i)

h e l l o

2、可迭代对象,都会具有一个__iter__方法

>>> a = [1]
>>> dir(a)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

实际上,可迭代对象之所以能够迭代,或者说可以通过for去遍历,就是因为其具有这个方法。以list列表举例,当我们for遍历这个列表对象时,实际上这个对象调用了其__iter__方法,该方法返回另一个特殊的对象,这个特殊的对象用于下一步的遍历!

看到这里,大家会问,这个__iter__返回的是什么特殊的对象呢?对,这个对象就是我们接下来要说的迭代器。我们可以先调用__iter__方法产生一个迭代器看看:

>>> a=[1,2,3]
>>> b = a.__iter__()
>>> b

<list_iterator object at 0x10592eb00>

这里b就是一个迭代器,由于是通过列表得到的,所以它是一个列表迭代器。

现在我们具体看看迭代器是什么

迭代器是python中一类对象,这类对象有这几个特点:

1、迭代器都会有一个__next__方法,通过这个方法可以逐个得到其每一个元素:

我们以上一步产生的迭代器b举例

>>> b.__next__()

1
>>> b.__next__()
2
>>> b.__next__()
3
>>> b.__next__()
Traceback (most recent call last):
  File "<pyshell#42>", line 1, in <module>
    b.__next__()

StopIteration

每次执行__next__方法,都会得到一个元素,直到所有元素得到后,抛出一个StopIteration错误,表示迭代结束。

2、迭代器都是可迭代的,也就是说,可以用for去遍历,比如上面的b,可以这样去实现:

>>> for i in b:
print(i)

1 2 3

其实在介绍“可迭代”这个概念时,我们也提到,可迭代对象for遍历时,其实最后也是返回一个迭代器,对迭代器遍历。

3、细心的同学会说,迭代器既然可以迭代,那它一定也有一个__iter__方法了?确实是的,只不过,迭代器这个方法返回的是它本身:

>>> a = iter([1,2,3])
>>> a
<list_iterator object at 0x10592eb38>
>>> b = a.__iter__()
>>> b

<list_iterator object at 0x10592eb38>

我们看到a,b是同一个对象


到这里,可以对迭代器和可迭代对象做一个总结,一句话:迭代器都是可迭代对象,可迭代对象不一定是迭代器。

了解了这些,我们就可以自己定义一个可迭代对象了。要想自己定义一个可迭代对象,只要给这个对象一个__iter__方法,并在这个方法中返回一个迭代器,就可以了,下面是一个例子:

>>> class MyIterableObj(object):
def __iter__(self):
return iter([1,2,3])
>>> test = MyIterableObj()
>>> [i for i in test]

[1, 2, 3]

这里我们使用iter函数得到一个迭代器。

那生成器又是什么呢?

其实可以这样简单理解,一个函数中出现yield,那么它就不是一个普通的函数,而是一个生成器。

>>> def test():
for i in [1,2,3]:
yield i
>>> a = test()
>>> a
<generator object test at 0x105914308>

这里a就是一个生成器。生成器的作用是什么呢?

最常见的是,我们可以使用生成器实现一个迭代模式。前面我们看到,通过iter函数,可以得到一个迭代器,从而得到一个可迭代对象,用于迭代操作。其实,通过生成器,也可以达到相同的目的。我们看下面的例子:

>>> def my_generator():
for i in [1,2,3]:

yield i>>> def my_generator():

>>> class MyIterableObj(object):
def __iter__():

return my_generator()

>>> test = MyIterableObj()
>>> [i for i in test]
[1, 2, 3]

这次,我们在自定义类的__iter__方法中,没有返回iter函数,而是返回我们自己定义的一个生成器函数,但是效果是一样的。

其实如果我们看一下一个生成器的属性,它和迭代器一样,也有__next__, __iter__方法,同样可以使用__next__去得到其中每一个元素,这样看来,用生成器去替代iter函数,就很好理解了:

>>> def my_generator():
for i in [1,2,3]:
yield i
>>> a = my_generator()
>>> a
<generator object my_generator at 0x105928518>
>>> dir(a)
['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']
>>> a.__next__()
1
>>> a.__next__()
2
a.__next__()
>>> a.__next__()
3
>>> a.__next__()
Traceback (most recent call last):
  File "<pyshell#125>", line 1, in <module>
    a.__next__()
StopIteration






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值