在您现有的代码中,您可以将列表更改为生成器表达式:
dest = "\n".join(line for line in src.split("\n") if line[:1]!="#")
这个非常小的改变避免了你代码中两个临时列表之一的构造,并且不需要你做出任何努力。
另一个完全不同的方法是使用正则表达式来避免构建两个临时列表:
import re
regex = re.compile('^#.*\n?', re.M)
dest = regex.sub('', src)
这不仅避免了创建临时列表,还避免了为输入中的每一行创建临时字符串。以下是所提出解决方案的性能测量结果:
init = r'''
import re, StringIO
regex = re.compile('^#.*\n?', re.M)
src = ''.join('foo bar baz\n' for _ in range(100000))
'''
method1 = r'"\n".join([line for line in src.split("\n") if line[:1] != "#"])'
method2 = r'"\n".join(line for line in src.split("\n") if line[:1] != "#")'
method3 = 'regex.sub("", src)'
method4 = '''
buffer = StringIO.StringIO(src)
dest = "".join(line for line in buffer if line[:1] != "#")
'''
import timeit
for method in [method1, method2, method3, method4]:
print timeit.timeit(method, init, number = 100)
结果:
9.38秒 # 分割后使用临时列表连接
9.92秒 # 分割后使用生成器连接
8.60秒 # 正则表达式
64.56秒 # StringIO
从结果可以看出,正则表达式是最快的方法。
从您的评论中可以看出,您实际上并不关心避免创建临时对象。您真正想要的是减少程序的内存需求。临时对象不一定会影响程序的内存消耗,因为Python可以快速清除内存。问题在于有些对象比需要更长时间地存在于内存中,而且所有这些方法都有这个问题。
如果您仍然遇到内存不足的问题,我建议您不要完全在内存中执行此操作。而是将输入和输出存储在磁盘上的文件中,并以流式方式从它们中读取。这意味着您从输入中读取一行,写入一行到输出中,再读取一行,再写入一行等等。这将创建大量的临时字符串,但即使如此,它也几乎不需要任何内存,因为您只需要逐个处理字符串。
MemoryError
错误的字符串的len(src)
和src.count('\n')
的结果? - Mark Byers