Python | 魔法函数`__iter__`的用法

发布时间 2023-06-27 20:06:38作者: 张Zong在修行

下面是找到的一个比较好的科学解释:

Python中可迭代对象(Iterable)并不是指某种具体的数据类型,它是指存储了元素的一个容器对象,且容器中的元素可以通过__iter__( )方法或__getitem__( )方法访问。

  1. __iter__方法的作用是让对象可以用for … in obj循环遍历,__getitem__( )方法是让对象可以通过实例名[index]的方式访问实例中的元素。这两个方法的目的是Python实现一个通用的外部可以访问可迭代对象内部数据的接口。

  2. 一个可迭代对象是不能独立进行迭代的,Python中,迭代是通过for … in obj来完成的。凡是可迭代对象都可以直接用for… in obj循环访问,这个语句其实做了两件事:第一件事是调用__iter__()获得一个可迭代器,第二件事是循环调用__next__()

  3. 常见的可迭代对象包括:
    a) 集合数据类型,如list、tuple、dict、set、str等;
    b) 生成器(generator),包括生成器和带yield的生成器函数(generator function)

  4. 如何判断一个对象是可迭代对象呢?具体判断方法如下两种:

    • 利用numpyiterable方法

      from numpy import iterable
      print(iterable(实例名))
      
    • 利用collections模块的Iterable

      from collections import Iterable
      isinstance(实例名, Iterable)
      

一个典型的实例

  • 随便定义一个对象,不定义__iter__方法:

    from numpy import iterable
    
    class MyList:
        def __init__(self, len: int):
            self.list = [i for i in range(len)]
            self.length = len
    
        def __repr__(self) -> str:
            return f"MyList({self.length}):{self.list}"
    
    
    x = MyList(10)
    for i in x:
        print(i)
    

    运行结果:

    显示MyList实例是不可迭代的

    • 定义__iter__方法后
      • 下面的例子简单实现一个range(n)
    from numpy import iterable
    
    class MyList:
        def __init__(self, len: int):
            self.cursor = -1
            self.length = len
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.cursor+1 < self.length:
                self.cursor += 1
                return self.cursor
            else:
                exit(1)
    
        def __repr__(self) -> str:
            return f"MyList({self.length})"
    
    
    x = MyList(10)
    print(iterable(x))
    for i in x:
        print(i)
    

    输出为:

    True
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    

    使用next()一步一步迭代可以看的更清楚:

    from numpy import iterable
    
    
    class MyList:
        def __init__(self, len: int):
            self.cursor = -1
            self.length = len
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.cursor+1 < self.length:
                self.cursor += 1
                return self.cursor
            else:
                exit(1)
    
        def __repr__(self) -> str:
            return f"MyList({self.length})"
    
    
    x = MyList(10)
    print(iter(x))
    print(next(x))
    print(next(x))
    print(next(x))
    print(next(x))
    for i in x:
        print(i)
    

    输出结果为:

    MyList(10)
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9