上一篇文章: Python实用技法第32篇:对齐文本字符串
下一篇文章:
咱们想将许多小字符串合并成一个大的字符串。程序员
若是想要合并的字符串在一个序列或可迭代对象中,那么将它们合并起来的最快方法就是使用join()方法。示例以下:编程
>>> parts = ['Is', 'Chicago', 'Not', 'Chicago?'] >>> ' '.join(parts) 'Is Chicago Not Chicago?' >>> ','.join(parts) 'Is,Chicago,Not,Chicago?' >>> ''.join(parts) 'IsChicagoNotChicago?' >>>
初看上去语法可能显得有些怪异,可是join()操做实际上是字符串对象的一个方法。这么设计的部分缘由是由于想要合并在一块儿的对象可能来自于各类不一样的数据序列,好比列表、元组、字典、文件、集合或生成器,若是单独在每一种序列对象中实现一个join()方法就显得太冗余了。所以只须要指定想要的分隔字符串,而后在字符串对象上使用join()方法将文本片断粘合在一块儿就能够了。segmentfault
若是只是想链接一些字符串,通常使用+操做符就足够完成任务了:app
>>> a = 'Is Chicago' >>> b = 'Not Chicago?' >>> a + ' ' + b 'Is Chicago Not Chicago?' >>>
针对更加复杂的字符串格式化操做,+操做符一样能够做为format()的替代,很好地完成任务:函数
>>> print('{} {}'.format(a,b)) Is Chicago Not Chicago? >>> print(a + ' ' + b) Is Chicago Not Chicago? >>>
若是打算在源代码中将字符串字面值合并在一块儿,能够简单地将它们排列在一块儿,中间不加+操做符。示例以下:性能
>>> a = 'Hello' 'World' >>> a 'HelloWorld' >>>
字符串链接这个主题可能看起来尚未高级到要用一整节的篇幅来说解,可是程序员经常会在这个问题上作出错误的编程选择,使得他们的代码性能受到影响。设计
最重要的一点是要意识到使用+操做符作大量的字符串链接是很是低效的,缘由是因为内存拷贝和垃圾收集产生的影响。特别是你毫不会想写出这样的字符串链接代码:code
s = '' for p in parts: s += p
这种作法比使用join()方法要慢上许多。主要是由于每一个+=操做都会建立一个新的字符串对象。咱们最好先收集全部要链接的部分,最后再一次将它们链接起来。orm
一个相关的技巧(很漂亮的技巧)是利用生成器表达式(见1.19节)在将数据转换为字符串的同时完成链接操做。示例以下:对象
>>> data = ['ACME', 50, 91.1] >>> ','.join(str(d) for d in data) 'ACME,50,91.1' >>>
对于没必要要的字符串链接操做也要引发重视。有时候在技术上并不是必需的时候,程序员们也会得意忘形地使用字符串链接操做。例如在打印的时候:
print(a + ':' + b + ':' + c) # Ugly print(':'.join([a, b, c])) # Still ugly print(a, b, c, sep=':') # Better
将字符串链接同I/O操做混合起来的时候须要对应用作仔细的分析。例如,考虑以下两段代码:
# Version 1 (string concatenation) f.write(chunk1 + chunk2) # Version 2 (separate I/O operations) f.write(chunk1) f.write(chunk2)
若是这两个字符串都很小,那么第一个版本的代码能带来更好的性能,这是由于执行一次I/O系统调用的固有开销就很高。另外一方面,若是这两个字符串都很大,那么第二个版本的代码会更加高效。由于这里避免了建立大的临时结果,也没有对大块的内存进行拷贝。这里必须再次强调,你须要对本身的数据作分析,以此才能断定哪种方法能够得到最好的性能。
最后但也是最重要的是,若是咱们编写的代码要从许多短字符串中构建输出,则应该考虑编写生成器函数,经过yield关键字生成字符串片断。示例以下:
def sample(): yield 'Is' yield 'Chicago' yield 'Not' yield 'Chicago?'
关于这种方法有一个有趣的事实,那就是它不会假设产生的片断要如何组合在一块儿。好比说能够用join()将它们简单的链接起来:
text = ''.join(sample())
或者,也能够将这些片断重定向到I/O:
for part in sample(): f.write(part)
又或者咱们能以混合的方式将I/O操做智能化地结合在一块儿:
def combine(source, maxsize): parts = [] size = 0 for part in source: parts.append(part) size += len(part) if size > maxsize: yield ''.join(parts) parts = [] size = 0 yield ''.join(parts) for part in combine(sample(), 32768): f.write(part)
关键在于这里的生成器函数并不须要知道精确的细节,它只是产生片断而已。