在Python中,修改列表和字符串哪个更高效?
不管使用起来有多方便,哪种方式计算上更高效呢?是不断地切割列表然后添加元素,还是取子字符串然后做同样的事情?
举个例子,假设我有两个二进制字符串“11011”和“01001”。如果我把它们当作列表来处理,我会随机选择一个“切割”点。假设我选择了3。那么我就会取第一个字符串的前3个字符,以及第二个字符串剩下的字符(所以我需要切割两个字符串),然后把它们组合成一个新的字符串。
这样做是通过切割子字符串更高效,还是把它表示成列表([1, 1, 0, 1, 1])来处理更好呢?
4 个回答
一般来说,修改列表比修改字符串要更有效率,因为字符串是不可改变的。
timeit
是一个很好的工具,用来做小规模的性能测试,但在比较可能会改变原始数据的操作时,使用时要特别小心。因为在这种情况下,你需要额外的操作来确保数据不会被修改。首先,先只测量“额外”的开销:
$ python -mtimeit -s'a="11011";b="01001"' 'la=list(a);lb=list(b)'
100000 loops, best of 3: 5.01 usec per loop
$ python -mtimeit -s'a="11011";b="01001"' 'la=list(a);lb=list(b)'
100000 loops, best of 3: 5.06 usec per loop
为了避免数据被改变,我们需要创建两个全新的列表,这个过程大约需要超过5微秒(当你关注小差异时,最好多运行2-3次来观察不确定性的范围)。之后:
$ python -mtimeit -s'a="11011";b="01001"' 'la=list(a);lb=list(b);x=a[:3]+b[3:]'
100000 loops, best of 3: 5.5 usec per loop
$ python -mtimeit -s'a="11011";b="01001"' 'la=list(a);lb=list(b);x=a[:3]+b[3:]'
100000 loops, best of 3: 5.47 usec per loop
在这种情况下,字符串切片和拼接的开销大约是410到490纳秒。而:
$ python -mtimeit -s'a="11011";b="01001"' 'la=list(a);lb=list(b);la[3:]=lb[3:]'
100000 loops, best of 3: 5.99 usec per loop
$ python -mtimeit -s'a="11011";b="01001"' 'la=list(a);lb=list(b);la[3:]=lb[3:]'
100000 loops, best of 3: 5.99 usec per loop
原地修改列表的开销大约是930到980纳秒。这个差异明显高于噪音和不确定性水平,所以你可以可靠地说,在这个使用场景中,处理字符串的时间大约是处理列表的一半。当然,测量一系列与你的典型瓶颈任务相关且具有代表性的用例也是非常重要的!
在编程中,有时候我们需要在代码里插入一些特定的内容,比如变量的值或者其他信息。这就像在写作文时,我们需要用一些例子来说明我们的观点。
有些时候,我们会用到占位符,这些占位符就像是一个空白的框框,等到需要的时候再把具体的内容填进去。比如说,如果我们想在代码中显示一个用户的名字,我们可以用一个占位符来表示这个名字,等到程序运行时再把真实的名字放进去。
这样做的好处是,我们可以让代码更加灵活,能够适应不同的情况,而不需要每次都手动去修改代码。
总之,占位符就像是一个准备好的空位,等着我们在合适的时候把内容放进去,让我们的代码更加智能和高效。
>>> a = "11011"
>>> b = "01001"
>>> import timeit
>>> def strslice():
return a[:3] + b[3:]
>>> def lstslice():
return list(a)[:3] + list(b)[3:]
>>> c = list(a)
>>> d = list(b)
>>> def lsts():
return c[:3] + d[3:]
>>> timeit.timeit(strslice)
0.5103488475836432
>>> timeit.timeit(lstslice)
2.4350100538824613
>>> timeit.timeit(lsts)
1.0648406858527295