세 가지 가능성이 있습니다.
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())
이것을 메인 스크립트로 실행하면 세 가지 기능이 동일하다는 것을 확인할 수 있습니다. 와 timeit
(과 * 100
에 대한 것은 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이 발생하는 모든 루프 는 자동으로 한 번에 하나씩 의심을 불러 일으키고, 다른 기능으로 출력을 확인할 수 있었기 때문에 내 코드도 옳다고 생각하지만 그러한 조정이 부족하고 가져야하는 많은 루프가 있어야합니다. ').
그러나 분할 기반 접근 방식은 여전히 규칙입니다.
제쳐두고 : 아마도 더 나은 스타일 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
안타깝게도 후행을 제거해야하는 필요성 은 while
루프를 보다 명확하고 빠르게 교체하는 것을 금지합니다 return iter(stri)
( iter
최신 버전의 Python에서 중복 되는 부분은 2.3 또는 2.4 이후로 믿지만 또한 무해합니다). 시도해 볼만한 가치가 있습니다.
return itertools.imap(lambda s: s.strip('\n'), stri)
또는 그것의 변형-그러나 나는 이론적 인 연습이 strip
기초적이고 가장 간단하고 빠른 것이므로 여기서 멈추고 있습니다 .
foo.splitlines()
있습니까?