Python学习笔记——(5)迭代器与可迭代对象

1 绪论

  • 迭代是Python最强大的功能之一,是访问集合元素的一种方式。
  • 迭代器是一个可以记住遍历的位置的对象。
  • 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
  • 迭代器有两个基本的方法:iter() 和 next()。

2 自定义迭代器

2.1 判断对象是否可迭代

  • isinstance是一种判断对象类型的函数,和type的功能差不多,但是使用的方法不同,具体的使用方法详见Python isinstance() 函数 | 菜鸟教程
  • 使用isinstance(a, Iterable)可以判断a是否为可迭代,在使用Iterable之前应该先导入:from collections import Iterable,举个例子如下:
>>> a = [1,2,3]
>>> b = list
>>> c = {1: '1', 2: '2', 3: '3'}
>>> from collections import Iterable
>>> isinstance(a, Iterable)
True
>>> isinstance(b, Iterable)
False
>>> isinstance(c, Iterable)
True

2.2 基于重写__getitem__方法的自定义迭代器

  • 这种方式并不常见,建议使用2.3中的方法
  • __getitem__即利用索引获取值,用该方法书写迭代器的好处就是可以通过索引(即a[1]这种形式)获取迭代器的值
  • 下面展示通过修改__getitem__方法手写python的range方法
class MyRange:
    """创建一个自己的Range函数"""
    def __init__(self, minn, maxn=None, step=1):
        """初始化MyRange"""
        self.minn, self.maxn = (0, minn) if maxn is None else (minn, maxn)
        self.step = step
        diff = self.maxn - self.minn  # 差
        self.cnt = diff // step + (0 if diff % step == 0 else 1)
        # "//"的意思是向下取整除
        # 整句话的意思是向上取整除,获得输出对象的个数
        self.cur = self.minn

    def __getitem__(self, item):
        """重写方法"""
        if item < self.cnt:
            return self.minn + (item + self.cnt) % self.cnt * self.step
        raise IndexError('索引{}超出了范围{}'.format(item, self.maxn))

  • 运行之后
>>> for i in MyRange(2, 10, 3):
...     print(i, end=' ' if i < 8 else '\n')
...     
2 5 8
>>> range(10)[-3]
7
>>> MyRange(10)[-3]
7

2.3 基于重写__iter__方法和__next__方法的自定义迭代器

  • 【注意】当类中没有__getitem__方法时,上述的两种方法必须显式的定义在类中,才能使定义的类被识别为迭代对象。如果没有__getitem__方法,这个类对象不能通过索引获取元素
  • __iter__方法可以将需要的类返回作为迭代器类型
  • 逐次__next__方法指定产生的返回结果
  • 我们将上面的MyRange类用__iter____next__实现:
在这里插入代码片

3 其他常用迭代器

3.1 iternext

  • 在上文中介绍了如何使用__iter__方法和__next__方法自定义一个迭代器
  • iter方法即调用对象的__iter__方法,生成一个迭代器
  • next方法即调用对象的__next__方法,将迭代器进行一次迭代,并返回对象的__next__方法的返回值。如果对象中没有__next__方法,则next会调用对象的__getitem__方法,并将参数item的初始值设为0,返回__getitem__方法的返回值
class MyRange2:
    """创建一个自己的Range函数"""
    def __init__(self, minn, maxn=None, step=1):
        """初始化MyRange"""
        self.minn, self.maxn = (0, minn) if maxn is None else (minn, maxn)
        self.step = step
        diff = self.maxn - self.minn  # 差
        self.cnt = diff // step + (0 if diff % step == 0 else 1)
        # "//"的意思是向下取整除
        # 整句话的意思是向上取整除,获得输出对象的个数
        self.cur = self.minn

    def __iter__(self):
        """创建迭代器"""
        return self
    
    def __next__(self):
        """返回下一元素"""
        if self.cur < self.maxn:
            self.cur += self.step
            return self.cur - self.step
        else:
            raise StopIteration

  • 运行结果:
for i in MyRange2(2, 10, 3):
    print(i, end=' ' if i < 8 else '\n')
    
2 5 8
print(range(10)[-3])
7
print(MyRange2(10)[-3])
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: 'MyRange2' object is not subscriptable

3.2 zip同时去除多个对象中索引相同的元素

  • zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存。
  • 我们可以使用 list() 转换来输出列表。
  • 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同
  • 利用 * 号操作符,可以将元组解压为列表,即zip(*)可以理解为解压
>>>a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b)     # 返回一个对象
>>> zipped
<zip object at 0x103abc288>
>>> list(zipped)  # list() 转换为列表
[(1, 4), (2, 5), (3, 6)]
>>> list(zip(a,c))              # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]
 
>>> a1, a2 = zip(*zip(a,b))          # 与 zip 相反,zip(*) 可理解为解压,返回二维矩阵式
>>> list(a1)
[1, 2, 3]
>>> list(a2)
[4, 5, 6]
>>>
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值