1

我试图在我的生成器的以下两个定义之间做出决定。哪个更好?哪个“更pythonic”?有没有办法减轻每个人的缺点?

def myGenerator1(howMany):
    result = [0,0,0]
    yield result
    for i in range(howMany)
        modifyListInPlace(result)
        yield result

for val in myGenerator1(1000):
    useValThenForgetIt(val)

def myGenerator2(howMany):
    result = (0,0,0)
    yield result
    for i in range(howMany)
        result = createNewUpdatedTuple(result)
        yield result

for val in myGenerator2(1000):
    useValThenForgetIt(val)

第一个修改了生成器返回的值,可能会弄乱我还没有预见到的调用代码。在这种情况下,第二个会产生 1000 个元组的垃圾,或者如果我增加“howMany”(我可能会)会产生更多。

我作为示例给出的循环只是我当前对生成器的使用。我认为我永远不会保存从中产生的值,但它是一种实用程序,可能在其他地方有用。

4

2 回答 2

3

以标准库为指导,尽管底层算法是就地变异算法,但itertools模块中的组合函数都返回元组。例如,查看itertools.permutations的代码。

这种设计(返回元组而不是列表)已被证明是健壮的。我担心变异列表方法会产生一些难以发现的错误,具体取决于调用者对迭代器的返回值所做的事情。

另一种想法。对于未使用的结果,我不会太担心“创建数以千计的垃圾元组”。Python 的元组实现非常擅长重用以前处理的元组(通过使用一个空闲列表数组,它可以从以前使用的元组创建一个新元组,而无需调用内存分配器)。因此,元组版本与列表版本一样具有性能甚至更好。

于 2011-11-16T06:07:31.030 回答
1

第一个可以返回一个对象,然后在它被返回后不明显地修改它的事实对我来说是一个巨大的代码味道,无论你使用什么语言(即这不是“pythonic”的问题)。另外,为什么你想要一个函数一次又一次地为相同的值产生一个迭代器,在产量之间进行修改?对我来说似乎很不直观。

如果您使用这些值,那么由创建的元组myGenerator2不是垃圾。如果您一次使用它们,它们将永远不会同时存在,并且您的程序几乎肯定会进行许多其他内存分配/释放。与返回的列表不同range(howMany)它将创建 1,000 个您从未实际使用过的整数(除非您使用的是 Python3,在这种情况下range返回的是生成器而不是列表)。

如果有任何机会调用者可能希望保留对生成器返回的某些内容的引用(并且 Python 程序员通常希望,当给定生成器时,items = list(generator)如果他们需要多次使用它们,则能够继续使用它们) ,那么第二个要好得多。

于 2011-11-16T05:53:24.270 回答