如何使用生成器减少内存使用并加速Python代码

大家好 今天,我们要分享一种有用的翻译,该翻译是在“ Python的Web开发人员”课程启动之前准备的。 在创建Web应用程序,机器学习模型或测试时,用Python编写节省时间和内存的代码尤为重要。



当我开始用Python学习生成器时,我不知道它们有多重要。 但是,他们在机器学习的整个过程中不断地帮助我编写功能。


生成器函数使您可以声明一个行为类似于迭代器的函数。 它们允许程序员创建快速,简单和干净的迭代器。 迭代器是可以重复(循环)的对象。 它用于抽象数据容器并使它的行为类似于可迭代的对象。 例如,可迭代对象的示例可以是字符串,列表和字典。


生成器看起来像一个函数,但是使用yield关键字而不是return。 让我们看一个例子,使其更清楚。


def generate_numbers(): n = 0 while n < 3: yield n n += 1 

这是一个生成器功能。 调用它时,它将返回一个生成器对象。


 >>> numbers = generate_numbers() >>> type(numbers) <class 'generator'> 

重要的是要注意状态如何封装在生成器函数的主体中。 您可以使用内置的next()函数一次迭代一个:


 >>> next_number = generate_numbers() >>> next(next_number) 0 >>> next(next_number) 1 >>> next(next_number) 2 

如果执行结束后调用next()会发生什么?


StopIteration是内置的异常类型,一旦生成器停止返回结果,该异常就会自动发生。 这是for循环的停止信号。


收益声明


它的主要任务是控制生成器函数的流程,使其看起来像一个return语句。 当调用生成器函数或使用生成器表达式时,它将返回一个称为生成器的特殊迭代器。 要使用生成器,请将其分配给某个变量。 在生成器中调用诸如next()之类的特殊方法时,将执行功能代码,直到yield为止。


当它进入yield语句时,程序将暂停该函数,并将该值返回给启动执行的对象。 (而return会完全停止执行该函数。)当函数挂起时,其状态将保留。


既然我们熟悉了Python中的生成器,就可以将常用方法与使用生成器的方法进行比较,以节省在代码执行上花费的内存和时间。


问题陈述


假设我们需要遍历大量数字(例如,1,000,000,000),然后将需要单独存储的所有数字的平方保存在另一个列表中。


通常的方法


 import memory_profiler import time def check_even(numbers): even = [] for num in numbers: if num % 2 == 0: even.append(num*num) return even if __name__ == '__main__': m1 = memory_profiler.memory_usage() t1 = time.clock() cubes = check_even(range(100000000)) t2 = time.clock() m2 = memory_profiler.memory_usage() time_diff = t2 - t1 mem_diff = m2[0] - m1[0] print(f"It took {time_diff} Secs and {mem_diff} Mb to execute this method") 

运行上面的代码后,我们得到以下内容:


 It took 21.876470000000005 Secs and 1929.703125 Mb to execute this method 

使用发电机


 import memory_profiler import time def check_even(numbers): for num in numbers: if num % 2 == 0: yield num * num if __name__ == '__main__': m1 = memory_profiler.memory_usage() t1 = time.clock() cubes = check_even(range(100000000)) t2 = time.clock() m2 = memory_profiler.memory_usage() time_diff = t2 - t1 mem_diff = m2[0] - m1[0] print(f"It took {time_diff} Secs and {mem_diff} Mb to execute this method") 

运行上面的代码后,我们得到以下内容:


 It took 2.9999999995311555e-05 Secs and 0.02656277 Mb to execute this method 

如我们所见,运行时和使用的内存大大减少了。 生成器以称为“惰性计算”的原理进行操作。 这意味着它们可以节省处理器,内存和其他计算资源。


结论


我希望本文能够说明如何使用Python中的生成器来节省诸如内存和时间之类的资源。 之所以出现这种优势,是因为生成器没有将所有结果存储在内存中,而是即时计算它们,并且仅当我们请求计算结果时才使用内存。 生成器还允许您抽象大量的样板代码,这是编写迭代器所必需的,因此它们还有助于减少代码量。

Source: https://habr.com/ru/post/zh-CN477926/


All Articles