为什么字符串连接在Python中很重要?

时间:2014-02-08 00:07:30

标签: python python-2.7 python-3.x

我看过很多帖子(例如herehere)谈到Python中的连接,如何做到最好('+'vs','),这更快等等。但我似乎无法找出为什么这很重要。 Roger Pate在第一个例子中提到了关于传递多个参数与一个参数的问题,但我仍然不清楚。

那么,为什么连接很重要?什么是一个关键的用例?

2 个答案:

答案 0 :(得分:6)

因为通常+ n字符串会导致n-1内存分配O(n)。通过邻接连接在解析器中完成,并执行1次分配。例如,''.join(iter(s))连接将执行O(log(n))总共2n个内存的分配/副本。

> a = ['a'] * 100000
> def concat(strings):
      c = ''
      for s in strings:
          c += s
      return c
> %timeit ''.join(a)       # precalculates necessary buffer size
1000 loops, best of 3: 1.07 ms per loop
> %timeit ''.join(iter(a)) # allocates exponentially larger buffers
1000 loops, best of 3: 1.94 ms per loop
> %timeit concat(a)        # allocates a new buffer n-1 times
100 loops, best of 3: 7.15 ms per loop

答案 1 :(得分:1)

字符串是Python中的不可变对象,因此您无法修改现有字符串。这意味着字符串的每个串联都会导致创建一个新的字符串对象,并抛弃两个(源对象)。内存分配很昂贵,足以解决这个问题。

因此,当您知道需要连接多个字符串时,请将它们存储在列表中。最后,只需一次,使用''.join(list_of_strings)加入该列表。这样,新的字符串只会被创建一次。

请注意,这也适用于其他语言。例如,Java和C#都具有StringBuilder类型,它们基本相同。只要你继续添加新的字符串部分,它们就会在内部将它添加到字符串中,并且只有当你将构建器转换为真正的字符串时,连接才会发生 - 而且只会发生一次。

另请注意,当您在一行中追加几个字符串时,就会发生这种内存分配开销。例如,a + b + c + d将创建三个中间字符串。如果查看该表达式的字节代码,可以看到:

>>> dis.dis('a + b + c + d')
  1           0 LOAD_NAME                0 (a) 
              3 LOAD_NAME                1 (b) 
              6 BINARY_ADD           
              7 LOAD_NAME                2 (c) 
             10 BINARY_ADD           
             11 LOAD_NAME                3 (d) 
             14 BINARY_ADD           
             15 RETURN_VALUE         

每个BINARY_ADD汇总前两个值,并为堆栈上的结果创建一个新对象。请注意,对于常量字符串文字,编译器足够聪明,可以注意到您正在添加常量:

>>> dis.dis('"foo" + "bar" + "baz"')
  1           0 LOAD_CONST               4 ('foobarbaz') 
              3 RETURN_VALUE         

如果你确实在其中有一些可变部分 - 例如,如果你想生成一个格式良好的输出 - 那么你又回到创建中间字符串对象。在这种情况下,使用str.format是一个好主意,例如'foo {} bar {} baz'.format(a, b)