迭代器和生成器在实际应用中的案例-Python (迭代器和生成器python)
迭代器
迭代器是特殊对象,可以让你逐个访问数据序列中的元素,而无需将整个序列加载到内存中。Python中的大多数数据结构都是可迭代对象,例如列表、元组、字符串等。
迭代器必须实现以下两个方法:
-
__iter__()
:返回迭代器本身,用于初始化迭代。 -
__next__()
:返回序列中的下一个元素,当到达序列末尾时引发StopIteration异常。
你可以创建自己的自定义迭代器,如下所示:
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:
self.current += 1
return self.current - 1
else:
raise StopIteration
你可以使用自定义迭代器如下所示:
my_iterator = MyIterator(0, 3)
for item in my_iterator:
print(item) 输出 0, 1, 2
迭代器与for循环
Python中的for循环用于迭代可迭代对象中的元素。当我们使用for循环时,会自动调用可迭代对象的__iter__()方法,并使用__next__()方法来遍历元素,直到引发StopIteration异常。
例如:
numbers = [1, 2, 3, 4, 5]
for num in numbers:
print(num) 输出 1, 2, 3, 4, 5
生成器
生成器是特殊类型的迭代器,允许你按需生成值,而不是一次性生成所有值。这种按需生成的方式非常有用,尤其是在处理大量数据时,以减少内存占用和提高性能。
生成器函数
生成器函数是包含yield语句的函数,而不是return。当函数包含yield语句时,它变成了一个生成器函数。每次调用生成器的__next__()方法时,函数会从上次yield的位置继续执行,直到遇到下一个yield或函数结束。
例如:
def countdown(n):
while n > 0:
yield n
n -= 1
使用生成器函数
for i in countdown(5):
print(i) 输出 5, 4, 3, 2, 1
生成器表达式
生成器表达式类似于列表推导式,但它返回一个生成器对象,而不是一次性生成所有元素。在处理大量数据时非常有用。
例如:
even_numbers = (x for x in range(10) if x % 2 == 0)
for num in even_numbers:
print(num) 输出 0, 2, 4, 6, 8
生成器的惰性求值
生成器以惰性方式生成数据,只有在需要时才计算和返回数据。这意味着生成器不会一次性生成所有值,从而减少内存占用。
生成器的无限序列
由于生成器的惰性求值,可以创建无限序列,而不必担心内存问题。例如,生成无限的斐波那契数列:
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
生成无限的斐波那契数列
fib = fibonacci()
for _ in range(10):
print(next(fib)) 输出 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
Python中的迭代器和生成器总结
迭代器和生成器是Python中强大的工具,可以用于处理各种数据序列。迭代器允许你逐个访问元素,而生成器允许你按需生成元素,从而减少内存占用并提高性能。这些概念对于编写高效的Python代码非常重要。
Python什么是迭代器
iamlaosong文我们在用...语句循环时,in后面跟随的对象要求是可迭代对象,即可以直接作用于for循环的对象统称为可迭代对象(iterable),如list、tuple、dict、set、str等。 可迭代对象是实现了__iter__()方法的对象,而迭代器(iterator)则是实现了__iter__()和__next__()方法的对象,可以显示地获取下一个元素。 这种可以被next调用并不断返回下一个值的对象称为迭代器。 迭代器一定是可迭代对象,反过来则不一定成立。 用iter()函数可以把list、dict、str等iterable变成iterator,例如:bb=[xforxinrange(10)]cc=iter(bb)()循环变量的值其实可以看着是一次次用next取值的过程,每取一个值,做一次处理。 list等对象用于循环实际上可以看着是用iter()方法产生一个迭代器,然后循环取值。 生成器(generator)就是一个能返回迭代器的函数,其实就是定义一个迭代算法,可以理解为一个特殊的迭代器。 调用这个函数就得到一个迭代器,生成器中的yield相当于一个断点,执行到此返回一个值后暂停,从而实现next取值。
闲话python 45: 浅谈生成器yield
生成器似乎并不是一个经常被开发者讨论的语法,因此也就没有它的大兄弟迭代器那么著名。大家不讨论它并不是说大家都已经对它熟悉到人尽皆知,与之相反,即使是工作多年的开发者可能对生成器的运行过程还是知之甚少。这是什么原因导致的呢?我猜想大概有以下几点原因: (1)运行流程不同寻常,(2)日常开发不需要,(3)常常将生成器与迭代器混淆。 生成器的运行流程可以按照协程来理解,也就是说 返回中间结果,断点继续运行 。这与我们通常对于程序调用的理解稍有差异。这种运行模式是针对什么样的需求呢? 一般而言,生成器是应用于大量磁盘资源的处理。 比如一个很大的文件,每次读取一行,下一次读取需要以上一次读取的位置为基础。下面就通过代码展示具体看看生成器的运行机制、使用方式以及与迭代器的比较。
什么是生成器?直接用文字描述可能太过抽象,倒不如先运行一段代码,分析这段代码的运行流程,然后总结出自己对生成器的理解。
从以上展示可以看出,这段代码定义了一个函数,这个函数除了yield这个关键字之外与一般函数并没有差异,也就是说生成器的魔法都是这个yield关键字引起的。 第一点,函数的返回值是一个生成器对象。 上述代码中,直接调用这个看似普通的函数,然后将返回值打印出来,发现返回值是一个对象,而并不是普通函数的返回值。 第二点,可以使用next对这个生成器对象进行操作 。生成器对象天然的可以被next函数调用,然后返回在yield关键字后面的内容。 第三,再次调用next函数处理生成器对象,发现是从上次yield语句之后继续运行,直到下一个yield语句返回。
生成器的运行流程确实诡异,下面还要展示一个生成器可以执行的更加诡异的操作:运行过程中向函数传参。
返回生成器和next函数操作生成器已经并不奇怪了,但是在函数运行过程中向其传参还是让人惊呆了。 调用生成器的send函数传入参数,在函数内使用yield语句的返回值接收,然后继续运行直到下一个yield语句返回。 以前实现这种运行流程的方式是在函数中加上一个从控制台获取数据的指令,或者提前将参数传入,但是现在不用了,send方式使得传入的参数可以随着读取到的参数变化而变化。
很多的开发者比较容易混淆生成器和迭代器,而迭代器的运行过程更加符合一般的程序调用运行流程,因此从亲进度和使用熟悉度而言,大家对迭代器更有好感。比如下面展示一个对迭代器使用next方法进行操作。
从以上展示来看,大家或许会认为迭代器比生成器简单易用得太多了。不过,如果你了解迭代器的实现机制,可能就不会这么早下结论了。python内置了一些已经实现了的迭代器使用确实方便,但是如果需要自己去写一个迭代器呢?下面这段代码就带大家见识以下迭代器的实现。
在python中,能被next函数操作的对象一定带有__next__函数的实现,而能够被迭代的对象有必须实现__iter__函数。看了这么一段操作,相信大家对迭代器实现的繁琐也是深有体会了,那么生成器的实现是不是会让你觉得更加简单易用呢?不过千万别产生一个误区,即生成器比迭代器简单就多用生成器。 在实际开发中,如果遇到与大量磁盘文件或者数据库操作相关的倒是可以使用生成器。但是在其他的任务中使用生成器难免有炫技,并且使逻辑不清晰而导致可读性下降的嫌疑。 这大概也能解释生成器受冷落的原因。不过作为一个专业的开发者,熟悉语言特性是分内之事。
到此,关于生成器的讨论就结束了。本文的notebook版本文件在github上的cnbluegeek/notebook仓库中共享,欢迎感兴趣的朋友前往下载。
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。