3つの可能性があります。
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())
メインスクリプトとしてこれを実行すると、3つの機能が同等であることを確認できます。でtimeit
(より正確な測定のために実質的な文字列を取得する* 100
ためのfor foo
):
$ 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
list()
イテレータが構築されるだけでなく、トラバースされるようにするために呼び出しが必要であることに注意してください。
IOW、素朴な実装は非常に高速であり、おかしくもありません。find
呼び出しを使用した試行よりも6倍高速であり、下位レベルのアプローチよりも4倍高速です。
保持すべき教訓:測定は常に良いことです(ただし正確でなければなりません)。のような文字列メソッドsplitlines
は非常に高速に実装されます。非常に低いレベルでのプログラミング(特に+=
、非常に小さなピースのループによる)によって文字列をまとめると、非常に遅くなる可能性があります。
編集:@Jacobの提案を追加、他と同じ結果が得られるように若干変更(行の末尾の空白は保持されます)。つまり、
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
測定は与える:
$ python -mtimeit -s'import asp' 'list(asp.f4())'
1000 loops, best of 3: 406 usec per loop
.find
ベースのアプローチほど良くありません-それでも、小さなオフバイワンバグ(f3
上記のように+1と-1の発生が見られるループは自動的に発生するはずです)が発生しにくいので、覚えておく価値があります1つずつ離れた疑いを引き起こします-そのような微調整を欠いていてそれらを持っているはずの多くのループもそうです-しかし、他の関数でその出力を確認できたので、私のコードも正しいと思います ')。
しかし、分割ベースのアプローチは依然として支配的です。
余談:のためのおそらくより良いスタイルはf4
:
from cStringIO import StringIO
def f4(foo=foo):
stri = StringIO(foo)
while True:
nl = stri.readline()
if nl == '': break
yield nl.strip('\n')
少なくとも、それは少し冗長ではありません。\n
残念ながら、末尾のs を削除する必要があるため、while
ループの明確で高速な置き換えが禁止されていますreturn iter(stri)
(そのiter
一部は、最新バージョンのPythonでは冗長ですが、2.3または2.4以降、無害です)。試してみる価値もあるでしょう:
return itertools.imap(lambda s: s.strip('\n'), stri)
またはそのバリエーション-しかし、これは、理論にstrip
基づいた、最も単純で最速の理論的な演習であるため、ここで停止します。
foo.splitlines()
正しく反復できることを知っていますか?