Python的Iterable和Iterator

Python部落组织翻译,禁止转载,欢迎转发


Iterable: 可迭代的

Iterator:  迭代器


Iterable


可迭代的就是逻辑上是“一排”的东西,比如列表、字典、元组都是iterable。

>>> iter([1,2,3])

<listiterator object at 0x026C8970>

 

>>> iter({1:2, 2:4})

<dictionary-keyiterator object at 0x026CC1B0>

 

>>> iter(1234)

Traceback (most recent call last):

  File "<pyshell#145>", line 1, in <module>

    iter(1234)

TypeError: 'int' object is not iterable

对于列表iter()返回一个可迭代列表的对象,对于字典它返回字典的键的可迭代对象。其他类型就会报错了。


那将iter()用于用户定义的类型,会是什么结果?

假设我们定义了一个类String

lass String(object):

  def __init__(self, val):

    self.val = val

  def __str__(self):

    return self.val

它是可迭代的吗?


st = String('sample string')

iter(st)

TypeError: 'String' object is not iterable


你现在可能有了新问题:

  • 如何让用户定义的类可迭代

  • iter()内部做了什么?


我们来扩展一下刚刚定义的类

class String(object):

    def __init__(self, val):

        self.val = val

    def __str__(self):

        return self.val

    def __iter__(self):

        print "This is __iter__ method of String class"

        return iter(self.val)  #self.val is python string so iter() will return it's iterator


> st = String('Sample String')

>>> iter(st)

This is __iter__ method of String class

<iterator object at 0x026C8150>


我们添加了一个方法__iter__,它就可迭代了。这意味着iter(iterable)实际上内部是这样调用的iterable.__iter__()


等一下,添加__iter__并不是唯一的方式

class String(object):

    def __init__(self, val):

        self.val = val

    def __str__(self):

        return self.val

    def __getitem__(self, index):

        return self.val[index]


st = String('Sample String')

>>> iter(st)

<iterator object at 0x0273AC10>


添加__getitem方法也是可以的。__iter__和__getitem__同时存在时,__iter__优先生效。


自动迭代


For循环完成自动迭代

for x in iterable:

    print x


没有For循环我们如何模拟这个过程

def iterate_while(iterable):

    index = 0

    while(i< len(iterable)):

        print iterable[i]

        i +=1


这个办法对list和string有效,但是对字典无效,很显然它不是一个pythonic的办法。它也没有实现For循环的功能。


我们先看看Iterator,再回来解决这个问题。


Iterator


iterator对象在迭代过程中提供返回的值。它的next()或者__next__()方法用来产生这个值。

迭代结尾它会产生StopIteration异常。

iter函数为一个可迭代对象返回一个迭代器。

如果给iter函数传入一个迭代器,它就直接返回那个迭代器。


我们试着模拟For循环

def simulate_for_loop(iterable):

    it = iter(iterable)

    while(True):

try:

    print next(it)

except StopIteration:

    break


late_for_loop([23,12,34,56])

23

12

34

56


一个迭代器的逻辑大概是这样的

class Iterator:

    def __init__(self, iterable)

        self.iterable = iterable

    def __iter__(self):  #iter should return self if called on iterator

        return self

    def next(self):  #Use __next__() in python 3.x

        if condition: #it should raise StopIteration exception if no next element is left to return

            raise StopIteration


掌握这些基础知识就够了,我们编程中应该用不到更多的知识了。


List iterator


面试的时候你可能需要写这个,所以,注意

class list_iter(object):

    def __init__(self, list_data):

        self.list_data = list_data

        self.index = 0

    def __iter__(self):

        return self

    def next(self):   #Use __next__ in python 3.x

        if self.index < len(self.list_data):

            val = self.list_data[self.index]

            self.index += 1

            return val

        else:

            raise StopIteration()


让我们用list_iter定义列表的iterable


class List(object):

    def __init__(self, val):

        self.val = val

    def __iter__(self):

        return list_iter(self.val)

>> ls = List([1,2,34])

>>> it = iter(ls)

>>> next(it)

1

>>> next(it)

2

>>> next(it)

34

>>> next(it)

 

Traceback (most recent call last):

  File "<pyshell#254>", line 1, in <module>

    next(it)

  File "<pyshell#228>", line 13, in next

    raise StopIteration()

StopIteration


英文原文:http://www.pythonabc.com/iterable-and-iterator/

译者:诗书塞外