美文网首页
Effective Python(16): 用生成器来改写直接返

Effective Python(16): 用生成器来改写直接返

作者: warmsirius | 来源:发表于2019-10-24 21:43 被阅读0次

    前言

    如果函数要产生一系列结果,那么最简单的做法就是把这些结果都放在一份列表里,并将其返回给调用者。

    1. 举例

    例如,我们要查出字符串中每个词的首字母,在整个字符串里的位置。

    下面这段代码,用append方法将这些词的首字母添加到result列表中,并在函数结束时将其返回给调用者。

    def index_word(text):
        result = []
        if text:
            result.append(0)
        for index, letter in enumerate(text):
            if letter == " ":
                result.append(index + 1)
        return result
    

    一、返回列表的缺点及改进

    列表的缺点
    1. 代码写的比较拥挤

    每次找到新的结果,都要调用append方法。另外,每次append都需要index+1,且函数首尾还各有1行代码用来创建及返回result列表。

    生成器

    • 生成器是使用yield表达式的函数。调用生成器函数时,它并不会真正的运行,而是会返回迭代器。
    • 每次在这个迭代器上面调用内置的next函数时,迭代器会把生成器推进到下一个yield表达式那里。
    • 生成器传给yield的每一个值,都会由迭代器返回给调用者。

    改进:

    def index_words_iter(text):
        if text:
            yield 0
        for index, letter in enumerate(text):
            if letter == " ":
                yield index + 1
    

    调用该生成器后所返回的迭代器,可以传给内置的list函数,以将其转化为列表。

    result = list(index_words_iter(text))
    

    2. 返回前将所有结果都放在列表里面,如过输入量非常大,那么程序可能崩溃

    下面定义的这个城生气,会从文件里面依次读入各行内容,然后逐个处理每行中的单词,并产生相应结果。

    该函数执行时所耗的内存,由单行输入值的最大字符数来界定。

    def index_file(handle):
        offset = 0
        for line in handle:
            if line:
                yield offset
            for letter in line:
                offset += 1
                if letter == ' ':
                    yield offset
    

    运行这个生成器函数,也能产生和原来相同的效果。

    from itertools import islice
    
    with open("/tmp/address.txt", "r") as f:
        it = index_file(f)
        results = islice(it, 0, 3)
        print(list(results))
    

    注意

    定义生成器的时候注意:函数返回的迭代器是有状态的,调用者不应该反复使用它

    相关文章

      网友评论

          本文标题:Effective Python(16): 用生成器来改写直接返

          本文链接:https://www.haomeiwen.com/subject/sqxhvctx.html