小说python何时使用生成器

生成器、迭代器作为python的两个高级特性,相信大家肯定耳熟能详,都能说道上一阵,但很多时候都是说说而已,知道有这么个东西,而且是好东西,但再看看写过的代码,有多少确实使用它的?

一个语音特性,在潜意识中没用被激活,更多时候还是因为不知道它的应用场景,这里就从三个方面说说生成器什么时候应该用,而且必须用。

是否需要返回列表中的所有元素?

不需要

当做出不需要的回答时,就应该选择生成器,而不是列表,因为生成器的主要特性就是'lazy evaluation'

生成器,只有在真正需要时才生成结果,因此在不需要列表中的所有元素,自然是没必要去创建它们的,创建后还不用,那就是浪费资源,而且影响效率

例如,我们碰到如下场景,公司年会搞一个抽奖活动,规则是每人拿一个号,抽奖时根据这些号码摇号,摇出的号和你对应的号一致,那就表示中奖。

下面给出一个简单实现:

import time
import random

def gen_winning_numbers():
    random.seed()
    elements = []
    for i in range (0,10):
        time.sleep(1) # 模拟很牛逼的摇号算法但有些费时
        elements.append(random.randint(1,10))

    return elements

random.seed()
my_number = random.randint(1,10)
print ("my number is " + str(my_number))

for winning_number in gen_winning_numbers():
    print(winning_number)
    if my_number == winning_number:
        print ("you win!")
        break

gen_winning_numbers函数是一个比较耗时的函数,随机产生10个中奖号码,如果my_number在这10个数中,表示中奖且程序退出,从这个实现中可以看到,不管如何至少需要等10s,才知道中奖结果。

而往往只要有一个中奖号码和my_number一致,就表示中奖,就无需关心其他中奖号码,也没必要生成其他剩余的号码,最优情况下,只需要1s就得到中奖结果了

使用生成器就很容易解决这个问题

import time
import random

def gen_winning_numbers():
    random.seed()
    for i in range(0,10):
        time.sleep(1)  # 模拟很牛逼的摇号算法但有些耗时
        yield random.randint(1,10)

random.seed()
my_number = random.randint(1,10)
print ("my number is " + str(my_number))

for winning_number in gen_winning_numbers():
    print(winning_number)
    if my_number == winning_number:
        print ("you win!")
        break

函数是否需要大内存?

需要

当做出需要的回答时,就应该选择生成器,因为生成器在需要时创建,获取到结果时才开始处理,完成后在请求其他项目前可从内存中删除,释放内存

先看看下面这段代码

def get_elements():
    elements = []
    for i in range (0,10000):
        elements.append("x"*10240)
    # 返回1W个每个元素10KB的大列表
    return elements

characters_count = 0

my_elements=get_elements()

for i in my_elements:
    characters_count = characters_count + len(i)

print(characters_count)

这段代码每次执行时至少需要占用超过100M的内存,而如果使用生成器,可是另外一番景象

def get_elements():
    for i in range (0,10000):
        yield("x"*10240)

characters_count = 0

my_elements=get_elements()

for i in my_elements:
    characters_count = characters_count + len(i)

print(characters_count)

得到同样的结果,但只需要10KB的内存

列表生成过程中是否需要通知?

需要

当做出需要的回答时,就应该选择生成器

在一个复杂或是耗时相对较长的列表生成过程中,用户如果不知道当前的元素过程,一味的盲目等待,那应该是很烦人的、无法接受的。

例如,下面这个过程

import time

def elements():
    elements = []
    for i in range (0,4):
        # 模拟耗时操作
        time.sleep(5)
        elements.append(i)
    return elements

print("start")
print(elements())
print("end")

每次需要得到5个结果,必须得等待20s,更糟糕的是,在等待的过程中什么都做不了,也不知内部具体情况,哪怕给个进度提示也好

import time

def elements():
    elements = []
    for i in range (0,4):
        # 模拟耗时操作
        time.sleep(5)
        yield(i)

print("start")
for i in elements():
    # 输出一个简易进度
    print(".", end="", flush=True)
print()
print("end")

由上可知:

如果创建一个元素的函数很耗时,如果该函数对内存占用敏感,或是不需要列表中的所有元素,那么最佳选择是生成器,那其他情况下,都可以使用列表,对吧?

当然没问题,但是如果选择生成器是否更好呢,既拥有了上述优势,也不乏列表的熟悉味道,因为生成器转换成列表很简单

1. list方法

mylist = list(my_generator())

2. 列表生成式

mylist = [elem for elem in my_generator()]

原文发布于微信公众号 - chafezhou(gh_5b8f0c59b682)

原文发表时间:2018-08-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据科学与人工智能

【Python环境】如何使用正确的姿势进行高效Python函数式编程?

关于函数式编程 有哪些函数式语言? 其实函数是语言很早就出现了,上世纪30年代出现的Lambda和50年代的LISP,比面向过程和对象的语言出现的更早,现代的C...

232100
来自专栏牛客网

金山WPS,C++研发工程师,一面

【每日一语】人们常常会欺骗你,是为了让你明白,有时候,你唯一应该相信的人就是你自己。——《千与千寻》

9720
来自专栏Java架构师进阶

编写高质量代码的思考

最近在看《代码大全》,可以说是一本软件开发的百科全书,特别厚,但是干货也很多。平时写代码,代码规范是一个最低的要求(很多老代码连最低要求都达不到),为什么要这样...

11120
来自专栏惨绿少年

Python入门篇

43940
来自专栏一个会写诗的程序员的博客

Java新手极简指北手册

为什么我先拿“数据结构和算法”说事捏?这玩意是写程序最最基本的东东。不管你使用 Java 还是其它的什么语言,都离不开它。而且这玩意是跨语言的,学好之后不管在哪...

14410
来自专栏申龙斌的程序人生

零基础学编程002:Hello World

昨天介绍了codecademy在线学编程的网站,不知道大家动手试验了没有?是不是太简单,一下子就完成了许多练习? 第一课的内容只有一条输出语句,点击保存并提交...

29570
来自专栏技术专栏

慕课网Flask高级编程实战-5.书籍详情页面的构建

大多时候,我们从数据库,或者外部网络获取到的原始数据,并不能满足复杂的业务需求。业务的直观体现就是页面。

16830
来自专栏社区的朋友们

ServerFrame::HashMap VS stl::unordered_map-性能探究之旅

突然就对项目中的 HashMap 有了强烈的好奇心,这个 HashMap 的实现够高效吗,和 std::unordered_map 的效率比较性能如何? 他们的...

50200
来自专栏技术专栏

慕课网Flask高级编程实战-6.书籍详情页面的构建

大多时候,我们从数据库,或者外部网络获取到的原始数据,并不能满足复杂的业务需求。业务的直观体现就是页面。

23510
来自专栏生信技能树

【生信菜鸟经】如何系统入门Perl

Perl是典型的脚本语言,短小精悍,非常容易上手,尤其适合处理文本,数据,以及系统管理。它在老一辈的生物信息学分析人员中非常流行,出于历史遗留原因大家肯定会或多...

44290

扫码关注云+社区

领取腾讯云代金券