Python学习之Part18.迭代器

1.迭代器

我们知道,对于一个列表而言,想要得到列表中的元素,有2种方法可以实现:
 1.索引 (切片的本质也是索引)
 2.循环*
在python中可以进行循环的数据类型有:

列表list,元组tuple,集合set,字符串str,字典dict, range();
文件句柄 f = open() for line in f
枚举 enumerate

这是因为以上数据类型都是可迭代的。
介绍一个函数:

dir()
 参数是一个数据类型,例如:[], {}…
 返回值:此种数据类型的所有方法,返回值类型:列表

双下方法的概念:

一般称某些双下划线的方法为:双下方法
 这种方法一般是已经写好的C语言的代码,可以通过不止一种方式进行调用
 一般情况下,双下方法不直接被我们调用,通过其他语法触发的

例如:

print([1].__add__([2]))
# 下面与上面等价,下面实际上就是调用上面的方法
print([1]+[2])
打印列表的所有方法:
print(dir([]))

我们需要注意到列表的方法中含有__iter__方法
在这里插入图片描述
判断其他可以使用for循环的数据类型都含有__iter__方法,不能使用for循环的数据类型不含有__iter__方法:

# 不可使用for循环
print('__iter__' in dir(int))
print('__iter__' in dir(bool))
# 可以使用for循环
print('__iter__' in dir(list))
print('__iter__' in dir(dict))
print('__iter__' in dir(set))
print('__iter__' in dir(tuple))
print('__iter__' in dir(enumerate))

结果如下:
在这里插入图片描述
因此,我们称含有__iter__方法的数据类型都是可迭代的 --> 可迭代协议

对于一个可迭代的数据类型,调用__iter__方法后便会生成一个迭代器(iterator),例如:

print([].__iter__())

可以看到,iter()方法返回一个迭代器对象:
在这里插入图片描述迭代器也是一种数据类型,我们同样可以使用dir()函数来查看迭代器类型的方法,与可迭代的数据类型对比,我们可以看到迭代器所特有的方法为:

# 查看迭代器的方法
print(dir([].__iter__()))
# 查看迭代器所特有的方法
print(set(dir([].__iter__()))-set(dir([])))

迭代器的特有方法如下:
在这里插入图片描述
其中,__setstate__指定指针位置,__length_hint__求元素的个数
我们需要关注的重点是__next__方法,此方法用于逐个取迭代器中的值

li = [1,2,3]
# 定义一个迭代器
iterator  = li.__iter__()
# 取迭代器中的值
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())

输出结果如下:
在这里插入图片描述
当取值的数目超过迭代器中值的数目时就会报错:

li = [1,2,3]
# 定义一个迭代器
iterator  = li.__iter__()
# 依次取4个值
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())

运行时报错如下:
在这里插入图片描述因此,内部含有__next__和__iter__方法的都是迭代器(必须同时含有) --> 迭代器协议

则当我们进行一个for循环时,其原理如下:

li = []
iterator = li.__iter__() # 首先拿到一个迭代器
i = iterator.__next__() # 使用next方法取值
# 直到报错的时候循环结束

2.判断是否可迭代&迭代器

注意:使用python3.3以下版本,导入库时以 from collections导入,3.3以上版本应使用 from collections.abc形式导入,之前的导入方式在3.3以上的pyton解释器中已经被废弃,且在3.9版本中将不能再使用。

from collections.abc import Iterable
from collections.abc import Iterator
# 判断列表是否是一个迭代器
print(isinstance([],Iterator))
# 判断列表是否是可迭代的
print(isinstance([],Iterable))

输出结果如下:
我们可以看到,列表虽然是可迭代的数据类型,但它并不是一个迭代器,
因此,可迭代的并不一定是迭代器。
在这里插入图片描述
我们做一个小测试:

from collections.abc import Iterable
from collections.abc import Iterator

class A:
    def __iter__(self):pass
    def __next__(self):pass

a = A()
print(isinstance(a,Iterator))
print(isinstance(a,Iterable))

若A类即含有__iter__方法和__next__方法,则它是一个迭代器并且可迭代:
在这里插入图片描述

from collections.abc import Iterable
from collections.abc import Iterator

class A:
    def __iter__(self):pass
    # def __next__(self):pass

a = A()
print(isinstance(a,Iterator))
print(isinstance(a,Iterable))

当A类中只含有__iter__方法,则它可迭代但不是一个迭代器:
在这里插入图片描述

from collections.abc import Iterable
from collections.abc import Iterator

class A:
    # def __iter__(self):pass
    def __next__(self):pass

a = A()
print(isinstance(a,Iterator))
print(isinstance(a,Iterable))

当A类中只含有__next__方法,则它既不可迭代也不是一个迭代器:
在这里插入图片描述
因此:
 只要含有__iter__和__next__方法的数据类型都是迭代器
 只含有__iter__方法的仅仅可迭代
 只含有__next__方法的既不可迭代又不是迭代器

总结

 1.内部含有__iter__方法的数据类型都是可迭代的,都可以使用for循环 – 可迭代协议。
 2.内部同时含有__iter__方法和__next__方法的都是迭代器 – 迭代器协议、
 3.可以被for循环的都是可迭代的
 4.可迭代的内部都含有__iter__方法
 5.迭代器一定可迭代,但是可迭代的不一定是迭代器(__next__方法不一定存在)
 6.可迭代的.__iter__方法就能得到一个迭代器
 7.迭代器中的__next__方法可以一个一个的获取值
 8.优势:
   从容器类型中一个一个的取值,会把所有的值都取到;
   可以节省内存空间:
    迭代器并不会在内存中再占用一大块内存,
    而是随着循环,每次生成一个,然后每次next给我一个
 9.应用: for循环

可迭代对象的特点:
 并不是一次性就生成好的,而是在需要时一个一个给你
 例如:range(1000) 并不是直接生成1000个数在内存中
 但是对于像列表这种有值存在的,其值是存在于内存中的
 因此,使用迭代器可以节省内存

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值