<p>有三种可能性:</p>
<pre><code>foo = """
this is
a multi-line string.
"""
def f1(foo=foo): return iter(foo.splitlines())
def f2(foo=foo):
retval = ''
for char in foo:
retval += char if not char == '\n' else ''
if char == '\n':
yield retval
retval = ''
if retval:
yield retval
def f3(foo=foo):
prevnl = -1
while True:
nextnl = foo.find('\n', prevnl + 1)
if nextnl < 0: break
yield foo[prevnl + 1:nextnl]
prevnl = nextnl
if __name__ == '__main__':
for f in f1, f2, f3:
print list(f())
</code></pre>
<p>运行这个作为主脚本确认这三个函数是等价的。使用<code>timeit</code>(和<code>* 100</code>用于<code>foo</code>以获得更精确测量所需的大量字符串):</p>
<pre><code>$ python -mtimeit -s'import asp' 'list(asp.f3())'
1000 loops, best of 3: 370 usec per loop
$ python -mtimeit -s'import asp' 'list(asp.f2())'
1000 loops, best of 3: 1.36 msec per loop
$ python -mtimeit -s'import asp' 'list(asp.f1())'
10000 loops, best of 3: 61.5 usec per loop
</code></pre>
<p>注意,我们需要<code>list()</code>调用来确保遍历迭代器,而不仅仅是构建迭代器。</p>
<p>听着,这种简单的实现要快得多,甚至一点也不好笑:比我尝试的<code>find</code>调用快6倍,而这又比低级方法快4倍。</p>
<p>要记住的教训:度量总是一件好事(但必须是准确的);像<code>splitlines</code>这样的字符串方法以非常快的方式实现;通过在非常低的级别编程(特别是通过非常小的片段的<code>+=</code>循环)将字符串组合在一起可能会非常慢。</p>
<p><strong>编辑</strong>:添加了@Jacob的建议,稍加修改以获得与其他建议相同的结果(保留一行的尾随空白),即:</p>
<pre><code>from cStringIO import StringIO
def f4(foo=foo):
stri = StringIO(foo)
while True:
nl = stri.readline()
if nl != '':
yield nl.strip('\n')
else:
raise StopIteration
</code></pre>
<p>测量给出:</p>
<pre><code>$ python -mtimeit -s'import asp' 'list(asp.f4())'
1000 loops, best of 3: 406 usec per loop
</code></pre>
<p>还不如基于<code>.find</code>的方法——仍然值得记住,因为它可能不太容易被一个bug所忽略(任何出现+1和-1的循环,就像上面的<code>f3</code>,都应该由一个怀疑自动触发——许多缺少这种调整并应该有它们的循环也应该如此——尽管相信我的代码也是正确的,因为我可以用其他函数检查它的输出。</p>
<p>但基于拆分的方法仍然适用。</p>
<p>旁白:可能更好的<code>f4</code>样式是:</p>
<pre><code>from cStringIO import StringIO
def f4(foo=foo):
stri = StringIO(foo)
while True:
nl = stri.readline()
if nl == '': break
yield nl.strip('\n')
</code></pre>
<p>至少,不那么冗长了。遗憾的是,删除尾部<code>\n</code>的需要禁止用<code>return iter(stri)</code>更清晰、更快地替换<code>while</code>循环(我相信,在现代版本的Python中,<code>iter</code>部分是多余的,从2.3或2.4开始,但它也是无害的)。或许值得一试:</p>
<pre><code> return itertools.imap(lambda s: s.strip('\n'), stri)
</code></pre>
<p>或者它的变体——但是我在这里停下来,因为这几乎是一个基于<code>strip</code>的、最简单和最快的理论练习。</p>