Python中的迭代器详解

 更新时间:2023年08月23日 09:15:44   作者:郝同学的测开笔记  
这篇文章主要介绍迭代器,看完文章你可以了解到什么是可迭代对象、啥是迭代器、如何自定义迭代器、使用迭代器的优势,文中有详细的代码示例,需要的朋友可以参考下

迭代器

迭代(iterate)意味着重复多次,就像循环那样。工作中我们一定使用for循环迭代过列表和字典,但实际上也可迭代其他对象:实现了方法__iter__的对象。方法__iter__返回一个迭代器,它是包含方法__next__的对象,而调用这个方法时可不提供任何参数。当你调用方法__next__时,迭代器应返回其下一个值。如果迭代器没有可供返回的值,应引发StopIteration异常。你还可使用内置的便利函数next。

__iter__

用于定义一个可迭代对象(iterable)。通过实现 __iter__ 方法,我们可以使自定义的对象能够被 for 循环等迭代器相关的操作使用。

python中哪些是可迭代对象呢?我们可以测试一下

def is_iterable(param):
    try:
        iter(param)
        return True
    except TypeError:
        return False
​
​
params = [
    1234,
    '1234',
    [1, 2, 3, 4],
    set([1, 2, 3, 4]),
    {1: 1, 2: 2, 3: 3, 4: 4},
    (1, 2, 3, 4)
]
​
for param in params:
    print(f'{param} is iterable? {is_iterable(param)}')
'''
1234 is iterable? False
1234 is iterable? True
[1, 2, 3, 4] is iterable? True
{1, 2, 3, 4} is iterable? True
{1: 1, 2: 2, 3: 3, 4: 4} is iterable? True
(1, 2, 3, 4) is iterable? True
'''

可以看到列表、元组、字典、集合、字符串都是可迭代对象,查看源码,发现他们都实现了__iter__方法

def __iter__(self, *args, **kwargs): # real signature unknown
    """ Implement iter(self). """
    pass
​

方法__iter__返回一个迭代器,它是包含方法__next__的对象,而调用这个方法时可不提供任何参数。当你调用方法__next__时,迭代器应返回其下一个值。

实践

示例一

迭代器实现斐波那契数列

class Fibs:
    def __init__(self):
        self.a = 0
        self.b = 1
​
    def __iter__(self):
        return FibIterator(self.a, self.b)
​
​
class FibIterator:
​
    def __init__(self, a, b):
        self.a = a
        self.b = b
​
    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        return self.a
​
    def __iter__(self):
        return self
​
​
fibs = Fibs()
for f in fibs:
    print(f)
    if f > 10:
        break
'''
1
1
2
3
5
8
13
'''

这段代码,Fibs 类是一个可迭代对象,并且在 __iter__ 方法中返回一个迭代器对象 FibIterator(self.a, self.b)

FibIterator 类是一个迭代器对象,它包含 __next____iter__ 方法。

FibIterator__init__ 方法中,初始化了两个变量 self.aself.b 分别表示斐波那契数列中的前两个元素。

__next__ 方法会根据迭代逻辑计算出下一个斐波那契数,并将 self.aself.b 更新为下一次迭代所需的值。然后,它返回当前的斐波那契数。

__iter__ 方法在这个示例中实现了迭代器对象的自引用,即返回自身,使得迭代器对象本身也可以被迭代。

当你使用 for 循环迭代 fibs 对象时,它会调用 fibs 对象的 __iter__ 方法获取迭代器对象,然后重复调用迭代器对象的 __next__ 方法来获取斐波那契数列中的下一个数。

示例二

使用自定义的迭代器类来生成一个递增序列

class IncrementIterator:
    def __init__(self, start, step):
        self.current = start
        self.step = step
​
    def __iter__(self):
        return self
​
    def __next__(self):
        value = self.current
        self.current += self.step
        return value
​

在这个例子中,IncrementIterator 类表示一个递增序列的迭代器。它接受两个参数 startstep,分别表示初始值和递增步长。

__init__ 方法初始化了两个实例变量 self.currentself.step,分别用于存储当前值和递增步长。

__iter__ 方法返回迭代器对象本身,即 self。这样可以使迭代器对象本身也是可迭代的。

__next__ 方法计算并返回当前值,并将 self.current 增加 self.step,以准备下一次迭代。

以下是如何使用 IncrementIterator 迭代器生成递增序列的示例代码:

iterator = IncrementIterator(0, 2)
for num in iterator:
    print(num)
    if num >= 10:
        break

这段代码会生成一个从 0 开始,每次递增 2 的递增序列。在 for 循环中,迭代器对象 iterator 会自动调用 __iter__ 方法获取迭代器本身,并重复调用 __next__ 方法来获取下一个递增值。

