2.14 合并拼接字符串

    如果你想要合并的字符串是在一个序列或者 中,那么最快的方式就是使用 join() 方法。比如:

    初看起来,这种语法看上去会比较怪,但是 被指定为字符串的一个方法。这样做的部分原因是你想去连接的对象可能来自各种不同的数据序列(比如列表,元组,字典,文件,集合或生成器等),如果在所有这些对象上都定义一个 join() 方法明显是冗余的。因此你只需要指定你想要的分割字符串并调用他的 方法去将文本片段组合起来。

    如果你仅仅只是合并少数几个字符串,使用加号(+)通常已经足够了:

    1. >>> a = 'Is Chicago'
    2. >>> b = 'Not Chicago?'
    3. >>> a + ' ' + b
    4. 'Is Chicago Not Chicago?'
    5. >>>

    加号(+)操作符在作为一些复杂字符串格式化的替代方案的时候通常也工作的很好,比如:

    1. >>> print('{} {}'.format(a,b))
    2. Is Chicago Not Chicago?
    3. >>> print(a + ' ' + b)
    4. Is Chicago Not Chicago?
    5. >>>

    如果你想在源码中将两个字面字符串合并起来,你只需要简单的将它们放到一起,不需要用加号(+)。比如:

    1. >>> a = 'Hello' 'World'
    2. >>> a
    3. >>>

    最重要的需要引起注意的是,当我们使用加号(+)操作符去连接大量的字符串的时候是非常低效率的,因为加号连接会引起内存复制以及垃圾回收操作。特别的,你永远都不应像下面这样写字符串连接代码:

    这种写法会比使用 join() 方法运行的要慢一些,因为每一次执行+=操作的时候会创建一个新的字符串对象。你最好是先收集所有的字符串片段然后再将它们连接起来。

    一个相对比较聪明的技巧是利用生成器表达式(参考1.19小节)转换数据为字符串的同时合并字符串,比如:

    1. >>> data = ['ACME', 50, 91.1]
    2. >>> ','.join(str(d) for d in data)
    3. 'ACME,50,91.1'
    4. >>>

    同样还得注意不必要的字符串连接操作。有时候程序员在没有必要做连接操作的时候仍然多此一举。比如在打印的时候:

    1. print(a + ':' + b + ':' + c) # Ugly
    2. print(':'.join([a, b, c])) # Still ugly
    3. print(a, b, c, sep=':') # Better

    当混合使用I/O操作和字符串连接操作的时候,有时候需要仔细研究你的程序。比如,考虑下面的两端代码片段:

    1. # Version 1 (string concatenation)
    2. f.write(chunk1 + chunk2)
    3.  
    4. # Version 2 (separate I/O operations)
    5. f.write(chunk1)
    6. f.write(chunk2)

    最后谈一下,如果你准备编写构建大量小字符串的输出代码,你最好考虑下使用生成器函数,利用yield语句产生输出片段。比如:

    这种方法一个有趣的方面是它并没有对输出片段到底要怎样组织做出假设。例如,你可以简单的使用 方法将这些片段合并起来:

    1. text = ''.join(sample())

    或者你也可以将字符串片段重定向到I/O:

    1. f.write(part)

    再或者你还可以写出一些结合I/O操作的混合方案:

    1. def combine(source, maxsize):
    2. parts = []
    3. size = 0
    4. for part in source:
    5. parts.append(part)
    6. size += len(part)
    7. if size > maxsize:
    8. yield ''.join(parts)
    9. parts = []
    10. size = 0
    11. yield ''.join(parts)
    12.  
    13. # 结合文件操作
    14. with open('filename', 'w') as f:
    15. f.write(part)

    这里的关键点在于原始的生成器函数并不需要知道使用细节,它只负责生成字符串片段就行了。