Python:迭代器

在使用Python的过程中,很容易混淆如下几个关联的概念:

  • 容器(container)
  • 可迭代对象(Iterable)
  • 迭代器(Iterator)
  • 生成器(generator)
  • 生成器表达式
  • {list, set, dict} 解析式

1.容器(container)

容器是用来储存元素的一种数据结构,它支持隶属测试,容器将所有数据保存在内存中,在Python中典型的容器有:

  • list, deque, ...
  • set,frozesets,...
  • dict, defaultdict, OrderedDict, Counter, ...
  • tuple, namedtuple, ...
  • str

通过判断一个对象是否包含某个元素来确定它是否为一个容器

>>> assert 1 in [1,2,3]       # lists
>>> assert 4 not in [1,2,3]
>>> assert 1 in {1,2,3}       # sets
>>> assert 4 not in {1,2,3} 
>>> assert 1 in (12,3)        # tuples
>>> assert 4 not in (1,2,3)

字典容器通过检查是否包含某个键来进行判断

>>> d = {1:"foo", 2:"bar", 3:"qux"}
>>> assert 1 in d
>>> assert 4 in d
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError
>>> assert "foo" in d
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

字符串通过检查是否包含某个子 串来判断

>>> s="foo"
>>> assert "f" in s
>>> assert "b" in s
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

2.可迭代对象

如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。

 很多容器都是可迭代对象,此外还有更多的对象同样也是可迭代对象,比如处于打开状态的files,sockets等等。但凡是可以返回一个 迭代器 的对象都可称之为可迭代对象,听起来可能有点困惑,没关系,可迭代对象与迭代器有一个非常重要的区别。

>>> x=[1,2,3]
>>> y=iter(x)
>>> z=iter(x)
>>> next(y)
1
>>> next(y)
2
>>> next(z)
1
>>> type(x)
<class 'list'>
>>> type(y)
<class 'list_iterator'>

 x 是一个可迭代对象,可迭代对象和容器一样是一种通俗的叫法,并不是指某种具体的数据类型,list是可迭代对象,dict是可迭代对象,set也是可迭代对象。 y 和 z 是两个独立的迭代器,迭代器内部持有一个状态,该状态用于记录当前迭代所在的位置,以方便下次迭代的时候获取正确的元素。迭代器有一种具体的迭代器类型,比如 list_iterator , set_iterator 。可迭代对象实现了 __iter__ 和 __next__ 方法(python2中是 next 方法,python3是 __next__ 方法),这两个方法对应内置函数 iter() 和 next() 。 __iter__ 方法返回可迭代对象本身,这使得他既是一个可迭代对象同时也是一个迭代器。

3.一些迭代工具

3.1并行迭代

>>> names=['greg','greg1','greg2']
>>> ages=[18,12,13]
>>> for i in range(len(names)):
    print(names[i]+' is '+str(ages[i]))

    
greg2 is 13
greg2 is 13
greg2 is 13
>>> for n,a in zip(names,ages):
    print(names[i]+' is '+str(ages[i]))

    
greg2 is 13
greg2 is 13
greg2 is 13

3.2 编号迭代

list1 = ["", "", "一个", "测试"]
for index, item in enumerate(list1):
    print(index, item)

0 这
12 一个
3 测试

3.2 翻转和排序迭代

>>> sorted([2,6,3,1,5])
[1, 2, 3, 5, 6]
>>> sorted('Hello,world!')
['!', ',', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w']
>>> list(reversed('Hello,world!'))
['!', 'd', 'l', 'r', 'o', 'w', ',', 'o', 'l', 'l', 'e', 'H']
>>> ''.join(reversed('Hello,world!'))
'!dlrow,olleH'

4.迭代器(iterator)

它是一个带状态的对象,他能在你调用 next() 方法的时候返回容器中的下一个值,任何实现了 __next__() (python2中实现 next() )方法的对象都是迭代器,至于它是如何实现的这并不重要。

#迭代器,1,有iter方法。2,有next方法
# 可以使用isinstance()判断一个对象是否是Iterable对象:
l=[1,2,3,4]
d=iter(l)
print(d) #<list_iterator object at 0x000002C34B71C160>
# list,tuple,dict,string:iterable
print(next(d))
print(next(d))
print(next(d))
print(next(d))

# for循环内部三件事:1,调用可迭代对象iter方法,返回迭代器对象
# 2,不断调用迭代器对象的next方法
# 3,处理StopIteration,遇到退出
# for i in [1,2,3,4]:
#     iter([1,2,3,4])

from collections import Iterator,Iterable
print(isinstance(2,list))#False
l=[1,2,3,4]
d=iter(l)
print(d)
print(isinstance(l,list))
print(isinstance(l,Iterable))
print(isinstance({}, Iterable))
print(isinstance('abc', Iterable))
print(isinstance((x for x in range(10)), Iterable))
print(isinstance(100, Iterable))#False

# 小结
# 凡是可作用于for循环的对象都是Iterable类型;
# 凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
# 集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
# Python的for循环本质上就是通过不断调用next()函数实现的,例如:


# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
while True:# 循环:
    try:# 获得下一个值:
        x = next(it)
    except StopIteration:# 遇到StopIteration就退出循环
        break

可以使用迭代器来解决复用可占空间的问题

class Fab(object):
    def __init__(self, max):
        self.max = max
        self.n, self.a, self.b = 0, 0, 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.n < self.max:
            r = self.b
            self.a, self.b = self.b, self.a + self.b
            self.n = self.n + 1
            return r
        raise StopIteration()

for key in Fab(5):
    print(key)
    
# 1
# 1
# 2
# 3
# 5

Fab既是一个可迭代对象(因为它实现了 __iter__ 方法),又是一个迭代器(因为实现了 __next__ 方法)。实例变量 self .a 和 self.b 用户维护迭代器内部的状态。每次调用 next() 方法的时候做两件事:

  1. 为下一次调用 next() 方法修改状态
  2. 为当前这次调用生成返回结果

迭代器就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。

5.从迭代器得到序列

 list构造方法显式将迭代器转化为列表

class TestIterator:
    value=0
    def __next__(self):
        self.value +=1
        if self.value>10:
            raise StopIteration
        return self.value
    def __iter__(self):
        return self

ti=TestIterator()
print(list(ti))
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

 

posted @ 2017-11-11 22:31  ninxin18  阅读(437)  评论(0编辑  收藏  举报