技能分享:​如何使用生成器减少内存占用,并让Python代码运行更快?


全文共2424字,预计学习时长7分钟

图源:Unsplash

如何使用生成器减少内存占用并让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是一个内置的异常类型,一旦生成器停止执行yield语句,它将自动触发。这是for循环停止的信号。

图源:Unsplash

Yield语句

 

它的主要工作是以类似于return语句的方式控制生成器函数的流程。

 

当调用一个生成器函数或者使用生成器表达式时,会返回一个称为生成器的特殊迭代器。可以通过将此生成器分配给变量来使用它。当调用生成器上的特殊方法,例如next(),函数中的代码会执行到yield语句。

 

当执行到达了Python代码中的yield语句,程序就会中止函数的执行,并将产生的值返回给调用方。(相反,return会完全停止函数执行。)当一个函数被挂起时,它的状态会被保存。

 

在熟悉了Python的生成器之后,让我们从内存使用和代码执行花费的时间两方面来比较普通方法与使用生成器的方法。

 

问题陈述

 

假设我们必须遍历一大串数字(例如100000000),并将所有偶数的平方存储在单独的列表中。

 

普通方法

 

importmemory_profiler
import time
def check_even(numbers):
    even = []
    for num in numbers:
        if num % 2 == 0:
            even.append(num*num)
           
    return evenif __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} Secsand {mem_diff} Mb to execute this method")

运行后,上述代码的输出如下:

 

It took21.876470000000005 Secs and 1929.703125 Mb to execute this method

使用生成器

 

importmemory_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} Secsand {mem_diff} Mb to execute this method")

运行后,上述代码的输出如下:

 

It took2.9999999995311555e-05 Secs and 0.02656277 Mb to execute this method

 

肉眼可见,执行时间和内存使用量都大大减少了。

 

生成器仅按需工作,也就是众所周知的通过惰性评估工作。这意味着它们可以节省CPU,内存和其他计算资源。

图源:Unsplash

今天,我们学习了如何使用python的生成器来减少内存使用并使代码执行更快。

 

这种方式的优点在于,生成器不会将所有结果都存储在内存中,而是即时生成它们,因此仅在我们请求结果时它才会使用内存。生成器还可以抽象出编写迭代器所需的许多样板代码,因此也有助于减少代码量。

 

快来试试吧,一定会取得让你惊喜不已的结果。

推荐阅读专题

留言 点赞 发个朋友圈

我们一起分享AI学习与发展的干货

编译组:林柯秀、王书晗

相关链接:

https://towardsdatascience.com/reduce-memory-usage-and-make-your-python-code-faster-using-generators-bd79dbfeb4c

如需转载,请后台留言,遵守转载规范

推荐文章阅读

ACL2018论文集50篇解读

EMNLP2017论文集28篇论文解读

2018年AI三大顶会中国学术成果全链接

ACL2017 论文集:34篇解读干货全在这里

10篇AAAI2017经典论文回顾

长按识别二维码可添加关注

读芯君爱你

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值