当前位置: 首页 > 科技观察

迭代器设计模式可以帮助你大幅提升Python性能

时间:2023-03-19 15:54:34 科技观察

今天给大家介绍的设计模式很简单,叫做iterator,也就是迭代器模式。迭代器是Python语言中非常重要的一部分。借助迭代器,我们可以轻松实现很多复杂的功能。在深度学习中,数据的获取往往是通过迭代器来实现的。所以这部分的内容非常重要,建议大家一定要掌握。简单案例在开始介绍设计模式之前,我们先来看一个简单的需求。假设现在我们需要根据传入的变量获取每周的第几天,比如传入3,返回[Mon,Tue,Wed],传入5,返回[周一、周二、周三、周四、周五]。这个需求大家应该都能看懂,非常非常的简单。如果用一个函数实现,它会像这样:defreturn_days(n):week=['Mon','Tue','Wed','Thu','Fri','Sat','Sun']returnweek[:n]你可以在三行代码中实现它。当然,在这种问题场景下这样写是没有问题的。但是如果我们稍微改变一下标题,这里的星期就不是一个固定的数据了,而是从上游或者某个文件中读取的。这里的n也是一个非常大的数,我们把这个函数重写如下:defget_data(n):data=[]foriinrange(n):data.append(get_from_upstream())returndata我们假设函数中实现了get_from_upstream具体数据的逻辑,那么上面的函数有什么问题呢?有同学会说这没问题,因为其他语言实现数据获取都是这样的。确实,Java等语言可能会做到这一点。但是其他语言这样做是对的,不代表Python这样做是对的。因为我们还没有把Python的能力发挥到极致。这里有两个问题。第一个问题是延迟,因为前面说过,n是一个非常大的数。我们从上游获取数据,无论是通过网络还是文件读取,本质上都是一个IO操作,而IO操作的延迟是非常大的。那么我们可能需要很长时间才能将这n条数据全部收集起来,导致下游长时间等待。第二个问题是内存,因为我们存储这n条数据,一起返回。如果n很大,对内存的开销压力也很大。如果机器内存不够,可能会导致死机。如何解决?其实解决方法很简单。如果你熟悉迭代器,你会发现迭代器就是针对这两个问题的。我们可以将上面的逻辑改写成迭代器实现,这就是迭代器模式。严格来说,迭代器模式只是迭代器的一种应用。它把迭代器和匿名函数结合的很巧妙,说起来也不多。我们把刚才的代码改写一下,具体在代码里。defget_data(n):foriinrange(n):yieldget_from_upstream()data_10=lambda:get_data(10)data_100=lambda:get_data(100)#usefordindata_10:print(d)非常简单,但也许你要问,因为我们写get_data迭代器已经出来了,所以当我们使用它时,仅仅fordinget_data(10)是不够的。为什么要用匿名函数在中间包一层呢?道理也很简单,如果这个数据是我们自己用的,那中间当然不用再包一层了。但是如果我们传递给下游使用,对于下游来说,它肯定不想考虑上游太多的细节,越简单越好。所以我们直接丢一个封装好的iterator过去,下游直接调用即可。否则下游需要感知get_data函数传入的参数,这显然是不合理的。