前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >小说python何时使用生成器

小说python何时使用生成器

作者头像
用户2196567
发布2018-09-20 17:33:30
5350
发布2018-09-20 17:33:30
举报
文章被收录于专栏:chafezhouchafezhou

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

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

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

不需要

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

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

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

下面给出一个简单实现:

代码语言:javascript
复制
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就得到中奖结果了

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

代码语言:javascript
复制
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

函数是否需要大内存?

需要

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

先看看下面这段代码

代码语言:javascript
复制
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的内存,而如果使用生成器,可是另外一番景象

代码语言:javascript
复制
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的内存

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

需要

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

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

例如,下面这个过程

代码语言:javascript
复制
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,更糟糕的是,在等待的过程中什么都做不了,也不知内部具体情况,哪怕给个进度提示也好

代码语言:javascript
复制
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方法

代码语言:javascript
复制
mylist = list(my_generator())

2. 列表生成式

代码语言:javascript
复制
mylist = [elem for elem in my_generator()]
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-08-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 chafezhou 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档