迭代器创建序列

对迭代器和可迭代对象进行迭代之外,还可将它们转换为序列。比如下面这个例子

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]

这段代码使用list显式地将迭代器转换为列表。

iter函数

可迭代对象调用 iter() 函数,可以得到一个迭代器。迭代器可以通过 next() 函数来得到下一个元素,从而支持遍历。

l = [1,2,3,4]
it = iter(l)
print(next(it)) # 1
print(type(it)) # <class 'list_iterator'>

使用迭代器的意义

有人说为啥要用迭代器,我用列表也可以呀,为啥不用列表呢?因为在很多情况下,你可能只想逐个地获取值,而不是使用列表一次性获取。这是因为如果有很多值,列表可能占用太多的内存。使用迭代器相对于直接使用列表的优势在于节省内存和提高性能。下面是一个例子来说明这一点:

我们需要生成一个非常大的数列,比如一个包含 1 到 1000000 的连续整数序列。如果我们使用列表来存储这个数列,就需要将所有的数都存储在内存中,这会消耗大量的内存空间。

my_list = list(range(1, 1000001))

然而,如果我们使用迭代器来生成这个数列,只需要在需要使用时逐个生成数字,而不需要一次性存储全部数字。这节省了大量的内存空间。

class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
​
    def __iter__(self):
        return self
​
    def __next__(self):
        if self.current > self.end:
            raise StopIteration
        else:
            value = self.current
            self.current += 1
            return value
​
my_iterator = MyIterator(1, 1000000)
​
for num in my_iterator:
    print(num)

过使用迭代器,我们避免了一次性将所有数字存储在内存中的需求,减少了内存的占用。相比之下,使用列表则需要先生成并存储所有数字,会占用大量的内存。

此外,迭代器还具有惰性求值的特点,即只在需要时才生成下一个元素。这种特性在处理大量数据时非常有用,可以减少不必要的计算和处理时间。

因此,使用迭代器可以节省内存,并在处理大量数据时提高性能。它们可以逐个生成序列中的元素,而无需一次性将所有元素存储在内存中。

最后

通过上述例子,可以知道实现了方法__iter__的对象是可迭代的,而实现了方法__next__的对象是迭代器。

以上就是Python中的迭代器详解的详细内容,更多关于Python迭代器的资料请关注脚本之家其它相关文章!

相关文章

  • Pytorch基础之torch.randperm的使用

    Pytorch基础之torch.randperm的使用

    这篇文章主要介绍了Pytorch基础之torch.randperm的使用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • python中的插入排序的简单用法

    python中的插入排序的简单用法

    在本篇内容里小编给各位分享的是一篇关于python中的插入排序的简单用法,有兴趣的朋友们可以参考学习下。
    2021-01-01
  • Python详细对比讲解break和continue区别

    Python详细对比讲解break和continue区别

    这篇文章主要介绍了python循环控制语句 break 与 continue,break就像是终止按键,不管执行到哪一步,只要遇到break,不管什么后续步骤,直接跳出当前循环
    2022-06-06
  • pytorch中的广播语义

    pytorch中的广播语义

    这篇文章主要介绍了pytorch中的广播语义,pytorch的广播语义即broadcasting semantics,和numpy的很像,下面文章介绍更多相关内容的介绍,需要的小伙伴可以参考一下
    2022-03-03
  • python实现将中文日期转换为数字日期

    python实现将中文日期转换为数字日期

    这篇文章主要介绍了python实现将中文日期转换为数字日期,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • python多线程http压力测试脚本

    python多线程http压力测试脚本

    这篇文章主要为大家详细介绍了python多线程http压力测试脚本,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-06-06
  • python 中 __init__的意义以及作用

    python 中 __init__的意义以及作用

    python中的__init__是一个私有函数(方法),访问私有函数中的变量在python中用self,在PHP中用$this,这篇文章主要介绍了python 中 __init__的意义以及作用,需要的朋友可以参考下
    2023-02-02
  • Flask如何获取用户的ip,查询用户的登录次数,并且封ip

    Flask如何获取用户的ip,查询用户的登录次数,并且封ip

    这篇文章主要介绍了Flask如何获取用户的ip,查询用户的登录次数,并且封ip问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • Django 解决distinct无法去除重复数据的问题

    Django 解决distinct无法去除重复数据的问题

    这篇文章主要介绍了Django 解决distinct无法去除重复数据的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-05-05
  • python 对象和json互相转换方法

    python 对象和json互相转换方法

    下面小编就为大家分享一篇python 对象和json互相转换方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-03-03

最新评论