Python生成器 - 不应使用的场景

9 投票
3 回答
1708 浏览
提问于 2025-04-15 12:05

我最近在研究Python的生成器,觉得它们真不错。不过,有没有什么地方不适合用生成器呢?我想到以前用C语言编程时,读取文件或者用户操作的场景。比如说,生成器能不能用来提示用户输入(比如基本的数据录入)呢?然后调用的函数再处理这些输入?在使用生成器时,有没有什么性能或者清理方面需要注意的问题呢?

3 个回答

1

当你想要让某个东西可以逐个取出来,但又不想把整个列表都放在内存里时,就可以使用生成器。这就是为什么在Python 2.x及更早版本中,xrange可以处理比range更长的序列。

如果你需要把整个“要生成的东西的列表”都加载到内存里,那使用生成器就没什么意义了——你直接返回一个列表就好了。

举个(稍微有点牵强的)例子:

def my_pointless_generator(x):
    thedata = range(x) # or thedata = list(range(x)) in Python 3.x
    for x in thedata:
        yield x

..可以同样高效地改写成..

def my_pointless_generator(x):
    return range(x)
13

生成器不太适合保存。

通常情况下,你尝试保存一个生成器对象时会遇到错误。

>>> def generatorForEvenKeys( aDictionary ):
    for k in aDictionary:
        if k % 2 == 0: yield aDictionary[k]

>>> x = generatorForEvenKeys( someDictionary )
>>> pickle.dump(x,file('temp.dat','wb'))

这会给你带来以下错误:

TypeError: can't pickle generator objects
12

生成器有一个问题,就是它们会被“消耗掉”。这意味着如果你想再次遍历这个序列,你就得重新创建这个生成器。

如果你担心懒惰求值的问题,那么你可能不想使用生成器表达式。比如说,如果你想提前完成所有计算(例如,为了释放某个资源),那么使用列表推导式或者for循环可能更合适。

如果你使用psyco,你会发现列表表达式和for循环的速度会显著提高,但生成器的速度就不会有太大变化。

还有一点很明显,如果你需要提前知道序列的长度,那么你也不应该使用生成器。

撰写回答