带切片分配的生成器

时间:2015-02-01 17:40:58

标签: python python-3.x generator slice

假设我有一个愚蠢的功能,比如FizzBu​​zz:

>>> def FizzBuzz(i):
...     if i % 15 == 0:
...         return "FB"
...     elif i % 3 == 0:
...         return "F"
...     elif i % 5 == 0:
...         return "B"
...     else:
...         return i 

列表:

>>> li=list(range(1,22))
>>> li
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]

现在,如果我执行将该函数应用于列表的生成器表达式:

>>> ge=(FizzBuzz(x) for x in li)
>>> ge
<generator object <genexpr> at 0x1063ca3a8>

我可以把它变成一个列表(即运行生成器表达式):

>>> list(ge)
[1, 2, 'F', 4, 'B', 'F', 7, 8, 'F', 'B', 11, 'F', 13, 14, 'FB', 16, 17, 'F', 19, 'B', 'F']

现在假设我执行切片分配而不是分配给单独的名称:

>>> li=list(range(1,22))
>>> li[:]=(FizzBuzz(x) for x in li)
>>> li
[1, 2, 'F', 4, 'B', 'F', 7, 8, 'F', 'B', 11, 'F', 13, 14, 'FB', 16, 17, 'F', 19, 'B', 'F']

您可以看到生成器表达式立即执行。

map相同:

>>> map(FizzBuzz, li)
<map object at 0x10640c358>
>>> li[:]=map(FizzBuzz, li)
>>> li
[1, 2, 'F', 4, 'B', 'F', 7, 8, 'F', 'B', 11, 'F', 13, 14, 'FB', 16, 17, 'F', 19, 'B', 'F']

现在假设FizzBuzz不是一个愚蠢的函数,而是一个需要一段时间的函数,而li足够大,你想要进行切片赋值。

有没有办法推迟生成器的执行但仍然分配到位? (我确实知道我可以做ge=(f(x) for x in big_list); big_list[:]=list(ge)这是一种解决方法......)

1 个答案:

答案 0 :(得分:1)

显然,(FizzBuzz(x) for x in li)需要li在开始运行时仍然“完整”,因为它必须遍历它并获得正确的项目。

那么你想在哪里“分配到位” - 你想到的哪个地方?

将其分配给独立于li的变量,您将其视为“变通方法”,当然可以。

但是哪里你想把它放在哪里?!

当你准备好运行它之前,它肯定不会在li的内容上被践踏,因为我们已经确定在生成器开始运行时所述内容必须完整。

您可以使用def绑定这些内容,例如

def doge(savedli=list(li)):
    for x in savedli: yield FizzBuzz(x)

现在,li[:]=doge会擦除li的内容,但是仍然会将它们安全地隐藏在doge(现在设置为li[0])中,以便稍后你可以做li[:] = doge()。但我认为这种更加扭曲的方法没有任何优势。

因此,如果这个答案不能令人满意,请在 的地方说明你想要“分配到位”的发电机,当然要尊重列表原始内容的存在以求生存 直到发电机开始运转为止。