大多数pythonic和/或performant方式将单个值分配给切片?

Vro*_*del 16 python slice

我想为列表的一部分分配一个值.除了以下之一之外,还有更好的解决方案吗?

也许性能最好,但有些丑陋:

>>> l=[0,1,2,3,4,5]
>>> for i in range(2,len(l)): l[i] = None

>>> l
[0, 1, None, None, None, None]
Run Code Online (Sandbox Code Playgroud)

简洁(但我不知道Python是否认识到不需要重新排列列表元素):

>>> l=[0,1,2,3,4,5]
>>> l[2:] = [None]*(len(l)-2)
>>> l
[0, 1, None, None, None, None]
Run Code Online (Sandbox Code Playgroud)

同样的警告如上:

>>> l=[0,1,2,3,4,5]
>>> l[2:] = [None for _ in range(len(l)-2)]
>>> l
[0, 1, None, None, None, None]
Run Code Online (Sandbox Code Playgroud)

不确定是否使用库来执行这样一个简单的任务是明智的:

>>> import itertools
>>> l=[0,1,2,3,4,5]
>>> l[2:] = itertools.repeat(None,len(l)-2)
>>> l
[0, 1, None, None, None, None]
Run Code Online (Sandbox Code Playgroud)

我看到切片的赋值(对于for循环)的问题是Python可能会尝试准备"l"长度的变化.毕竟,通过插入更短/更长的切片来更改列表涉及复制列表AFAIK的所有元素(即所有引用).如果Python也在我的情况下这样做(虽然没有必要),操作变为O(n)而不是O(1)(假设我只是总是改变一些元素).

Inb*_*ose 6

时间安排:

python -mtimeit "l=[0,1,2,3,4,5]" "for i in range(2,len(l)):" "    l[i] = None"
1000000 loops, best of 3: 0.669 usec per loop

python -mtimeit "l=[0,1,2,3,4,5]" "l[2:] = [None]*(len(l)-2)"
1000000 loops, best of 3: 0.419 usec per loop

python -mtimeit "l=[0,1,2,3,4,5]" "l[2:] = [None for _ in range(len(l)-2)]"
1000000 loops, best of 3: 0.655 usec per loop

python -mtimeit "l=[0,1,2,3,4,5]" "l[2:] = itertools.repeat(None,len(l)-2)"
1000000 loops, best of 3: 0.997 usec per loop
Run Code Online (Sandbox Code Playgroud)

看起来l[2:] = [None]*(len(l)-2)是您提供的最佳选项(对于您正在处理的范围).

注意:

请记住,结果将根据Python版本,操作系统,其他当前正在运行的程序而变化,最重要的是 - 列表的大小和要替换的切片的大小.对于较大的范围,可能最后一个选项(使用itertools.repeat)将是最有效的,既易于阅读(pythonic)又高效(性能).

  • 您的基准适用于小型列表.随着`l`变大,分配和释放临时列表需要更多时间,基于`itertools.repeat`的解决方案变得相对便宜.要对此进行测试,请将列表设置替换为"l = range(6)",然后增加列表.`itertools.repeat`需要一个令人惊讶的大型列表才能在我的系统上,在包含数十万个元素的列表上变得更快,但确实会发生. (2认同)

use*_*342 5

您的所有解决方案都是Pythonic,同样具有可读性.如果您真的关心性能并认为在这种情况下它很重要,请使用该timeit模块对它们进行基准测试.

话虽如此,我希望第一个解决方案几乎肯定不是最高效的解决方案,因为它迭代Python中的列表元素.此外,Python不会优化远离列表在分配右侧创建的列表,但列表创建速度非常快,并且在大多数情况下,一个小的临时列表根本不会影响执行.就个人而言,对于一个简短的列表,我会选择你的第二个解决方案,并且我会选择更长的列表itertools.repeat().

请注意,itertools它并不真正算作"库",它带有Python,并且经常被使用,它本质上是语言的一部分.


Pau*_* Bu 1

我认为 Python 中没有直接开箱即用的功能来做到这一点。我喜欢你的第二种方法,但请记住,空间和时间之间需要权衡。这是 @user4815162342 推荐的一本非常好的读物:Python 模式 - 优化轶事

无论如何,如果这是您最终将在代码中执行的操作,我认为最好的选择是将其包装在辅助函数中:

def setvalues(lst, index=0, value=None):
    for i in range(index, len(lst)):
        lst[i] = value

>>>l=[1,2,3,4,5]
>>>setvalues(l,index=2)
>>>l
>>>[1, 2, None, None, None]
Run Code Online (Sandbox Code Playgroud)

这有一些优点:

  1. 该代码在函数内进行了重构,因此如果您改变了如何执行该操作的想法,则可以轻松修改。
  2. 您可以拥有多个实现相同目标的函数,因此可以衡量它们的性能。
  3. 您可以为它们编写测试。
  4. 通过重构可以获得的所有其他优势:)

恕我直言,这个操作没有直接的 Python 未来,这是我能想象到的最好的解决方法。

希望这可以帮助!