迭代器

以前看阮一峰老师的《ES6入门》,说到ES6开始,语言针对Array(ArrayLike)、Map、Set数据结构提供了统一的接口机制--iterator来实现遍历,并配套了for...of循环。并提醒我们iteraor只是实现了接口,与所遍历的数据结构是分开的。

今天大致看了python中的迭代器部分,发现从概念、特性和实现机制上,二者都相当一致。(说白了就是一东西。。)

数据结构:

只要实现或继承了iterable接口的数据结构,都可以用iterator遍历。

ES6中数组、类数组(字符串、HTMLCollection)、Map、Set数据结构都部署有属性[Symbol.iterator],调用它时返回一个迭代器,迭代时默认从该数据结构索引位置0往Length-1遍历,对Map、Set则是按元素添加顺序遍历。

Python中的集合数据(字符串、列表、元组、集合、字典)也自带一个内部方法__iter__.当调用语言内置函数iter(s)时实际上执行了s.__iter__()返回一个迭代器。next(iterator)实际上执行了iterator.__next__()指向数据结构下一个成员,直到遇到终止条件。

终止条件:

日常遍历集合数据时我们很少需要手动调用迭代器,但是我们可以看看:

//ES6
    let lis = [1,2,3,5]
    let it = lis[Symbol.iterator]()
    console.log(it)
    console.log(it.next())
    ...
    console.log(it.next())//第4次
    console.log(it.next())//第5次
//输出:
Array Iterator {}
{value: 1, done: false}
...
{value: 5, done: false}
{value: undefined, done: true}

ES6的迭代器自带一个next方法,每次执行指向结构中下一个成员。当指针指向最后一个成员之后时,返回对象的done才为true,作为遍历结束的依据。

但是在python中手动调用迭代器时,遍历完最后一个元素再执行next,会直接抛出一个错误StopIteration表示遍历结束,比如下边:

list = [1, 2, 3]
it = iter(list)  # 创建迭代器对象
try:
    print(next(it))
    print(next(it))
    print(next(it))
    print(next(it))
except StopIteration:
    pass
finally:
    print("遍历结束")
#输出:
1
2
3
遍历结束

自定义迭代器对象:

由于迭代器本身只是描述一个接口,并不与具体数据结构绑定,所以我们可以借助迭代器的模式构建自定义的迭代器。

-用函数实现:

#《python cookbook》4.2节的例子
def frange(start, stop, increment):
    x = start
    while x < stop:
        yield x
        x += increment

for n in frange(0, 2, 0.5):
    print(n)
#输出:
0
0.5
1.0
1.5

-用class/对象实现:

#自定义一个iterable的class
class MyNumbers:
  def __iter__(self): 
    self.a = 1
    return self
 
  def __next__(self):
    x = self.a
    self.a += 1
    return x
 
myclass = MyNumbers()
myiter = iter(myclass) #执行myclass.__iter__()
 
print(next(myiter))    ##执行myclass.__next__()
print(next(myiter))
#输出:
1
2

generator函数:

顾名思义是可以产生一系列值的函数,或者说,在函数的不同执行阶段可以产生对应的状态。

python中的generator函数定义概念比较简单:凡是使用了yield语句的函数就是一个generator函数,generator函数返回的是一个迭代器对象。

ES6中generator的意义几乎一样,只是语法上稍有不同:function后必须加*符号,且yield关键字不是必须的。在ES中generator往往作为封装任务的容器。(反正我自己是很少用了,async比较舒服。。)

由于generator执行返回的是一个iterator,因而可以充当数据结构的iterator接口,不过这方面我倒是很少用到。

generator和iterator的很多实践在python和es6中都是通用的,毕竟这模式本来就和语言无关。讲真,如果我们需要动态遍历一个符合某种规则的序列,使用iterator比先生成一个序列实例再去逐一遍历其元素性能要好很多。

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值